멱등성(Idempotent)이 뭔데?

eunhee·2025년 12월 18일

결제시스템

목록 보기
11/15

개발을 하면서 외국 결제 시스템의 개발 트렌드나
요즘 개발 어떻게 하나.. 궁금해서 둘러보던 중 찾은 단어

"멱.등.성" 이라는 단어 자체가 생소하고 컴공인 나도 뭐라는 건지 모르겠는데 쉽게 정리해 보겠다.
결제 시스템 개발자라면 "아.. 뭐야 어려운 건 줄 알았는데 별거 아니네" 할 거임.

멱등성

동일 요청이 여러 번 와도 한 번만 실행

⚠️ 핵심은 “요청 횟수”가 아니라 “결과의 중복 방지”


발생 원인들

결제 시스템에서는 이런 일이 실제로 일어남

  • PG가 Webhook을 2번, 3번 보냄
  • 서버가 응답 늦어서 재시도
  • 프론트에서 사용자가 결제 버튼 연타
  • 네트워크 타임아웃 후 재요청

> 자, 이때 멱등성 없으면? <

❌ 돈 두 번 받음
❌ 권한 두 번 열림
❌ 데이터 꼬임


결제 멱등성의 핵심 구성요소

Idempotency Key

“이 요청은 이 거래다”를 식별하는 키
예시 :payment_id, order_id, transaction_id ...


요청이 들어오면 이렇게 처리함

  1. 데이터 수신
  2. 식별키 확인
payment_id = "2025121618000001A" 
  1. DB 확인
SELECT * FROM payments WHERE payment_id = '2025121618000001A';
  1. 분기 처리
    이미 있음→ ❌ 다시 처리 안 함
    없음 → ✅ 결제 처리 + 저장
  2. 응답 반환
    성공 처리 완료 → 클라이언트/PG에 알림
    “같은 transactionId가 두 번 들어와도 DB가 거부 → 멱등성 보장

FastAPI 예제

@app.post("/webhook/payment")
def payment_webhook(req: PaymentWebhook):
    if payment_exists(req.payment_id):
        return {"status": "ok"}  # 이미 처리됨

    save_payment(req)
    grant_access(req.user_id)

    return {"status": "ok"}

DB는 왜 쓰는가?

단순한데 영속성 떄문임

  • 이유 1️⃣ 메모리는 믿을 수 없음
    서버 재시작
    멀티 인스턴스
  • 이유 2️⃣ 결제는 영속성 필요
    감사 로그
    분쟁 대응

멱등성 ≠ 트랜잭션

트랜잭션 = DB에서 ‘한 덩어리’로 묶인 작업 단위
“모두 성공하거나 모두 실패해야 한다”는 특징
둘 다 성공 → commit
하나라도 실패 → rollback
원자성(Atomicity)을 보장하는 것

차이점

항목트랜잭션멱등성
목적여러 작업 묶어서 “전부 성공 or 전부 실패”같은 요청이 여러 번 와도 “결과는 1번만 처리”
범위단일 DB/작업 단위요청 단위 / 시스템 전체
구현DB 트랜잭션(commit/rollback)DB 조회 + UNIQUE 제약 + 로직 분기
예시계좌 송금, 주문 생성과 재고 차감결제 Webhook 중복 수신 방지

결제 시스템에서 같이 쓰는 이유

멱등성만 있으면?
중복 요청은 막을 수 있음
하지만 DB 작업이 중간에 실패하면?
예: 결제 기록 저장 후 권한 부여 중 실패 → 데이터 불일치

트랜잭션만 있으면?
같은 요청 여러 번 오면?
PG Webhook 두 번 → 두 번 처리 → 돈 중복 차감

결론
멱등성: “중복 요청 거르는 관문”
트랜잭션: “한 요청 처리 단위를 안전하게 실행”

참고

멱등성 - TOSS

profile
안녕하세요. 개발 로그입니다.

0개의 댓글