← 문제로

24. 멱등성과 exactly-once의 착시: at-least-once + dedup 설계

난이도 중
내 답안
모범답안

난이도: 중

1. exactly-once가 불가능한 이유와 effectively-once

네트워크는 메시지 유실·지연·중복을 막을 수 없고, "처리했다"는 사실과 "그 사실을 상대에게 알렸다"는 사실을 하나의 원자 연산으로 묶을 방법이 근본적으로 없다(두 장군 문제). 송신자가 ACK를 못 받으면 재전송할 수밖에 없고, 그 재전송이 원본과 중복인지 수신자는 구별해야 한다. 따라서 전달 계층은 현실적으로 at-least-once(중복 허용) 또는 at-most-once(유실 허용) 둘 중 하나다.

실무의 정답은 at-least-once 전달 + 수신 측 멱등 처리(dedup) = effectively-once다. 즉 "네트워크는 여러 번 보내도 되지만, 애플리케이션의 관측 가능한 효과는 한 번"으로 만든다.

2. 멱등성과 부수효과 연산

멱등한 연산은 여러 번 적용해도 결과가 한 번 적용한 것과 같은 연산이다. 재화 지급처럼 부수효과(상태 변화)가 있는 연산을 멱등하게 만들려면 세 요소가 필요하다.

  • 멱등 키(idempotency key): 요청을 유일하게 식별(결제 ID, 메시지 offset, 클라 생성 UUID). "같은 논리적 요청"을 판정하는 기준.
  • 처리 여부 저장: 이 키를 이미 처리했는지 기록하는 저장소(dedup 테이블/키).
  • 원자적 결합: "효과 적용"과 "키 기록"이 원자적으로 함께 커밋되어야 한다. 분리되면 둘 사이 크래시에서 이중 지급 또는 미지급이 난다.

전형적 구현: INSERT INTO processed(key) ... 가 지급 UPDATE와 같은 DB 트랜잭션에 있으면, 중복 키는 UNIQUE 위반으로 트랜잭션 전체가 롤백되어 지급도 취소된다.

3. 멱등 키 TTL 산정

멱등 키의 보존 기간은 곧 **중복을 걸러낼 수 있는 창(window)**이다. 반드시 상류의 최대 재시도/재투입 지평 이상이어야 한다. 결제사가 최대 24시간 재시도하고 DLQ 재투입이 며칠 뒤에도 일어난다면, TTL 10분짜리 dedup 키는 만료 후 도착한 늦은 중복을 걸러내지 못해 이중 지급된다. TTL이 짧으면 "대부분은 막히는데 가끔 두 번 지급되는" 재현 어려운 사고가 난다. 저장 비용이 문제면 만료 대신 콜드 스토리지로 이관하거나, 시간 기반 파티셔닝으로 오래된 키를 아카이브한다.

4. Redis 마커 vs DB UNIQUE 제약

  • Redis 단독 마커: 빠르고 부하가 낮다. 그러나 "지급(DB 커밋)"과 "마킹(Redis)"이 서로 다른 저장소라 원자적으로 묶이지 않는다. 커밋 후 마킹 전 크래시하면 표시가 없어 재시도 시 이중 지급. 또 Redis 데이터 유실 시 dedup이 통째로 날아간다.
  • DB UNIQUE 제약(같은 트랜잭션): 지급과 dedup 기록이 한 트랜잭션이라 원자적·강건하다. 중복이면 커밋 실패로 지급도 롤백. 단, 모든 요청이 DB를 때리므로 부하가 크다.
  • 실무 절충: Redis를 빠른 1차 필터로 두어 명백한 중복을 싸게 걸러내고, 통과한 요청은 DB UNIQUE를 최종 방어선으로 둔다. 성능과 정확성을 함께 얻는다.

5. 자연 멱등 vs 비자연 멱등

  • 자연 멱등: SET balance = 5, status = 'DONE' 처럼 절댓값을 쓰는 연산은 여러 번 적용해도 결과가 같다.
  • 비자연 멱등: balance += 5, "우편 발송", "카운터 증가"처럼 상대적/누적 연산은 반복하면 결과가 달라진다.
  • 비자연 멱등을 멱등하게 만드는 법: (a) 멱등 키로 dedup해 중복 적용 자체를 차단, (b) 가능하면 절댓값/목표 상태로 재정식화(예: "이 결제의 지급 결과는 항상 +5이며 processed 테이블로 1회 보장"), (c) 이벤트 소싱처럼 효과를 이벤트로 기록하고 같은 이벤트 ID는 한 번만 반영.

면접 포인트

  • exactly-once "전달"과 effectively-once "처리"의 구분, 그리고 두 장군 문제.
  • 멱등성의 세 축(키·저장·원자 결합)과 TTL이 곧 dedup 창이라는 점.
  • 자연/비자연 멱등의 구분과 재정식화 전략.