1. 멱등성이란 무엇인가?
멱등성(idempotency)은 “같은 작업을 여러 번 반복해도 결과가 달라지지 않는 성질”을 말해요.
예를 들어 어떤 숫자에 1을 곱하는 연산, 절대값 함수처럼 몇 번을 적용해도 결과가 똑같으면 그 연산은 멱등하다고 부를 수 있어요.
API 세계로 가져오면, 멱등한 API는 같은 요청을 두 번, 세 번 보내도 서버의 상태와 응답 결과가 처음 요청 때와 완전히 동일하게 유지되는 API를 의미해요.
단순히 응답 JSON만 비슷한 게 아니라, 실제 DB 상태까지 “한 번 처리된 것과 동일하게” 유지되는 게 핵심이에요.
2. HTTP 메서드와 멱등성, 그리고 안전성
HTTP 메서드에도 멱등성과 안전성이라는 개념이 있어요.
- 멱등한 메서드: GET, PUT, DELETE, HEAD, OPTIONS, TRACE
- 멱등하지 않은 메서드: POST, PATCH, CONNECT
예를 들어:
- GET: 여러 번 호출해도 리소스를 바꾸지 않고 같은 결과를 조회하므로 멱등해요.
- PUT: 호출할 때마다 리소스를 “같은 내용으로 교체”하기 때문에 여러 번 호출해도 결과가 같아서 멱등해요.
- DELETE: 이미 지워진 리소스를 또 삭제 요청해도 상태는 “삭제된 상태”로 유지되기 때문에 멱등으로 봐요.
여기서 한 가지 더 중요한 개념이 “안전성(safety)”이에요.
- 안전한 메서드: 리소스를 변경하지 않는 메서드 (GET, HEAD, OPTIONS)
- 멱등하지만 안전하지는 않은 메서드: PUT, DELETE (리소스를 실제로 바꾸긴 하지만, 반복해도 상태가 더 바뀌지 않는다는 의미에서 멱등)
정리하면,
- 안전한 메서드는 항상 멱등하지만,
- 멱등한 메서드가 항상 안전한 것은 아니에요.
3. 왜 API에서 멱등성이 중요한가?
실제 서비스에서는 네트워크 오류, 타임아웃, 클라이언트 버그, 사용자의 중복 클릭 등으로 인해 같은 요청이 여러 번 들어오는 상황이 자주 발생해요.
특히 결제·환불 같은 API에서 멱등성이 없으면 이런 문제가 생길 수 있어요.
- 결제 요청을 보냈는데 타임아웃이 나서 응답을 못 받은 상황
- 실제로는 결제가 성공했는지, 실패했는지 알 수 없음
- 개발자나 운영자가 수동으로 결제 내역을 확인해야 함
- 사용자가 “다시 결제하기”를 누르면서 중복 결제 가능성도 생김
반대로 결제 API가 멱등하게 설계되어 있다면:
- 클라이언트는 같은 요청을 다시 보내도 “이미 처리된 요청”으로 인식되어 같은 결과만 돌려받고, 서버 상태는 그대로 유지돼요.
- 사용자가 결제 버튼을 여러 번 눌러도 실제 결제는 한 번만 처리돼요.
즉, 멱등성은 안전하게 재시도할 수 있는 API를 만드는 기본 장치예요.
이 덕분에 장애·네트워크 이슈에도 서비스가 더 견고해지고, 사용자 경험도 좋아집니다.
4. 멱등키(Idempotency Key)로 멱등성 구현하기
문제는 POST, PATCH 같은 메서드 자체는 원래 멱등하지 않다는 점이에요.
그래서 서버에서 “멱등키(idempotency key)”라는 개념을 도입해 멱등성을 직접 구현합니다.
멱등키란?
- 클라이언트가 요청을 보낼 때 함께 첨부하는 고유한 식별자예요. 보통 UUID v4 같은 랜덤한 문자열을 사용해요.
- 같은 작업(예: 같은 결제 취소)을 다시 요청할 때 동일한 멱등키를 재사용하면, 서버는 “아 이건 전에 처리했던 그 요청이구나”라고 인식하게 돼요.
동작 방식(일반적인 패턴)
- 클라이언트
- 결제, 결제 취소 같은 “멱등해야 하는 요청”을 보낼 때 헤더나 바디, 쿼리 파라미터 등에 멱등키를 함께 보냅니다.
- 네트워크 오류나 타임아웃이 나도, 같은 멱등키로 다시 요청을 보내요.
- 서버
- 요청을 받으면 멱등키가 있는지 확인해요.
- 멱등키 전용 DB(또는 캐시)에 “이 키로 처리된 요청이 있는지”를 조회합니다.
- 이전 기록이 있으면:
- 실제 비즈니스 로직(결제·취소)을 다시 수행하지 않고,
- 예전에 저장해둔 응답을 그대로 돌려줘요.
- 이전 기록이 없으면:
- 실제 비즈니스 로직을 수행하고,
- 그 때의 응답 결과와 상태를 멱등키와 함께 DB에 저장한 뒤 클라이언트에 반환해요.
이렇게 하면 클라이언트 입장에서는 “동일한 멱등키로 요청 → 항상 같은 결과”가 보장됩니다.
서버 상태(DB)도 처음 요청 때의 상태로 고정되기 때문에 멱등한 API가 되는 거죠.
또한 이 멱등키는 영원히 유지할 필요는 없고, 서비스마다 유효 기간을 정해 그 기간 동안만 멱등성을 보장한 뒤, 일정 시간이 지나면 같은 키를 새로운 요청에 다시 사용할 수 있게 설계하기도 해요.
5. 토스페이먼츠의 결제 취소 예시
토스페이먼츠 글에서는 결제 “취소” API를 예로 들어 멱등키가 어떻게 쓰이는지 보여줘요.
클라이언트 측
- 결제 취소 요청마다 UUID v4 등으로 멱등키를 하나 생성해 헤더에 넣어 보냅니다.
- 같은 취소 요청을 다시 시도할 때도 같은 멱등키를 재사용해요.
- 그러면 최초 요청 이후 재요청에서도 항상 HTTP 200과 동일한 응답 바디를 받게 됩니다.
서버 측
- 멱등성을 지원하는 서버는 다음 흐름을 따릅니다.
- 요청이 들어오면 헤더에서 멱등키를 꺼내 확인한다.
- 멱등키 DB를 조회해 이미 처리된 키인지 확인한다.
- 이미 처리된 키라면, 저장된 응답 데이터를 그대로 반환하고 실제 취소 로직은 다시 수행하지 않는다.
- 처음 보는 키라면, 실제 취소 처리를 수행한 뒤 응답과 함께 이 결과를 멱등키 DB에 저장한다.
토스페이먼츠는 여기서 멱등키만 보지 않고,
“멱등키 + API 키 + API 주소 + HTTP 메서드” 조합으로 요청의 동일성을 판별해요.
그래서 같은 멱등키라도 다른 API 엔드포인트이면 완전히 다른 요청으로 취급할 수 있게 설계되어 있어요.
6. 여러 API에서 재사용 가능한 멱등성 컴포넌트
멱등성이 필요한 API가 결제 취소 하나만 있는 것은 아니죠.
결제, 환불, 포인트 적립, 주문 생성 등 여러 곳에서 재시도·중복 요청 이슈가 생길 수 있어요.
매번 각 API마다 멱등 로직을 다시 구현하면:
- 코드 중복이 많아지고,
- 실수나 누락 가능성이 커지고,
- 유지보수도 어려워져요.
그래서 글에서는 **“멱등성 컴포넌트”**를 따로 만들어 두고, 여러 API에서 공통으로 사용하는 방식을 추천합니다.
이 공통 컴포넌트는 다음 역할만 담당해요.
- 멱등키 추출
- 멱등키 DB 조회 및 저장
- 이전 응답 재사용 여부 결정
실제 “결제 취소 처리”, “주문 생성” 등 도메인 로직은 원래 서비스 코드에 그대로 두고, 멱등성 처리만 컴포넌트로 분리하는 거죠.
이렇게 하면 도메인 로직이 복잡한 서비스에서도 불필요한 중복 작업을 줄이고, 일부 요청을 도메인 서버까지 보내지 않아도 돼서 성능 면에서도 이득을 볼 수 있어요.
7. 에러 시나리오와 권장 HTTP 상태 코드
멱등키를 도입하면 “서로 다른 요청인데 우연히 같은 멱등키를 썼을 때” 같은 예외 상황도 처리해야 해요.
글에서는 IETF 명세를 참고해 다음 세 가지 상황을 다루라고 제안합니다.
- 400 Bad Request
- 꼭 멱등키가 있어야 하는 API인데 멱등키가 누락되었거나, 형식이 잘못된 경우.
- 즉, 요청 자체가 잘못된 상황.
- 409 Conflict
- 이전 요청이 아직 처리 중인데, 같은 멱등키로 또 요청이 들어온 경우.
- “조금 기다렸다가 다시 시도해 주세요”라는 의미로 409를 보내는 식이에요.
- 422 Unprocessable Entity
- 처음 요청과 본문(payload)이 다른데도 같은 멱등키를 사용한 경우.
- 요청 형식은 유효하지만 “처음 요청과 동일한 멱등 요청”이 아니라서 받아들일 수 없다는 의미예요.
- 서버 입장에서는 “이 멱등키로는 이미 다른 내용의 요청을 처리했다”고 알려주는 셈이에요.
이런 규칙을 정해두면, 클라이언트 개발자도 멱등키 사용 실수를 빨리 발견하고 바로잡을 수 있어요.
8. 정리: 멱등성을 도입하면 얻는 것
이 글이 전달하는 핵심 메시지는 다음 한 줄로 요약할 수 있어요.
“결제 같은 중요한 API에는 반드시 멱등성을 넣자. 멱등키를 잘 설계하면, 네트워크 오류와 사용자의 중복 요청에도 안전하고 신뢰할 수 있는 시스템을 만들 수 있다.”
블로그에 쓸 때는:
- “멱등성 개념 + HTTP 메서드와의 관계”를 먼저 소개하고,
- “결제/취소 실전 시나리오”로 왜 중요한지 공감대를 만든 뒤,
- “멱등키 구조, 멱등성 컴포넌트, 에러 처리 규칙” 순서로 구현 아이디어를 풀어 쓰면,
독자들이 이해하기 좋고 바로 실무에 적용하기도 쉬울 거예요.
멱등성이 뭔가요? | 토스페이먼츠 개발자센터
생소한 표현이지만 알고 보면 쉬워요. 멱등성에 대해 이해하고 API를 멱등하게 제공하기 위한 방법도 함께 알아봐요.
docs.tosspayments.com
'CS Language' 카테고리의 다른 글
| curl 사용법 (0) | 2024.06.21 |
|---|