멱등성이란 무엇인가요?
- 예상 시간
- 5분
멱등성(idempotency)은 같은 요청을 여러 번 보내도 결과가 달라지지 않는 성질입니다. 한 번 실행한 것과 열 번 실행한 것의 최종 상태가 동일하면 멱등합니다.
HTTP 메서드 중 GET, PUT, DELETE는 멱등하고, POST는 멱등하지 않습니다. 네트워크 오류로 재시도할 때 멱등한 요청은 안전하게 다시 보낼 수 있습니다.
멱등이라는 단어는 수학에서 왔습니다. f(f(x)) = f(x)를 만족하는 연산을 멱등이라 합니다. 절댓값 함수 abs(abs(x)) = abs(x)가 예입니다.
네트워크는 불안정합니다. 요청을 보냈는데 응답이 안 오면 서버가 처리했는지 모릅니다. 멱등한 요청이라면 그냥 다시 보내면 됩니다. 멱등하지 않으면 "이미 처리됐을 수 있는데 또 보내도 되나?"를 신경 써야 합니다. 분산 시스템에서 at-least-once delivery(최소 한 번 전달)를 쓸 때 멱등성이 필수입니다.
꼬리질문
조금 더 깊게 물어본다면
답변 뒤에 이어질 수 있는 질문들을 하나씩 열어볼 수 있어요.
HTTP 메서드별 멱등성은?
GET, HEAD, PUT, DELETE는 멱등합니다. POST와 PATCH는 멱등하지 않습니다.
| 메서드 | 멱등 | 이유 |
|---|---|---|
| GET | O | 조회만, 상태 변경 없음 |
| HEAD | O | GET과 같지만 body 없음 |
| PUT | O | 같은 데이터로 덮어씌우므로 결과 동일 |
| DELETE | O | 이미 없는 리소스를 또 삭제해도 "없음" 상태 동일 |
| POST | X | 매번 새 리소스 생성 가능 |
| PATCH | X | 상대적 변경이면 누적됨 |
DELETE가 멱등한 이유는 "없는 상태"가 목적이기 때문입니다. 이미 삭제된 리소스에 DELETE를 다시 보내면 404가 오지만, 서버 상태 자체는 "해당 리소스 없음"으로 동일합니다.
PUT이 멱등한 이유는 리소스 전체를 보내서 덮어쓰기 때문입니다. PUT /users/1 { name: "홍길동" }을 열 번 보내도 결과는 항상 name이 "홍길동"입니다.
POST는 /orders에 주문 생성 요청을 보낼 때, 같은 요청을 두 번 보내면 주문이 두 개 생깁니다. 멱등하지 않습니다.
PUT과 PATCH의 멱등성 차이는?
PUT은 리소스 전체를 교체하므로 멱등합니다. PATCH는 일부만 수정하는데, 수정 방식에 따라 멱등할 수도 아닐 수도 있습니다.
PATCH가 멱등하지 않은 케이스는 상대적 변경입니다.
PATCH /users/1
{ "increment_age": 1 }이 요청을 두 번 보내면 나이가 2 올라갑니다. 반면
PATCH /users/1
{ "age": 30 }이 요청은 몇 번을 보내도 나이가 30으로 고정됩니다. 멱등합니다.
REST API 설계에서 PATCH를 멱등하게 설계할지는 선택입니다. 다만 클라이언트가 재시도할 때를 고려하면 멱등하게 만드는 것이 안전합니다.
재시도 로직에서 멱등성이 왜 중요한가요?
네트워크 오류로 요청의 성공 여부를 알 수 없을 때 안전하게 재시도하려면 멱등성이 필요합니다. 멱등하지 않은 요청을 재시도하면 중복 처리가 생길 수 있습니다.
결제 API가 대표적입니다. 결제 요청을 보냈는데 응답이 timeout됐을 때, 결제가 됐는지 모르는 상태에서 그냥 재시도하면 이중 결제가 생깁니다.
해결 방법은 idempotency key입니다. 클라이언트가 요청마다 고유한 키를 헤더에 포함해 보내면, 서버가 같은 키로 이미 처리한 요청인지 확인해 중복을 막습니다.
POST /payments
Idempotency-Key: a3b8f2e-4c91-...
{ "amount": 10000 }같은 Idempotency-Key로 재시도하면 서버가 이전 응답을 그대로 돌려줍니다. Stripe, Toss 같은 결제 서비스가 이 패턴을 씁니다.
한 줄 정리
멱등성은 같은 요청을 반복해도 결과가 동일한 성질로, 재시도 안전성의 핵심 조건입니다.