Message Delivery Semantics
Kafka가 프로듀서에서 컨슈머까지 메시지를 전달할 때 보장하는 신뢰성 수준을 조절할 수 있으며, 이는 시스템의 요구사항에 따라 성능과 데이터 신뢰성 사이의 균형을 맞추는 중요한 설정이다.
At-most-once (최대 한 번 전송)
Section titled “At-most-once (최대 한 번 전송)”메시지가 유실될 수는 있지만 절대 중복되지는 않음을 의미하며, 가장 낮은 신뢰성 수준을 제공하고 최고의 성능을 목표로 할 때 사용된다.
- Producer 설정:
acks=0지정- 응답 대기 생략:
send()요청 후 브로커 응답을 기다리지 않아 네트워크 왕복 시간(RTT) 절약 - 위험성: 브로커 장애나 네트워크 단절 시 메시지 유실 발생
- 응답 대기 생략:
- Consumer 설정: 메시지 처리 전 오프셋 커밋
- 자동 커밋 사용 시 처리 완료 전 커밋이 발생하여 유실 가능성 존재
At-least-once (최소 한 번 전송)
Section titled “At-least-once (최소 한 번 전송)”메시지가 중복될 수는 있지만 절대 유실되지는 않음을 의미하며, 대부분의 애플리케이션에서 기본적으로 채택하는 신뢰성 수준이다.
- Producer 설정:
acks=all및retries > 0지정- 전송 보장: ISR의 모든 브로커가 메시지를 받았음을 확인 후 성공 간주
- 중복 발생 시나리오: 브로커가 메시지 저장 후 응답을 보내기 전 장애 발생 시 프로듀서가 재전송을 시도하여 중복 기록됨
- Consumer 설정: 메시지 처리 완료 후 수동 오프셋 커밋
- 처리 방식:
poll()배치의 로직이 모두 끝난 후commitSync()또는commitAsync()호출 - 중복 발생 시나리오: 로직 성공 후 커밋 전 컨슈머 장애 시 재시작 후 마지막 커밋 지점부터 다시 읽음
- 처리 방식:
멱등적 소비자(Idempotent Consumer) 구현 전략
Section titled “멱등적 소비자(Idempotent Consumer) 구현 전략”At-least-once 방식에서 발생하는 중복 처리를 방지하기 위해 소비자의 멱등성 확보가 필수적이다.
- 데이터베이스 활용: 메시지의 고유 키(예: 이벤트 ID, 주문 ID)를 데이터베이스의 Primary Key나 Unique Key로 사용하여 중복 삽입 방지
- 버전 관리: 데이터에 버전 번호를 두고, 현재 저장된 버전보다 낮은 버전의 데이터가 들어오면 무시
- 상태 저장소 활용: Redis나 DB에 처리된 메시지 ID를 저장하고, 메시지를 처리하기 전에 ID의 존재 여부를 먼저 확인하여 중복 실행 방지
메시지 순서 보장과 In-flight 요청
Section titled “메시지 순서 보장과 In-flight 요청”Kafka는 파티션 단위로 순서를 보장하지만, 프로듀서의 재전송 설정에 따라 순서가 뒤바뀌는 예외 상황이 발생할 수 있다.
순서 역전 현상 (Out-of-order) 발생 원인
Section titled “순서 역전 현상 (Out-of-order) 발생 원인”max.in.flight.requests.per.connection 설정이 1보다 크고 enable.idempotence=false인 상태에서 retries가 활성화된 경우 발생한다.
- 전송 시도: 프로듀서가 메시지 A(Seq 1)와 메시지 B(Seq 2)를 비동기로 연속 전송
- 부분 실패: 메시지 A는 네트워크 일시 오류로 실패하고, 메시지 B는 브로커에 성공적으로 기록
- 재전송: 프로듀서가 실패한 메시지 A를 재전송
- 결과: 브로커 로그에는 B(Seq 2), A(Seq 1) 순서로 저장되어 메시지 순서가 뒤섞임
멱등적 프로듀서를 통한 해결
Section titled “멱등적 프로듀서를 통한 해결”- 과거의 해결책:
max.in.flight.requests.per.connection=1로 설정하여 한 번에 하나의 요청만 처리(처리량 저하 초래) - 현재 해결책:
enable.idempotence=true활성화- 시퀀스 검증: 브로커는 파티션별로 프로듀서의 시퀀스 번호를 추적하여 번호가 누락된 요청(Gap)은 거절하고, 이미 처리된 번호는 중복으로 처리하여 저장하지 않음
- 윈도우 보장: 브로커는 최근 5개의 시퀀스 번호를 관리하므로,
max.in.flight.requests.per.connection을 5 이하로 설정하면 성능을 유지하면서도 순서 보장 가능
Exactly-once (정확히 한 번 전송)
Section titled “Exactly-once (정확히 한 번 전송)”메시지가 유실되거나 중복되지 않고 정확히 단 한 번만 처리됨을 보장하는 가장 강력한 신뢰성 수준이다.
- Producer:
enable.idempotence=true/transactional.id=<UNIQUE_ID>설정enable.idempotence=true로 설정하여 브로커로의 메시지 중복 전송 방지transactional.id를 고유하고 안정적인 값으로 설정하여 트랜잭션을 활성화- 이를 통해 여러 토픽 파티션에 걸친 ‘읽기-처리-쓰기’ 작업을 하나의 원자적 단위로 묶어줌
- Consumer:
isolation.level=read_committed설정- 컨슈머는 최종적으로 커밋(Commit)된 트랜잭션에 포함된 메시지만 읽도록 설정
- 만약 트랜잭션이 처리 도중 중단(Abort)되면, 해당 트랜잭션에 포함된 모든 메시지는 컨슈머에게 노출되지 않아 데이터 정합성 보장
전송 보장 수준별 성능 및 트레이드오프
Section titled “전송 보장 수준별 성능 및 트레이드오프”신뢰성이 높아질수록 추가적인 네트워크 통신과 디스크 I/O가 발생하여 성능 하락이 수반된다.
| 보장 수준 | 처리량(Throughput) | 지연 시간(Latency) | 신뢰성 | 주요 용도 |
|---|---|---|---|---|
| At-most-once | 최고 | 최저 | 낮음 | 로그 수집, 단순 모니터링 지표 |
| At-least-once | 높음 | 보통 | 높음 | 일반적인 비즈니스 이벤트 처리 |
| Exactly-once | 보통 | 높음 | 최고 | 금융 결제, 핵심 데이터 동기화 |