백엔드 면접 용어 사전
메시지 큐rebalancing · 리밸런싱

컨슈머 리밸런싱

컨슈머 그룹 구성이 변할 때 파티션을 재배분하는 과정. 그 동안 소비가 잠시 멈춘다.

컨슈머 그룹의 구성이 바뀔 때 파티션을 소비자들에게 다시 나눠 주는 과정.

언제 일어나나

  • 소비자가 추가되거나 종료될 때
  • 소비자가 죽은 것으로 판정될 때 (하트비트 끊김, poll 지연)
  • 파티션 수가 바뀔 때
  • 구독 토픽이 바뀔 때

무엇이 문제인가 — 전체가 멈춘다

전통적인(eager) 방식에서는

  1. 그룹 코디네이터가 리밸런싱 시작을 알림
  • 2. 모든 소비자가 자기 파티션을 반납 — ← 여기서 소비 전면 중단
  1. 새 할당을 계산
  2. 각자 새 파티션을 받아 재개

2~4 사이에 그룹 전체의 소비가 멈춘다(stop-the-world). 소비자가 많고 재시작이 잦으면 이 정지가 반복돼 지연이 눈에 띈다.

가장 흔한 원인 — poll 지연

while (true) {
    var records = consumer.poll(Duration.ofMillis(100));
    for (var r : records) {
        heavyWork(r);      // ← 여기가 5분 걸리면?
    }
}

max.poll.interval.ms(기본 5분) 안에 다음 poll()을 호출하지 않으면 코디네이터가 이 소비자를 죽은 것으로 판단하고 리밸런싱을 시작한다.

그런데 소비자는 멀쩡히 일하는 중이다. 작업을 마치고 커밋하려 하면 "넌 이미 쫓겨났다"며 실패하고, 그 파티션은 다른 소비자가 처음부터 다시 처리한다. → 중복 처리 + 무한 리밸런싱 루프.

대응

방법내용
max.poll.records 줄이기한 번에 가져오는 양을 줄여 처리 시간 단축
max.poll.interval.ms 늘리기오래 걸리는 작업을 허용
처리를 별도 스레드로poll 루프는 계속 돌리고 작업은 위임
정적 멤버십group.instance.id 지정 → 재시작해도 같은 파티션 유지
협력적 리밸런싱CooperativeStickyAssignor — 전체 중단 없이 필요한 것만 이동

하트비트와 poll 간격은 다르다

  • session.timeout.ms하트비트가 끊긴 시간. 별도 스레드가 보내므로 처리가 길어도 유지된다
  • max.poll.interval.mspoll 호출 간격. 처리 시간이 여기 걸린다

"하트비트는 살아 있는데 쫓겨났다"면 원인은 후자다.

Kafka 4.0의 새 프로토콜 (KIP-848)

2025년 3월 Kafka 4.0에서 차세대 리밸런스 프로토콜이 정식(GA) 이 됐다. 바뀐 핵심은 배정을 누가 계산하느냐다.

  • [기존] — 그룹 멤버 중 리더 컨슈머가 배정을 계산

    • 멤버가 하나 들고 날 때마다 그룹 전체가
      • 동기화 지점(join/sync 라운드)을 거쳐야 한다
  • [KIP-848] — 브로커의 그룹 코디네이터가 계산해

    • 각 컨슈머에게 점진적으로 내려보낸다
    • 나머지 컨슈머의 소비를 멈추지 않는다

컨슈머 수가 많은 대규모 그룹일수록 차이가 크다. 클라이언트도 단순해진다 — 배정 로직이 브로커로 옮겨갔기 때문이다.

group.protocol=consumer     # 새 프로토콜로 참여 (미지정 시 기존 방식)

면접 포인트: "리밸런싱은 stop-the-world인가요?"라는 질문에 세 단계로 답하면 깊이가 드러난다 — 예전 eager는 전부 멈췄고, 2.4의 cooperative는 옮겨지는 파티션만 멈췄으며, 4.0의 KIP-848은 브로커가 계산해 점진 적용한다.

함께 보면 좋은 용어

노트에서 맥락과 함께 보기 — 메시지 큐·비동기 — Kafka/RabbitMQ·EOS·순서·outbox