멱등성(Idempotency)

hznnoy·2025년 11월 30일

CS

목록 보기
23/24

웹 서비스에서 API를 설계할 때 가장 중요한 개념 중 하나가 멱등성(Idempotency)이다.
특히 결제, 주문, 포인트 지급, 재고 감소 같은 '금전·수량' 관련 로직에서는 필수적이다.


멱등성(Idempotency)이란?

같은 요청을 여러 번 보내더라도 결과가 한 번 실행된 것과 동일한 특성을 의미한다.
예를 들어, 아래 두 API 중 어떤 것이 멱등적일까?

요청멱등성 여부
GET /products/1⭕ 멱등성 있음 (몇 번 조회해도 같음)
DELETE /posts/10⭕ 멱등성 있음 (이미 삭제된 상태에서 또 삭제해도 상태는 동일)
POST /orders❌ 멱등성 없음 (두 번 호출하면 주문이 두 개 생성됨)

즉,

멱등적: 여러 번 호출해도 결과가 변하지 않음
비멱등적: 동일한 요청이 여러 번 실행되면 부작용이 발생함 (중복 주문, 중복 결제 등)

왜 멱등성이 중요한가?

HTTP 요청은 언제든지 중복 전송될 수 있다.

1) 사용자가 버튼을 여러 번 클릭

  • 더블 클릭
  • 화면 멈춰서 다시 클릭

2) 네트워크 재전송

  • 모바일 환경에서 패킷 재전송 발생
  • 브라우저 자동 재시도

3) 프록시/게이트웨이 재시도

  • Nginx, Cloudflare, API Gateway 등에서 timeout → 자동 재시도 발생

4) 서버에서 재시도 로직 사용

  • @Retryable
  • Circuit Breaker 재시도
  • 외부 API 호출 실패 후 재요청

➡️ 결제/주문 API가 멱등적이지 않으면 중복 결제·중복 주문이 발생할 수 있다.

이런 문제는 고객 피해 + 정산 오류 + CS 증가로 이어지기 때문에
멱등성은 실무에서 필수적인 안정성 요소다.

멱등성이 필요한 대표 도메인

  • 결제 승인
  • 포인트 지급·차감
  • 쿠폰 발급
  • 재고 감소
  • 주문 생성
  • 유료 구독 갱신
  • 환불 처리

모두 중복 실행되면 문제가 되는 로직들이다.

멱등성을 보장하는 방식

멱등성을 지키기 위한 방법에는 크게 3가지가 있다.

1) 클라이언트에서 Idempotency-Key 제공

Stripe·PayPal 등 글로벌 PG들이 사용하는 방식이다.

요청 예시

POST /payments
Idempotency-Key: 1fa4e3b2-1234-4b98-82a1-a9f4f93d0aa1

서버는 다음을 보장한다.

  • 같은 Key로 들어온 요청 → 첫 번째 요청의 결과를 그대로 반환
  • 실제 로직은 한 번만 실행됨

구현 개념

요청마다 UUID를 생성해 헤더에 포함
서버는 “해당 키로 처리된 결과가 있는지” DB나 Redis에서 조회
있으면 로직 실행하지 않고 저장된 결과 반환
없으면 수행 후 결과를 저장하고 키와 함께 캐싱

➡️ 중복 요청이 와도 실제 작업은 단 한 번만 수행.


2) 서버에서 중복 여부를 식별하는 키 활용

예)

  • 주문번호(orderId)
  • 결제 transactionId
  • 사용자별 “오늘의 출석” 기록
  • 쿠폰 코드

이런 값들은 중복으로 생성되면 안 되는 키이므로
이미 존재하면 중복 요청으로 판단하고 기존 결과를 반환할 수 있다.

예시 (Order 중복 생성 방지)

if (orderRepository.existsByOrderId(request.orderId)) {
    return existingOrderResponse
}

createOrder()

➡️ 자연 키(Natural Key) 기반 멱등성.


3) DB 트랜잭션 + Unique 제약 조건 이용

가장 단순하고 강력한 방식.

예) 결제 레코드에 paymentKey UNIQUE 제약

ALTER TABLE payments
ADD CONSTRAINT unique_toss_payment_key UNIQUE (toss_payment_key);

중복 요청 발생 시

처음 요청 → DB INSERT 성공
두 번째 요청 → UNIQUE 제약 오류 발생
서버는 이 오류를 캐치해서
"이미 처리된 결제입니다."
로 응답한다.

➡️ DB가 멱등성을 보장해주는 방식이라 신뢰성이 높다.


멱등성 구현 시 주의사항

1) 단순히 “중복 요청 무시”가 아님
➡️ 중복 요청이어도 첫 번째 요청의 결과를 그대로 반환해야 함

2) @Transactional과 같이 사용할 경우 롤백 처리 주의
중복 요청 처리도 트랜잭션 경계를 명확히 해야 한다.

3) 재시도 로직과 반드시 짝을 이뤄야 함
재시도는 중복 요청을 만들어내기 때문에멱등성과 “세트”로 설계돼야 한다.

4) 분산 환경(멀티 인스턴스)에서는 Redis Lock 또는 DB Lock 필요
두 서버가 동시에 같은 멱등성 키로 요청을 처리하면 충돌 가능
➡️ Redlock, MySQL SELECT ... FOR UPDATE 등을 활용


정리

멱등성은 단순한 기술적 개념이 아니라, 금전·주문 시스템의 안정성을 보장하는 핵심 설계 원칙이다.

  • 멱등성 = 여러 번 호출되어도 “한 번 호출한 것과 같은 결과”
  • 왜 필요? → 사용자의 중복 클릭, 네트워크 재전송, API 재시도 때문에 결제/재고/포인트 등에는 필수
  • 구현 방법
    - Idempotency-Key
    - Unique 제약 조건
    - 자연 키 기반 식별
    - Lock & 트랜잭션

즉,
재시도 가능한 API는 반드시 멱등성을 가져야 한다.
그렇지 않으면 중복 결제, 중복 주문 같은 심각한 문제가 발생하게 된다.

profile
노력에는 지름길이 없으니까요

0개의 댓글