Kafka StickyPartitioner 버그로 인한 메시지 분배 불균형 해결
Kafka Client 3.3 미만 버전에서 StickyPartitioner 버그로 특정 파티션에 메시지가 몰리는 현상이 발생했습니다. 원인 분석부터 해결까지의 과정을 정리합니다.
문제 상황
Gmarket AdTech팀에서 CPC 광고 랭킹 시스템을 개선하던 중, Kafka로 발행하는 랭킹 갱신 메시지가 특정 파티션에만 몰리는 현상이 발견됐습니다.
예상 동작은 파티션에 균등하게 메시지가 분배되어야 하지만, 실제로는 파티션 0과 2에만 메시지가 집중되고 나머지 파티션은 거의 비어 있는 상태였습니다.
Partition 0: ████████████ 45%
Partition 1: ██ 5%
Partition 2: ████████████ 48%
Partition 3: ▏ 2%
원인 분석
StickyPartitioner의 버그
Kafka Client 2.4부터 기본 파티셔너가 RoundRobinPartitioner에서 StickyPartitioner로 변경되었습니다. StickyPartitioner는 배치 효율을 높이기 위해 배치가 채워질 때까지 동일 파티션에 메시지를 보내는 방식입니다.
그런데 Kafka Client 3.3 미만 버전의 StickyPartitioner에는 특정 조건(낮은 linger.ms 설정, 일부 브로커 지연)에서 특정 파티션에만 편중되는 버그가 존재합니다.
// 문제가 있는 버전의 StickyPartitioner 내부 로직 (단순화)
// partition() 메소드가 특정 조건에서 두 번 호출되어
// 짝수/홀수 파티션에만 메시지가 분배되는 버그
추가로 **Kafka Client 2.4 버전 이상의 RoundRobinPartitioner**에도 partition() 메소드가 두 번씩 호출되어 짝/홀수 파티션에만 분배되는 버그가 있습니다.
설정 환경 확인
# application.yml
spring:
kafka:
producer:
linger-ms: 0 # 낮은 linger.ms 설정 → 버그 트리거 조건
properties:
partitioner.class: org.apache.kafka.clients.producer.internals.DefaultPartitioner
저희 환경은 낮은 linger.ms로 설정되어 있었고, 이것이 버그를 트리거하는 조건이었습니다.
해결 방법
Kafka Client 버전 업그레이드
가장 근본적인 해결책은 Kafka Client 버전을 3.3 이상으로 업그레이드하는 것입니다.
<!-- pom.xml -->
<dependency>
<groupId>org.springframework.kafka</groupId>
<artifactId>spring-kafka</artifactId>
<version>3.1.0</version> <!-- Kafka Client 3.3+ 포함 -->
</dependency>
Kafka Client 3.3부터 기존의 StickyPartitioner와 RoundRobinPartitioner를 대체하는 개선된 DefaultPartitioner가 적용됩니다.
검증
업그레이드 후 파티션 분배 현황:
Partition 0: ██████ 25%
Partition 1: ██████ 25%
Partition 2: ██████ 25%
Partition 3: ██████ 25%
균등한 분배가 확인됐습니다.
결과
- Kafka 메시지 분배 불균형 완전 해소
- 파티션 편중으로 인한 특정 컨슈머 과부하 문제 해결
- 랭킹 데이터 업데이트의 균일하고 예측 가능한 처리 성능 확보
교훈
라이브러리 버전을 업그레이드할 때는 반드시 릴리스 노트와 버그 픽스 내역을 확인하는 것이 중요합니다. 이번 케이스처럼 기본 동작에서 버그가 있는 경우 원인을 찾기 어려울 수 있기 때문입니다.
또한 메시지 분배 상태를 Datadog 대시보드로 실시간 모니터링하고 있었기에 조기에 문제를 발견할 수 있었습니다. 적절한 모니터링 체계의 중요성을 다시 한번 느꼈습니다.