Idempotent

멱등하다는 것은 여러번 같은 요청을 보내도 결과가 같다는 것이다.

멱등키를 사용하면 민감한 API 요청이 반복적으로 일어나는 문제를 막을 수 있고, 네트워크 이슈나 타임아웃 문제로 응답을 받지 못했을 때도 안전하게 같은 요청을 다시 보낼 수 있다.

The Idempotency-Key HTTP Header Field 멱등키(Idempotency Key) 를 헤더에 담아서 보내는 것을 IETF 에서 표준으로 제안하고 있다.

미국 핀테크 유니콘 대장급 기업인 Stripe 에서도 이미 Idempotent Requests 를 사용하고 있다.

Stripe 에서 다음과 같이 말하고 있다. To perform an idempotent request, provide an additional Idempotency-Key: <key> header to the request. Idempotency keys can be up to 255 characters long.

아래와 같이 API 요청에 멱등키 헤더를 사용하면 같은 요청이 두 번 일어나도 실제로 요청이 이루어지지 않고 첫 번째 요청 응답과 같은 응답을 보내준다.

결제 서버에서 결제 요청이 정상 처리되고나면, 캐시에 멱등키를 key 로하고 value 로 응답형식 or 거래아이디 등을 설정할 수 있다. 네트워크 이슈로 인해서 결제가 성공했음에도 응답을 받지 못하면, 주문 서버는 멱등키를 가지고 다시 요청하고, 결제 서버는 캐시에서 key 가 존재하는지 확인하여 같은 응답을 내줄 수 있다. 실패한 경우라면, 결제를 생성해서 생성 응답을 내줄 수 있다. 이때 무한정 멱등키를 캐시에 가지고 있으면 안되므로 TTL 을 설정한다.

Stripe:

curl https://api.stripe.com/v1/charges \
  -u sk_test_4eC39HqLyjWDarjtT1zdp7dc: \
  -H "Idempotency-Key: FDkJkm3AJaBnGAdM" \
  -d amount=2000 \
  -d currency=usd \
  -d description="My First Test Charge (created for API docs at https://www.stripe.com/docs/api)" \
  -d source=tok_mastercard

Keys are eligible to be removed from the system automatically after they're at least 24 hours old, and a new request is generated if a key is reused after the original has been pruned. The idempotency layer compares incoming parameters to those of the original request and errors unless they're the same to prevent accidental misuse.

Toss Payments:

curl --request POST \
  --url https://api.tosspayments.com/v1/payments/key-in
  --header 'Authorization: Basic dGVzdF9za196WExrS0V5cE5BcldtbzUwblgzbG1lYXhZRzVSOg=='
  --header 'Content-Type: application/json' \
  --header 'Idempotency-Key: SAAABPQbcqjEXiDL' \
  --data '{"amount":15000,"orderId":"a4CWyWY5m89PNh7xJwhk1","orderName":"토스 티셔츠 외 2건","customerName":"박토스","cardNumber":"4330123412341234","cardExpirationYear":"24","cardExpirationMonth":"07","cardPassword":"12","customerIdentityNumber":"881212"}'

Resolve consistency issues with retries

재시도로 인한 정합성 오류를 해결하기 위해 멱등키를 활용할 수 있다.

Toss Payments Developer center - Idempotency Key

예를 들어 결제 고객이 부분 취소 요청을 했는데 네트워크가 불안정해서 성공 응답이 전송되지 않을 수 있습니다. 결제 고객은 부분 취소가 이루어지지 않았다고 판단하고 다시 요청을 보내서 두 번 취소되는 문제가 생깁니다. 이런 상황에서 멱등키를 사용하면 같은 요청이 여러 번 처리되지 않아 안전합니다.

타임아웃 특성상 짧은 주기로 계속 재시도 요청을 보내게 되면 네트워크 지연 상황을 더욱 악화 시킬 수 있다. 네트워크 지연으로 인해 더 빈번한 타임아웃이 발생할 수 있다.

이러한 방법을 지수적으로 재시도 요청 하는 방향으로 개선할 수 있다. 예를 들면, 1분, 2분, 4분, 8분에 한 번씩 보내도록 처리할 수 있다.

그럼에도 정합성이 틀어지는 경우에는 별도의 Batch 에서 정합성을 올바르게 맞추도록 할 수 있다.