주문이 두 번 도착했고 한 번은 사라졌다 · 한 번 사라짐 · 실습
커밋 시점이 한 번을 사라지게 한다 — 되감기와 멱등 처리
이 실습은 VM 에서 돕니다
우분투 VM 에 Apache Kafka 4.3.1 이 KRaft 단일 노드로 떠 있습니다
(localhost:9092). 도우미 ship-process 는 배송 처리기를 흉내 냅니다 — 표준
입력의 주문을 전부 읽은 뒤 하나씩 /root/kafka/processed.txt 에 적다가,SHIP_FIXED=1 이 아니면 order-2 에서 죽습니다. 처음 뜨는 데 4분쯤 걸립니다.
목표
컨슈머가 처리보다 먼저 오프셋을 커밋하면 크래시 뒤에 메시지가 "사라지는" 것을
재현하고, 그 메시지가 Kafka 에는 그대로 있음을 다른 그룹으로 확인한 뒤, 그룹
오프셋을 되감아 다시 처리합니다. 되감기가 만드는 중복은 멱등 컨슈머로 막고,auto.offset.reset 이 새 그룹의 첫 위치를 어떻게 정하는지 봅니다.
왜 중요한가
설계 문서의 '메시지 전달 의미론' 절이 이 실습의 대본입니다. 읽고 → 위치를
저장하고 → 처리하면, 처리 중 죽었을 때 그 메시지는 다시 오지 않습니다
(at-most-once). 읽고 → 처리하고 → 저장하면, 저장 전에 죽었을 때 다시
옵니다(at-least-once). 콘솔 컨슈머처럼 자동 커밋(enable.auto.commit 기본
true, 5초 간격)에 기대는 처리기는 앞의 모양에 가깝습니다. "한 번 사라졌다" 는
대개 이것이고, 고치면 "두 번 도착" 이 됩니다 — 그래서 처리기는 멱등해야 합니다.
문서는 그것을 "메시지에 기본 키가 있어 갱신이 멱등한 경우" 라고 적습니다.
단계
1. 토픽 shipments 를 파티션 1개로 만들고 order-1 부터 order-5 까지 다섯 줄을 넣으세요.
2. 그룹 ship-svc 로 처음부터 세 건을 읽어 ship-process 에 파이프하세요(죽습니다). 그 뒤 ship-svc 를 describe 해 /root/kafka/ship-crash.txt 에 저장하세요. CURRENT-OFFSET 은 3 인데 /root/kafka/processed.txt 에는 order-1 하나뿐이어야 합니다 — order-2, order-3 이 "사라진" 것입니다.
3. 새 그룹 audit-svc 로 처음부터 다섯 건을 읽어 /root/kafka/ship-audit.txt 에 저장하세요. Kafka 에는 전부 남아 있습니다.
4. ship-svc 의 오프셋을 가장 앞으로 되감고(--reset-offsets --to-earliest --execute) 그 출력을 /root/kafka/ship-reset.txt 에 저장하세요.
5. SHIP_FIXED=1 로 ship-svc 가 다섯 건을 다시 읽어 ship-process 에 파이프하세요. processed.txt 는 여섯 줄이 되고 order-1 이 두 번 있어야 합니다 — 되감기의 대가인 중복입니다.
6. /root/kafka/dedup.sh 를 만드세요. 표준 입력의 주문을 읽어 /root/kafka/seen.txt 에 없는 것만 /root/kafka/processed-dedup.txt 에 적고 seen 에 기록합니다(환경변수 DEDUP_SEEN·DEDUP_OUT 이 있으면 그 경로). shipments 를 처음부터 두 번 읽어 파이프해도 다섯 줄만 남아야 합니다.
7. --from-beginning 없이 새 그룹 late-svc 로 5초 읽고(0건), auto.offset.reset=earliest 로 새 그룹 early-svc 로 다섯 건을 읽으세요. /root/kafka/offset-reset.txt 에 late_count=0, early_count=5 두 줄을 쓰세요.
8. /root/kafka/consumer-report.txt 에 lost_after_crash=<2단계에서 사라진 건수>, duplicates_after_reset=<5단계 뒤 processed.txt 의 중복 건수>, unique_orders=<processed-dedup.txt 의 줄 수> 세 줄을 쓰세요.
참고
- 그룹으로 읽기:
kafka-console-consumer.sh --bootstrap-server localhost:9092 --topic shipments --group ship-svc --from-beginning --max-messages 3 --timeout-ms 8000 | ship-process - 되감기:
kafka-consumer-groups.sh ... --reset-offsets --group ship-svc --topic shipments --to-earliest --execute. 운영 문서대로 컨슈머가 멈춰 있어야 합니다.--execute없이 돌리면 계획만 보여 줍니다. - 새 그룹의 첫 위치: 컨슈머 설정 문서의
auto.offset.reset— 기본latest라 그룹에 오프셋이 없으면 지금 이후만 읽습니다.--command-property auto.offset.reset=earliest로 바꿉니다.--from-beginning은 콘솔 도구가 같은 일을 해 주는 단축키입니다. - 흔한 실수 1: 2단계에서
--max-messages를 빼는 것. 다섯 건을 다 읽어 버리면 '사라진 두 건' 이 재현되지 않습니다. - 흔한 실수 2: dedup 의 상태(seen)를 메모리에만 두는 것. 프로세스가 죽으면 상태도 죽어 다음 실행이 다시 중복을 냅니다. 파일이든 DB 든 처리 결과와 함께 남아야 합니다.
단계 8개
- 배송 주문 다섯 건
- 처리 전에 커밋하면 사라진다
- Kafka 에는 그대로 있다
- 그룹 오프셋을 되감는다
- 다시 처리하면 두 번 도착한다
- 멱등 컨슈머
- 새 그룹은 어디서 시작하나
- 사라진 것과 두 번 온 것을 센다