REST API 멱등성: 분산 시스템에서 데이터 무결성을 지키는 필수 원칙
분산 시스템에서 API 호출은 언제든 실패할 수 있다. 네트워크가 끊기거나 타임아웃이 발생하면 클라이언트는 같은 요청을 여러 번 보낸다. 이때 멱등성(idempotency)이 없다면 데이터가 중복되거나 상태가 꼬일 수 있다. 이는 단순한 기술적 개선이 아니라 시스템 안정성의 핵심이다.
멱등성이란 무엇인가
멱등성은 같은 요청을 여러 번 보내도 단 한 번 보낸 것과 같은 결과를 가지는 성질이다. 수학에서 f(f(x)) = f(x)인 경우를 생각하면 이해하기 쉽다. REST API 관점에서 보면, 동일한 HTTP 요청을 반복해도 서버 상태가 안전하게 유지되는 것을 의미한다. 이것이 보장되지 않으면 실패한 요청을 재시도할 때마다 부작용이 쌓인다.
분산 시스템이 멱등성을 요구하는 이유
분산 환경에서는 예측 불가능한 장애가 일상이다. 네트워크 패킷이 손실되거나 서버가 응답하기 전에 클라이언트 타임아웃이 발생할 수 있다. 이런 상황에서 클라이언트는 합리적으로 요청을 다시 보낸다. 멱등성이 없으면 같은 금융 거래가 여러 번 처리되거나, 동일한 주문이 중복 생성될 수 있다. 멱등성은 이런 재시도를 안전하게 만든다.
HTTP 메서드별 멱등성 구분
멱등한 메서드: GET, HEAD, PUT, DELETE는 RFC 7231에서 멱등한 메서드로 정의된다. GET은 데이터를 조회만 하므로 당연히 멱등하다. PUT은 같은 리소스를 여러 번 업데이트해도 최종 상태는 동일하다. DELETE도 이미 삭제된 리소스를 다시 지우려 해도 결과는 같다(보통 404를 반환).
멱등하지 않은 메서드: POST는 본질적으로 멱등하지 않다. 새로운 리소스를 생성하는 POST는 매번 새로운 엔티티를 만들기 때문이다. 결제 API에서 POST로 새로운 거래를 생성하면, 같은 요청을 두 번 보내면 두 개의 거래가 생성된다.
PATCH는 상황에 따라 다르다: PATCH의 멱등성은 구현 방식에 따라 결정된다. 부분 업데이트인 경우 멱등하지 않을 수 있으므로 개발 시 명시적으로 정의해야 한다.
멱등성을 보장하는 설계 패턴
Idempotency Key 활용: 클라이언트가 각 요청에 고유한 identifier(UUID, nonce 등)를 포함시키면 서버는 중복 요청을 감지하고 필터링할 수 있다. Stripe, AWS, Google 같은 대형 API 제공자들이 채택한 표준이다. HTTP 헤더로 Idempotency-Key를 전달하고, 서버는 이를 캐싱하여 같은 키로 들어온 재시도 요청에는 이전 응답을 반환한다.
리소스 기반 설계: POST 대신 PUT을 사용하여 멱등성을 강제하는 방식이다. /invoices/ABC-123 에 PUT으로 청구서를 생성하면, 같은 요청을 여러 번 보내도 같은 청구서만 유지된다. POST는 컬렉션에만 사용하고, 클라이언트가 최종 리소스 경로를 알면 PUT을 선호한다.
멱등한 상태 관리: 비즈니스 로직에서 부분적인 상태 변화를 피하고, 전체 상태를 원자적으로 업데이트하는 방식이다. 데이터베이스 트랜잭션과 함께 사용하면 더욱 안전하다.
실전 구현 시 주의할 점
멱등성을 선언했다면 일관되게 지켜야 한다. 같은 요청이 들어왔을 때 이전과 동일한 응답을 반환하는지 검증하는 테스트를 작성하자. 클라이언트가 Idempotency-Key를 전달하지 않는 경우도 고려해야 한다. API 문서에 어떤 메서드가 멱등한지, 어떻게 재시도를 처리하는지 명확히 명시해야 한다. 모니터링 시스템에서 중복 요청 비율을 추적하면 문제를 조기에 발견할 수 있다.
멱등성 없이는 신뢰할 수 없다
분산 시스템의 복잡성이 증가할수록 멱등성의 중요도는 높아진다. 마이크로서비스 아키텍처, 클라우드 환경, 고가용성 시스템에서 필수 원칙이다. API를 설계할 때부터 멱등성을 고민하고, 비멱등한 작업이 필요하면 보상 트랜잭션이나 상태 머신으로 안전장치를 만들어야 한다. 이것이 견고한 시스템과 불안정한 시스템의 차이를 결정한다.