구현: 파티션·오프셋 분산
구현: 파티션·오프셋 분산 (Distribution)
이 페이지는 Kafka가 메시지를 어떻게 분산해서 저장하고, 컨슈머가 어디까지 읽었는지(오프셋)를 어떻게 기억하는지에 대한 내부 설계 이야기예요. 요즘 봇처럼 Kafka를 그냥 사용할 때는 몰라도 괜찮지만, 컨슈머 그룹이 왜 그렇게 동작하는지 궁금할 때 딱 좋은 내용이에요.
출처: 문서
본문
컨슈머 오프셋 추적 (Consumer Offset Tracking)
Kafka 컨슈머는 각 파티션에서 자신이 소비한 최대 오프셋을 추적하며, 오프셋을 커밋(commit)해서 재시작 시 그 지점부터 다시 이어서 소비할 수 있는 기능을 제공합니다. Kafka는 특정 컨슈머 그룹의 모든 오프셋을 그 그룹 전용으로 지정된 브로커(그룹 코디네이터, group coordinator)에 저장하는 옵션을 제공합니다. 즉, 그 컨슈머 그룹에 속한 어떤 컨슈머 인스턴스든 오프셋 커밋과 페치(fetch)를 그 그룹 코디네이터(브로커)에게 보내야 합니다.
컨슈머 그룹은 그룹 이름을 기준으로 코디네이터에 배정됩니다. 컨슈머는 아무 Kafka 브로커에게 FindCoordinatorRequest를 보내고, 코디네이터 세부 정보가 담긴 FindCoordinatorResponse를 읽어서 자신의 코디네이터를 찾을 수 있습니다. 그런 다음 컨슈머는 코디네이터 브로커에게 오프셋 커밋이나 페치 요청을 진행하면 됩니다. 코디네이터가 옮겨가면 컨슈머는 코디네이터를 다시 발견(rediscover)해야 합니다. 오프셋 커밋은 컨슈머 인스턴스가 자동 또는 수동으로 수행할 수 있습니다.
그룹 코디네이터가 OffsetCommitRequest를 받으면, 그 요청을 __consumer_offsets라는 특별한 컴팩션(compacted) Kafka 토픽에 추가합니다. 브로커는 오프셋 토픽의 모든 복제본이 오프셋을 받은 후에야 컨슈머에게 성공적인 오프셋 커밋 응답을 보냅니다. 설정 가능한 타임아웃 안에 오프셋이 복제되지 않으면 오프셋 커밋은 실패하며, 컨슈머는 백오프(back off) 후 커밋을 재시도할 수 있습니다. 브로커는 파티션별로 가장 최근의 오프셋 커밋만 유지하면 되므로 오프셋 토픽을 주기적으로 컴팩션합니다. 코디네이터는 오프셋 페치를 빠르게 처리하기 위해 메모리 내 테이블에도 오프셋을 캐시합니다.
코디네이터가 오프셋 페치 요청을 받으면, 단순히 오프셋 캐시에서 마지막으로 커밋된 오프셋 벡터를 반환합니다. 만약 코디네이터가 방금 시작되었거나 새 컨슈머 그룹 집합의 코디네이터가 된 경우(오프셋 토픽의 한 파티션 리더가 된 경우)에는 오프셋 토픽 파티션을 캐시에 로드해야 할 수 있습니다. 이 경우 오프셋 페치는 CoordinatorLoadInProgressException으로 실패하고, 컨슈머는 백오프 후 OffsetFetchRequest를 재시도할 수 있습니다.
더 알아보기 (Learn more)
- 오프셋 커밋이 저장되는
__consumer_offsets토픽과 그룹 코디네이터 동작은 컨슈머 그룹 내부 동작의 핵심이에요. - 컨슈머가 오프셋을 커밋하는 방식(자동/수동)과 재시도 로직을 살펴보면 장애 상황에서도 데이터를 안전하게 이어 소비할 수 있어요.