드디어 분산 시스템의 가장 까다로운 난제이자, 금융권 주식 시스템에서는 '목숨'과도 같은 주제인 순서 보장과 중복 방지(멱등성)에 도달하셨군요! 🫡
사용자의 주식 계좌에서 '1억 입금' 후 '1억 출금'이 순서가 바뀌어 '출금'부터 시도되면 잔액 부족으로 에러가 날 것이고, '1억 입금' 메시지가 중복 처리되어 2억이 입금된다면 은행은 파산하겠죠.

🔢 1. 메시지 순서 보장 (Message Ordering)
RabbitMQ는 기본적으로 단일 큐(Single Queue) 내에서는 메시지 순서를 보장합니다. 하지만 실무(쿠버네티스 환경)에서는 순서가 뒤섞이는 복병들이 있습니다.
① 순서가 꼬이는 주범: 병렬 소비자 (Multiple Consumers)
우리가 앞서 배운 'Work Queues'에서 소비자 파드를 여러 개 두면 순서가 깨집니다. 1번 메시지는 느린 파드에, 2번 메시지는 빠른 파드에 배정되면 2번이 먼저 처리될 수 있기 때문입니다.
② 해결책: 단일 소비자 vs 일관성 해싱 (Consistent Hashing)
- 단일 소비자: 순서가 절대적이라면 해당 큐에는 소비자를 딱 하나만 둡니다. 하지만 처리 속도가 느려진다는 단점이 있죠.
- 일관성 해싱 (Consistent Hashing Exchange): 이게 고급 기술입니다! 메시지의 특정 키(예:
stock_code=SAMSUNG)를 해싱하여 특정 종목의 메시지는 항상 특정 큐로만 가게 만듭니다. - 삼성전자 메시지는 A큐로, SK하이닉스는 B큐로 보냅니다.
- 각 큐에는 소비자를 하나씩만 배정합니다.
- 이렇게 하면 종목별 순서는 완벽히 보장되면서 전체적인 처리 속도는 병렬로 가져갈 수 있습니다.
🛡️ 2. 중복 방지의 핵심: 멱등성 (Idempotency)
분산 시스템에서 "메시지는 반드시 한 번 이상 전달된다(At-least-once delivery)"는 원칙 때문에 중복 메시지는 피할 수 없는 숙명입니다. 따라서 시스템은 똑같은 메시지를 두 번 받아도 결과가 같아야 하는데, 이를 멱등성이라고 합니다.
① 왜 중복이 발생하는가?
네트워크 장애로 인해 소비자가 일을 다 끝내고도 RabbitMQ에게 "나 다 했어(Ack)"라는 신호를 보내지 못하면, RabbitMQ는 "일이 안 끝났네?" 하고 똑같은 메시지를 다른 파드에게 다시 보냅니다.
② 설계 전략 1: 유니크 키 (Unique ID)
모든 메시지에 생성 시점의 고유 ID(UUID)를 부여합니다.
- 소비자는 메시지를 처리하기 전, DB나 Redis에서 "이 ID를 이미 처리했나?"를 확인합니다.
- 처리했다면 그냥 버리고(Ack만 보냄), 안 했다면 처리 후 ID를 저장합니다.
③ 설계 전략 2: 데이터베이스 레벨의 멱등성
- UPSERT (Insert or Update): 데이터를 넣을 때 이미 존재하면 덮어쓰거나 무시하도록 SQL을 짭니다. (
ON CONFLICT구문 등) - 상태 체크: "입금 완료" 상태인 데이터에 또 "입금" 메시지가 오면 무시하도록 비즈니스 로직을 보호합니다.
🛠️ 3. 실전 아키텍처: "A그룹 주식 매매 시스템"
사용자의 핵심 시스템을 위한 무결성 설계 요약입니다.
- 발행 단계: 메시지에
correlation_id를 넣고,publisher confirms기능을 켜서 RabbitMQ에 안전하게 도달했는지 확인합니다. - 보관 단계: Quorum Queues를 사용하여 메시지가 여러 노드에 복제되도록 하여 유실을 방지합니다.
- 소비 단계:
Prefetch Count를 적절히 조절하고, Redis를 활용해 처리된 메시지 ID를 24시간 동안 캐싱하여 중복을 원천 차단합니다. - 복구 단계: 처리에 실패한 메시지는 아까 배운 DLX로 보내 원인을 분석합니다.
💡 실전 비유: "은행 창구와 번호표"
- 순서 보장: 은행에 온 손님들이 번호표 순서대로 상담받는 것입니다. 만약 상담원이 여러 명(Consumer)이면 먼저 온 손님이 복잡한 상담을 할 때 뒤 손님이 먼저 끝날 수 있죠. 이를 막으려면 "입출금 전담 창구(Specific Queue)"를 만들어 순서를 강제해야 합니다.
- 멱등성: 손님이 "제 계좌에 100만 원 입금해 주세요"라고 말했는데, 상담원이 깜빡하고 두 번 처리할 뻔한 상황입니다. 이때 상담원이 "아까 처리하신 전표(Message ID) 여기 있네요"라고 하며 두 번째 요청을 거절하는 것이 멱등성 설계입니다.
📊 요약: 무결성 유지 체크리스트
| 목표 | 적용 기술 | 기대 효과 |
|---|---|---|
| 전체 순서 보장 | 단일 소비자 (Single Active Consumer) | 절대적인 처리 순서 유지 |
| 부분 순서 보장 | 일관성 해싱 (Consistent Hashing) | 종목/사용자별 순서 보장 + 성능 확보 |
| 중복 방지 | Message ID + Redis Check | 중복 결제/처리 방지 (멱등성) |
| 데이터 안전 | Publisher Confirms + Quorum Queues | 메시지 유실 및 중복 발행 방지 |
🚀 꼬리 질문 🫡
순서와 중복까지 다스리게 되셨으니, 이제 사용자의 시스템은 전 세계 어떤 금융 인프라와 비교해도 손색이 없는 견고함을 갖추게 되었습니다.
그런데 지금까지는 우리가 '메시지 브로커'에 집중했지만, 사실 시스템이 커지면 RabbitMQ 자체의 모니터링이 또 다른 숙제가 됩니다. 큐에 메시지가 얼마나 쌓였는지, 소비자가 노는 건 아닌지 실시간으로 감시해야 하죠.
"그럼 RabbitMQ의 상태를 Prometheus/Grafana로 시각화하고, 큐에 메시지가 너무 많이 쌓였을 때 쿠버네티스 파드 개수를 자동으로 늘려주는 'KEDA'는 어떻게 연동해?"
'1. 개발 > 1.1. RabbitMQ' 카테고리의 다른 글
| Prometheus/Grafana 시각화, 'KEDA' 연동 (0) | 2026.02.13 |
|---|---|
| 'TTL(Time To Live)'과 'Dead Letter Exchange(DLX)' (0) | 2026.02.12 |
| 'Prefetch Count' 설정과, 'Work Queues'의 부하 분산 원리 (0) | 2026.02.12 |
| 고가용성(HA)을 위한 'Clustering'과 'Quorum Queues' (0) | 2026.02.12 |
| RabbitMQ 에 대한 모든것 (0) | 2026.02.12 |