자동화 시스템에 재시도를 넣는 순간, 새로운 질문이 생깁니다. 같은 요청이 두 번 도착하면 어떻게 되는가. 통신 순단으로 응답을 못 받은 클라이언트는 재전송하는 것이 맞지만 서버가 이미 첫 요청을 처리했다면 장부에는 같은 거래가 두 줄 적힙니다. 돈이 걸린 시스템에서 이는 그냥 버그가 아니라 정산 사고입니다. 디지털 재화 거래를 무인 처리하는 시스템을 만들며 정착시킨 멱등성 설계를 정리합니다.
멱등성이란: 두 번 실행해도 한 번의 결과
멱등성(idempotency)은 같은 연산을 여러 번 수행해도 결과가 한 번 수행한 것과 같은 성질입니다. 실무 언어로 바꾸면 "재시도해도 안전하다"입니다. 멱등성이 확보되면 클라이언트는 응답을 못 받았을 때 마음 놓고 재전송할 수 있고 네트워크 순단·타임아웃·프로세스 재시작이 데이터 중복으로 이어지지 않습니다.
반대로 멱등성이 없는 시스템에서 재시도는 도박입니다. 그래서 많은 시스템이 재시도를 겁내다 유실을 택하거나, 재시도를 하다 중복을 만듭니다. 멱등성은 이 딜레마를 구조적으로 없애는 장치입니다.
멱등성 설계의 세 가지 패턴
우리 시스템에서는 처리 성격에 따라 세 가지 패턴을 썼습니다.
1. 내용 지문(fingerprint): 요청 내용에서 키를 만든다
거래 기록처럼 "같은 내용이면 같은 건"인 데이터는 내용 자체를 해시해 지문을 만듭니다. 거래처·방·메시지 식별자·수량을 이어 붙여 해시하면, 같은 주문이 어떤 경로로 다시 들어와도 같은 지문이 나옵니다. 서버는 지문이 이미 있으면 새 기록을 만들지 않습니다.
fingerprint = sha256(vendorId | chatId | messageId | quantity)지문 방식의 장점은 클라이언트가 상태를 유지할 필요가 없다는 점입니다. 재시작한 프로세스가 같은 메시지를 다시 읽어도, 지문이 같으니 결과도 같습니다.
2. 발급형 멱등키: 작업 단위마다 고유 ID를 붙인다
내용이 같아도 다른 작업일 수 있는 경우(같은 수량의 주문이 연달아 두 건)에는 지문이 못 씁니다. 이때는 작업을 시작할 때 고유한 작업 ID를 발급하고 그 ID를 처리 전 과정에 끌고 다닙니다. 서버는 같은 작업 ID의 요청을 두 번 받으면 두 번째는 첫 번째의 결과를 그대로 돌려줍니다. 통신이 순간적으로 흔들려 클라이언트가 재시도해도, 서버 입장에서는 같은 작업의 재확인일 뿐입니다.
3. 원자적 배정: 경쟁 조건은 서버에서 끝낸다
가장 까다로운 건 동시성입니다. 계정 풀에서 다음 계정을 배정하는 작업을 생각해 보면, "조회한 뒤 갱신"하는 2단계 구현은 두 요청이 동시에 오면 같은 계정을 두 곳에 배정합니다. 우리는 이 작업을 클라이언트에서 조회·갱신으로 나누지 않고 서버 측 단일 원자 연산으로만 수행하도록 아키텍처 결정을 못 박았습니다. 낙관적 동시성 제어(OCC)가 있는 백엔드에서 배정 로직 전체가 한 트랜잭션으로 돌고 클라이언트는 결과만 받습니다.
| 패턴 | 쓰는 곳 | 핵심 |
|---|---|---|
| 내용 지문 | 같은 내용 = 같은 건인 기록 | 상태 없이 중복 판정 |
| 발급형 멱등키 | 내용이 같아도 별개인 작업 | 작업 ID로 재시도 흡수 |
| 원자적 배정 | 동시성 경쟁이 있는 자원 할당 | 조회·갱신을 서버 원자 연산으로 |
멱등성이 만드는 운영의 여유
멱등성의 진짜 가치는 장애 대응에서 드러납니다. 우리 시스템은 장부 전송이 실패하면 로컬 버퍼에 쌓았다가 자동 재전송하는데, 이 재전송이 마음 편한 이유가 멱등성입니다. 몇 번을 다시 보내도 장부에는 한 번만 적히니, 복구 로직이 "혹시 이미 처리됐나"를 고민할 필요가 없습니다. 통신 순단에 2회 자동 재시도를 기본으로 걸 수 있는 것도 같은 이유입니다.
멱등성 없이 지은 시스템은 장애 때마다 "이 건이 처리됐는지" 사람이 대조해야 합니다. 멱등성은 코드 몇 줄이 아니라, 장애를 사람 없이 흡수하는 운영 능력의 토대입니다. 이 설계가 들어간 시스템 전체는 카카오톡 주문 자동화 사례에서, 함께 동작하는 안전장치들은 무인 자동화 안전장치 설계에서 볼 수 있습니다. 정산 데이터의 무결성 관점은 정산 데이터 불변성 설계와도 이어집니다.
자주 묻는 질문
멱등성 설계는 언제부터 필요한가요?
재시도가 있는 순간부터입니다. 네트워크를 건너는 기록, 결제·정산처럼 중복 비용이 큰 처리, 자동 복구가 있는 무인 시스템이라면 처음부터 넣어야 합니다. 나중에 붙이려면 이미 쌓인 데이터의 중복 여부를 판별할 방법부터 만들어야 해서 비용이 훨씬 큽니다.
멱등키는 무엇으로 만들어야 하나요?
데이터 성격에 따라 다릅니다. 같은 내용이면 같은 건인 기록은 내용 해시(지문)로, 내용이 같아도 별개인 작업은 발급형 고유 ID로 만듭니다. 중요한 것은 키 생성 규칙이 재시작·재시도 상황에서도 같은 건에 같은 키를 주는가입니다.
조회 후 갱신 방식이 왜 위험한가요?
두 요청이 동시에 조회하면 둘 다 같은 상태를 보고 같은 자원을 잡기 때문입니다. 자원 배정처럼 경쟁이 있는 작업은 조회와 갱신을 클라이언트에서 분리하지 말고 서버 측 단일 원자 연산(트랜잭션)으로 처리해야 중복 배정이 원천 차단됩니다.
멱등성과 중복 제거는 다른 건가요?
방향이 다릅니다. 멱등성은 중복이 생기지 않게 입구에서 막는 설계이고 중복 제거는 이미 들어온 데이터에서 중복을 찾아 정리하는 처리입니다. 입구를 멱등하게 만들수록 사후 중복 제거의 부담이 줄어듭니다.