Kafka: abortOnNewBatch 매커니즘과 파티션 쏠림 이슈¶
Kafka Producer가 메시지를 전송할 때 사용하는 abortOnNewBatch 매커니즘은 성능 향상을 위한 장치이지만, 커스텀 파티셔너를 사용할 때 특정 파티션으로 데이터가 쏠리는 현상을 유발할 수 있습니다.
1. abortOnNewBatch란?¶
abortOnNewBatch는 Kafka Producer 내부의 RecordAccumulator에서 동작하는 로직입니다.
- 동작 원리: 메시지를 전송할 때 현재 선택된 파티션의 배치(Batch)가 가득 차서 새로운 배치를 생성해야 하는 상황이 오면, 작업을 중단(
abort)하고 파티션을 다시 결정(re-partition)하도록 유도하는 플래그입니다. - 목적: 가능한 한 이미 열려 있는(데이터가 채워지고 있는) 배치에 메시지를 밀어 넣어 배칭 효율을 극대화하고 네트워크 전송 횟수를 줄이기 위함입니다.
2. 커스텀 파티셔너 사용 시의 문제 상황¶
사용자가 직접 Partitioner 인터페이스를 구현하여 특정 로직에 따라 파티션을 분배할 때, 다음과 같은 무한 루프에 가까운 쏠림이 발생할 수 있습니다.
- 파티셔너 호출: Producer가 메시지를 보낼 파티션을 결정하기 위해 커스텀 파티셔너를 호출합니다. (예: 파티션 0번 선택)
- 배치 확인: 0번 파티션의 배치가 이미 가득 찼거나 새로 만들어야 하는 상태입니다.
- 작업 중단 (
abortOnNewBatch: true): Producer는 배치를 새로 만드는 대신 "다른 파티션을 찾아보자"며 전송 과정을 중단합니다. - 재시도: 다시 파티셔너를 호출합니다.
- 쏠림 발생: 커스텀 파티셔너 로직이 상태값이나 특정 키 기반이라면 또다시 0번 파티션을 선택하게 되고, Producer는 다시 중단하는 과정을 반복하거나 결국 억지로 해당 파티션에 배치를 새로 생성하여 밀어 넣게 됩니다.
결과적으로 라운드 로빈이나 균등 분배가 무너지고 특정 파티션에만 배치가 집중적으로 생성되는 현상이 나타납니다.
3. 해결 방법¶
3.1 batch.size 및 linger.ms 조정¶
배치가 너무 빨리 가득 차지 않도록 batch.size를 늘리거나, linger.ms를 조절하여 전송 타이밍을 튜닝합니다. 하지만 이는 근본적인 해결책은 아닙니다.
3.2 Sticky Partitioner 전략 이해 (v2.4+)¶
Kafka 2.4부터는 DefaultPartitioner가 배치가 가득 찰 때까지 한 파티션에 머무는 Sticky 전략을 사용합니다. 커스텀 파티셔너를 만들 때도 이 abortOnNewBatch 힌트를 고려해야 합니다.
3.3 커스텀 파티셔너 로직 보강¶
파티셔너 내부에서 단순히 순차적인 번호만 리턴하는 것이 아니라, 현재 Producer의 상태(배치 가득 참 여부)를 인지하거나, onNewBatch() 메서드를 적절히 오버라이드하여 배치가 새로 생성될 때만 파티션을 변경하도록 설계해야 합니다.
// Kafka 2.4+ 부터 제공되는 메서드
@Override
public void onNewBatch(String topic, Cluster cluster, int prevPartition) {
// 배치가 가득 차서 새로 생성될 때만 호출됨
// 여기서 다음 파티션 번호를 계산하여 저장해두면 쏠림을 방지할 수 있음
}
4. 요약¶
abortOnNewBatch는 "가급적 배치를 채워서 보내자"는 Kafka의 최적화 철학입니다. 커스텀 파티셔너를 구현할 때는 이 매커니즘 때문에 내 로직이 의도치 않게 특정 파티션만 계속 고집하게 되지 않는지 반드시 점검해야 합니다.