[Kafka 운영 ②] Consumer Lag이 줄지 않는 7가지 원인과 처방
Kafka 컨슈머 랙(consumer lag)이 좀처럼 줄지 않는 7가지 근본 원인을 증상→진단→처방 순서로 정리합니다. 느린 컨슈머 처리, poll 루프 블로킹, 병렬성 부족, 핫 파티션, GC, 브로커 병목, 오프셋 커밋 문제까지 진단 명령과 설정 표, 의사결정 플로우로 풀어냅니다.
새벽 3시, 알림이 울립니다. "Consumer lag 1,200만 건, 계속 증가 중." 컨슈머는 멀쩡히 돌고 있고, 에러 로그도 없고, CPU도 한가합니다. 그런데 랙은 줄지 않습니다. 마치 양동이에 물을 퍼내는데 구멍으로 들어오는 양이 더 많은 상황이죠. 이 글은 그 "구멍"이 어디인지 찾는 지도입니다. 랙이 줄지 않는 데는 거의 항상 정해진 7가지 패턴이 있습니다.
이 글에서 배우는 것
- 컨슈머 랙이 줄지 않을 때의 7가지 근본 원인과 각각의 처방
kafka-consumer-groups.sh --describe로 어느 파티션이 밀리는지 콕 집어내는 법max.poll.records·max.poll.interval.ms·fetch.*핵심 설정의 의미와 트레이드오프- 컨슈머 수와 파티션 수의 황금 비율, 그리고 핫 파티션을 푸는 법
- 증상만 보고 곧장 원인으로 가는 의사결정 플로우
이 글은 「Kafka 운영 트러블슈팅」 시리즈의 2편입니다. 랙을 어떻게 측정하고 모니터링하는지는 1편 「Consumer Lag 측정과 모니터링」에서, 리밸런스 폭풍이 랙을 만드는 메커니즘은 6편 「Rebalance Storm」에서 더 깊이 다룹니다. 이 글은 "측정은 됐는데 줄지 않는다"는 다음 단계에 집중합니다.
1. 먼저, 랙이 "줄지 않는다"를 정의하자
처방에 앞서 증상을 정확히 읽어야 합니다. 랙(lag)은 파티션별로 log-end-offset(브로커가 가진 마지막 오프셋)과 current-offset(컨슈머가 커밋한 오프셋)의 차이입니다. 줄지 않는 랙은 보통 세 가지 형태로 나타납니다.
| 패턴 | 랙 그래프 모양 | 해석 |
|---|---|---|
| 선형 증가 | 우상향 직선 | 처리량(consume rate) < 유입량(produce rate). 만성적 처리 부족 |
| 톱니파(sawtooth) | 쌓였다 → 잠깐 줄었다 → 다시 쌓임 | 리밸런스 루프, 주기적 GC, 배치 다운스트림 정체 |
| 특정 파티션만 폭증 | 한 파티션만 우상향, 나머지 평탄 | 핫/스큐 파티션, 또는 일부 컨슈머만 멈춤 |
진단의 출발점: --describe
랙 트러블슈팅은 항상 이 명령에서 시작합니다. 그룹 전체가 아니라 파티션 단위로 봐야 한다는 점이 핵심입니다.
kafka-consumer-groups.sh \
--bootstrap-server broker1:9092 \
--describe \
--group payment-consumerGROUP TOPIC PARTITION CURRENT-OFFSET LOG-END-OFFSET LAG CONSUMER-ID HOST CLIENT-ID
payment-consumer payments 0 1048576 1048590 14 consumer-1-a1b2 /10.0.1.5 consumer-1
payment-consumer payments 1 990000 1990000 1000000 consumer-2-c3d4 /10.0.1.6 consumer-2
payment-consumer payments 2 1048500 1048512 12 consumer-3-e5f6 /10.0.1.7 consumer-3
payment-consumer payments 3 1048400 1048450 50 consumer-1-a1b2 /10.0.1.5 consumer-1이 출력 한 장이면 절반은 진단됩니다. 위 예시에서는 파티션 1만 100만 건이 밀려 있습니다(나머지는 두 자릿수). 이건 "전체가 느린" 문제가 아니라 핫 파티션(원인 4)이거나 파티션 1을 맡은 컨슈머만 멈춘(원인 5·7) 문제입니다. 만약 모든 파티션의 LAG이 고르게 커지면 처리량 부족(원인 1·3·6)입니다.
체크포인트:
CONSUMER-ID가 비어 있는(-) 파티션이 있다면 그 파티션에는 할당된 컨슈머가 없다는 뜻입니다. 컨슈머가 죽었거나, 리밸런스가 끝나지 않았거나, 컨슈머 수 > 파티션 수(원인 3)입니다.
2. 원인 ①: 느린 컨슈머 처리 (다운스트림 지연)
가장 흔한 원인입니다. 컨슈머 코드 자체는 빠른데, 메시지 한 건마다 다운스트림(DB·외부 API)을 동기 호출하면서 그 응답을 기다리느라 처리량이 바닥나는 경우입니다.
증상
- 모든 파티션의 랙이 고르게 선형 증가.
- 컨슈머 CPU는 한가한데(I/O 대기) 처리 건수/초가 낮음.
- 다운스트림 DB·API의 p99 레이턴시가 높거나 들쭉날쭉.
진단
처리량을 거꾸로 계산해 봅니다. 메시지 한 건 처리에 다운스트림 왕복이 20ms 걸린다면, 단일 스레드 컨슈머의 이론상 최대 처리량은 초당 50건입니다. 유입량이 초당 5,000건이라면 100배 부족한 셈이고, 랙은 영원히 줄지 않습니다.
유입량(produce rate) : 5,000 msg/s
컨슈머 1개 다운스트림 RTT : 20 ms → 50 msg/s
필요 병렬도 : 5,000 / 50 = 100 (단순 환산)
현재 파티션/컨슈머 : 12개 → 600 msg/s ⟶ 적자처방
핵심은 poll로 받아온 메시지를 한 건씩 동기 처리하지 않는 것입니다.
- 다운스트림 배치 쓰기: 건당
INSERT대신INSERT ... VALUES (...), (...), ...로 수백 건을 한 번에. RTT 1회로 수백 건을 처리해 처리량이 수십~수백 배 뜁니다. - 비동기 쓰기 + 파이프라이닝: 다운스트림 호출을 비동기로 보내고, 응답을 받은 오프셋까지만 커밋합니다(순서·정합성 주의).
- 병렬성 확대: 파티션 수를 늘리고 컨슈머를 그만큼 띄웁니다(원인 3 참조). 단, 파티션 수가 곧 병렬성 상한입니다.
# 안티패턴: 건당 동기 처리 (RTT가 처리량을 지배)
for record in consumer:
db.execute("INSERT INTO events VALUES (%s)", record.value) # 매번 20ms 대기
# 처방: poll 단위 배치 + 묶음 쓰기
while True:
batch = consumer.poll(timeout_ms=500, max_records=500)
rows = [r.value for tp in batch.values() for r in tp]
if rows:
db.execute_batch("INSERT INTO events VALUES %s", rows) # 1 RTT로 수백 건
consumer.commit() # 다운스트림 성공 후 커밋3. 원인 ②: poll 루프가 max.poll.interval.ms보다 오래 블로킹
가장 음흉한 원인입니다. 컨슈머는 살아 있는데 랙이 톱니파로 쌓이고, 로그에 주기적으로 리밸런스가 찍힙니다.
메커니즘
Kafka 컨슈머는 poll()을 주기적으로 호출해야 "나 살아 있다"는 신호로 인정됩니다. 한 번 poll()로 가져온 메시지(max.poll.records개)를 처리하는 데 max.poll.interval.ms(기본 5분)를 초과하면, 브로커는 그 컨슈머가 죽은 것으로 보고 그룹에서 **추방(eviction)**하고 리밸런스를 트리거합니다.
추방당한 컨슈머는 마지막 배치를 커밋하지 못하므로, 재할당받은 컨슈머가 같은 구간을 다시 처리합니다. 그런데 그 처리 역시 느려서 또 추방됩니다. 이 루프는 영원히 따라잡지 못하고, 랙은 톱니파로 진동하며 우상향합니다. (이 추방→리밸런스 연쇄가 클러스터 전반으로 번지는 양상이 6편의 리밸런스 폭풍입니다.)
진단
컨슈머 로그에서 다음 메시지를 찾습니다.
This member will leave the group because consumer poll timeout has expired.
This means the time between subsequent calls to poll() was longer than the
configured max.poll.interval.ms, which typically implies that the poll loop
is spending too much time processing messages.처방
처리 시간을 max.poll.interval.ms 안으로 들여놓는 것이 목표입니다. 세 가지 레버가 있습니다.
| 레버 | 방향 | 효과 | 주의 |
|---|---|---|---|
max.poll.records 낮추기 | ↓ (예: 500→100) | 한 배치 처리 시간 단축 → 추방 회피 | 너무 낮추면 poll 오버헤드↑ |
max.poll.interval.ms 높이기 | ↑ (예: 5분→10분) | 느린 배치도 허용 | 진짜 죽은 컨슈머 감지가 느려짐 |
| 처리를 poll 스레드 밖으로 | 구조 변경 | 근본 해결 | 오프셋 커밋 정합성 설계 필요 |
가장 견고한 해결책은 세 번째입니다. poll 스레드는 수령과 워커 큐 적재만 담당하고, 실제 처리는 별도 스레드 풀에서 합니다. 그러면 poll 루프는 절대 블로킹되지 않습니다.
# poll 스레드는 빠르게 돌고, 처리는 워커 풀로 위임
while True:
batch = consumer.poll(timeout_ms=300, max_records=100)
for tp, records in batch.items():
worker_pool.submit(process_partition, tp, records)
# 워커가 완료 보고한 오프셋까지만 커밋 (정합성 핵심)
consumer.commit(offsets=completed_offsets.snapshot())단, 처리를 비동기로 빼면 오프셋 커밋 시점이 까다로워집니다. 아직 처리되지 않은 구간을 커밋하면 장애 시 유실되고, 너무 보수적으로 커밋하면 재처리가 늘어납니다. 워커별 완료 오프셋을 추적해 "연속으로 완료된 최저 오프셋"까지만 커밋하세요.
4. 원인 ③: 병렬성 부족 — 컨슈머 수 ≠ 파티션 수
Kafka의 병렬성 단위는 파티션입니다. 한 파티션은 같은 컨슈머 그룹 내에서 단 하나의 컨슈머만 읽을 수 있습니다. 이 제약에서 두 가지 실수가 나옵니다.
증상 A: 컨슈머 < 파티션 (일부 파티션 적체)
컨슈머 한 개가 여러 파티션을 떠안습니다. 이 컨슈머가 처리 한계에 도달하면, 자신이 맡은 파티션들의 랙이 함께 증가합니다.
증상 B: 컨슈머 > 파티션 (유휴 컨슈머)
파티션이 6개인데 컨슈머를 10개 띄우면, 4개는 아무 파티션도 할당받지 못하고 논다. --describe에서 CONSUMER-ID가 붙지 않은 idle 컨슈머로 보이거나, 스케일아웃했는데 처리량이 그대로입니다.
황금 규칙
유효 최대 컨슈머 수 = 파티션 수. 그 이상은 처리량을 늘리지 못하고 자원만 낭비합니다.
| 파티션 수 | 컨슈머 수 | 결과 |
|---|---|---|
| 12 | 4 | 컨슈머당 3파티션. 병렬성 4배 여력 남음 |
| 12 | 12 | 1:1, 최대 병렬성 |
| 12 | 16 | 12개만 일하고 4개는 유휴(낭비) |
진단과 처방
# 토픽 파티션 수 확인
kafka-topics.sh --bootstrap-server broker1:9092 --describe --topic payments
# → PartitionCount: 12 (이 값이 병렬성 상한)- 처리량이 부족하고 컨슈머 < 파티션이면 → 컨슈머를 늘린다(파티션 수까지).
- 이미 컨슈머 = 파티션인데도 부족하면 → 파티션을 늘린다(
--alter --partitions). 단, 키 기반 파티셔닝을 쓰면 파티션 증설 시 키→파티션 매핑이 바뀌어 순서 보장이 깨질 수 있으니 주의.
# 파티션 증설 (줄이는 것은 불가)
kafka-topics.sh --bootstrap-server broker1:9092 \
--alter --topic payments --partitions 245. 원인 ④: 핫/스큐 파티션 (잘못된 키 분포)
--describe에서 한 파티션만 랙이 폭증하고 나머지는 평탄하다면, 거의 확실히 핫 파티션입니다. 파티션을 24개로 늘려도, 트래픽의 80%가 한 키로 몰리면 그 키가 매핑되는 파티션 하나만 불타고 나머지 23개는 한가합니다.
원인: 키 → 파티션 매핑
기본 파티셔너는 partition = hash(key) % partitionCount로 메시지를 분배합니다. 키가 고르게 분포하지 않으면 특정 파티션에 메시지가 쏠립니다. 대표적인 사례:
tenant_id를 키로 쓰는데 한 대형 고객이 전체 트래픽의 절반.null키 또는"default"같은 상수 키가 섞여 한 파티션으로 직행.- 시간 버킷(
yyyyMMddHH)을 키로 써서 "현재 시각" 파티션만 항상 핫.
진단
--describe 출력에서 파티션별 LAG의 분산을 봅니다. 한 파티션의 LAG이 나머지 합보다 크면 스큐입니다. 더 정밀하게는 파티션별 메시지 유입률을 비교합니다.
# 파티션별 메시지 수(오프셋) 비교 — 특정 파티션만 빠르게 증가하는지
kafka-run-class.sh kafka.tools.GetOffsetShell \
--broker-list broker1:9092 --topic payments --time -1
# payments:0:1048590
# payments:1:9982110 ← 이 파티션만 압도적으로 많다
# payments:2:1048512처방
- 키 설계 변경: 카디널리티가 높고 고르게 분포하는 키를 선택합니다.
tenant_id대신tenant_id + ":" + record_id같은 복합 키로 분산을 높입니다(단, 같은 tenant의 순서 보장이 필요 없을 때). - 커스텀 파티셔너: 핫 키를 감지해 여러 파티션으로 흩뿌리는 파티셔너를 구현합니다(예: 핫 키만 라운드로빈).
- 순서 보장이 필요 없다면 키 제거: 키를
null로 두면 라운드로빈(또는 sticky)으로 고르게 분배됩니다.
// 핫 키만 여러 파티션으로 흩뿌리는 커스텀 파티셔너 개요
public int partition(String topic, Object key, byte[] keyBytes,
Object value, byte[] valueBytes, Cluster cluster) {
int numPartitions = cluster.partitionsForTopic(topic).size();
if (isHotKey(key)) {
// 핫 키는 키 해시 대신 라운드로빈으로 분산
return Math.floorMod(counter.getAndIncrement(), numPartitions);
}
return Math.floorMod(Utils.murmur2(keyBytes), numPartitions);
}핫 키 분산은 순서 보장과 트레이드오프입니다. 같은 키의 순서가 중요한 도메인(예: 한 계좌의 거래 이벤트)이라면 키를 흩뿌리면 안 됩니다. 이때는 파티션을 더 늘리고 핫 키 자체를 분해(예: 대형 고객을 별도 토픽으로)하는 쪽을 검토하세요.
6. 원인 ⑤: GC 정지 / 자원 부족 컨슈머
컨슈머 JVM의 Stop-the-World GC가 길어지면, 그 시간 동안 poll()도 하트비트도 멈춥니다. 결과는 원인 2와 같습니다 — poll 타임아웃 → 추방 → 리밸런스 → 랙 톱니파. 다만 트리거가 코드 처리 시간이 아니라 GC 정지라는 점이 다릅니다.
증상
- 랙이 주기적으로 튀고, 그 시점이 GC 로그의 긴 정지와 일치.
- 컨슈머 메모리 사용률이 한계에 가깝고,
max.poll.records가 크다(한 번에 받은 레코드가 힙을 압박). - 컨테이너 환경이라면 CPU throttling 또는 메모리 limit 근접.
진단
GC 로그를 켜고 정지 시간을 봅니다.
# 컨슈머 JVM에 GC 로깅 추가
-Xlog:gc*:file=/var/log/kafka/consumer-gc.log:time,uptime:filecount=5,filesize=10M
# 긴 STW(예: 1초 이상) 발생 시각과 랙 스파이크 시각을 대조처방
- 힙을 압박하는 배치 크기 줄이기:
max.poll.records와fetch.max.bytes를 낮춰 한 번에 메모리에 올리는 양을 줄입니다. - 힙 증설 또는 GC 튜닝: G1GC라면
-XX:MaxGCPauseMillis를 낮춰 정지 목표를 줄입니다. 처리량이 매우 크면 ZGC/Shenandoah 같은 저지연 GC를 검토합니다. - 컨테이너 자원 보정: CPU limit이 throttling을 유발하면 limit을 올리거나 request를 보장합니다. 메모리 limit은 힙 + 다이렉트 버퍼 + 네이티브를 모두 감안합니다.
- 레코드를 빨리 버리기: 처리 후 참조를 끊어 GC가 빨리 회수하게 합니다(불필요한 누적 컬렉션 주의).
7. 원인 ⑥: 브로커 측 병목
컨슈머를 아무리 튜닝해도, 브로커가 데이터를 빨리 내주지 못하면 랙은 줄지 않습니다. 컨슈머 CPU·다운스트림 모두 한가한데 처리량이 낮다면 브로커를 의심하세요.
증상과 진단
| 병목 | 증상 | 확인 지표 |
|---|---|---|
| Under-replicated 파티션 | ISR 축소, 일부 파티션 fetch 지연 | UnderReplicatedPartitions > 0 |
| 느린 fetch | 컨슈머 fetch latency 상승 | FetchConsumerTotalTimeMs p99 |
| 네트워크 포화 | 브로커 NIC 대역폭 한계 | BytesOutPerSec ≈ NIC 한계 |
| 디스크 I/O 한계 | 콜드 데이터 읽기 시 디스크 대기 | iostat %util ≈ 100 |
| 큰 메시지 | 큰 레코드가 fetch를 키워 지연 | 평균 record size↑ |
# under-replicated 파티션 즉시 확인
kafka-topics.sh --bootstrap-server broker1:9092 --describe --under-replicated-partitions
# 브로커 fetch/네트워크 지표는 JMX로 (예시 MBean)
# kafka.network:type=RequestMetrics,name=TotalTimeMs,request=FetchConsumer
# kafka.server:type=BrokerTopicMetrics,name=BytesOutPerSec처방
- Under-replicated 해소: 느린/장애 브로커를 복구하고, 필요 시 파티션 리더를 재분배(
kafka-leader-election.sh)합니다. - fetch 효율 조정: 컨슈머의
fetch.min.bytes를 키우면 브로커가 작은 응답을 모아 보내 요청 수를 줄여 처리량이 오릅니다(대신 약간의 지연 증가,fetch.max.wait.ms와 함께 튜닝). - 큰 메시지:
max.partition.fetch.bytes를 메시지 크기에 맞게 올려야 컨슈머가 큰 레코드를 한 번에 받습니다. 너무 작으면 한 레코드도 못 받아 정체될 수 있습니다. 단, 너무 키우면 메모리 압박(원인 5)이 생깁니다. - 네트워크/디스크: NIC·디스크가 한계면 브로커 증설 또는 파티션 재배치로 부하를 분산합니다.
8. 원인 ⑦: 커밋/오프셋 문제
랙 수치 자체가 거짓말을 하는 경우입니다. 실제로는 처리하고 있는데 오프셋을 안 올리거나, 자꾸 과거로 되감겨 같은 데이터를 무한 재처리하는 상황입니다.
증상 A: 커밋을 안 한다
enable.auto.commit=false인데 코드에서 commitSync()/commitAsync()를 호출하지 않으면, 처리는 되지만 current-offset이 제자리입니다. --describe의 LAG은 계속 커지지만 다운스트림에는 데이터가 정상 적재됩니다. 재기동하면 마지막 커밋 지점부터 대량 재처리가 일어납니다.
증상 B: 자꾸 되감긴다 (offset reset)
auto.offset.reset=earliest 상태에서 커밋된 오프셋이 사라지면(리텐션 만료로 __consumer_offsets에서 제거되거나, 그룹 ID가 매번 바뀌거나) 컨슈머가 토픽 맨 처음부터 다시 읽습니다. 랙이 갑자기 토픽 전체 크기로 점프합니다.
진단
# 커밋 지점이 멈춰 있는지 — CURRENT-OFFSET이 시간이 지나도 그대로면 커밋 문제
kafka-consumer-groups.sh --bootstrap-server broker1:9092 \
--describe --group payment-consumer
# 오프셋이 리셋됐는지 — 그룹 상태/리셋 로그 확인
# 컨슈머 로그: "Resetting offset for partition ... to offset 0" 가 보이면 reset 발생처방
- 커밋 보장: 배치 처리 성공 후 반드시 커밋합니다. 비동기 처리라면 원인 2의 "완료된 최저 오프셋까지 커밋" 패턴을 적용합니다.
- 고정 그룹 ID: 컨슈머 그룹 ID를 환경/배포마다 바꾸지 마세요. 우연히 매번 새 그룹이 되면
earliest로 전체 재처리가 일어납니다. - 오프셋 리텐션 확인:
offsets.retention.minutes(브로커, 기본 7일)보다 오래 컨슈머가 멈춰 있으면 커밋이 만료됩니다. 장기 중단이 예상되면 리텐션을 늘리거나, 의도적으로 특정 오프셋으로 리셋합니다.
# 의도적으로 특정 시각 이후로 오프셋 리셋 (드라이런 후 --execute)
kafka-consumer-groups.sh --bootstrap-server broker1:9092 \
--group payment-consumer --topic payments \
--reset-offsets --to-datetime 2026-07-02T03:00:00.000 --dry-run9. 핵심 설정 한눈에 보기
랙 트러블슈팅에서 가장 자주 만지는 컨슈머 설정입니다. 하나를 키우면 다른 하나가 깎이는 트레이드오프를 기억하세요.
| 설정 | 기본값 | 역할 | 키우면 | 줄이면 |
|---|---|---|---|---|
max.poll.records | 500 | poll 한 번에 가져올 최대 레코드 수 | 배치 효율↑, 처리 시간↑(추방 위험·GC 압박) | poll 오버헤드↑, 추방 위험↓ |
max.poll.interval.ms | 300000(5분) | poll 사이 허용 최대 간격 | 느린 배치 허용 | 죽은 컨슈머 빠른 감지 |
fetch.min.bytes | 1 | 응답을 보내기 위한 최소 누적 바이트 | 처리량↑(요청 수↓), 지연↑ | 지연↓, 요청 수↑ |
fetch.max.bytes | 52428800(50MB) | 한 fetch 응답의 최대 바이트 | 한 번에 많이 수령(메모리↑) | 메모리↓, 요청 수↑ |
max.partition.fetch.bytes | 1048576(1MB) | 파티션당 fetch 최대 바이트 | 큰 메시지 수용 | 메모리↓(큰 메시지 못 받을 위험) |
fetch.max.wait.ms | 500 | fetch.min.bytes 미달 시 최대 대기 | 배치 효율↑ | 지연↓ |
일반적 출발점: 처리량이 부족하면
fetch.min.bytes를 올려 fetch 효율을 높이고, 추방이 의심되면max.poll.records를 낮춰 배치 처리 시간을 줄입니다. 큰 메시지로 정체되면max.partition.fetch.bytes를 메시지 최대 크기 이상으로 올립니다.
10. 증상 → 원인 의사결정 플로우
새벽 3시에 빠르게 따라갈 수 있는 분기입니다. --describe로 시작하세요.
마치며 — 핵심 요약
- 랙 트러블슈팅은 항상
kafka-consumer-groups.sh --describe로 파티션 단위 진단부터. 전체가 고르게 미는지, 한 파티션만 미는지가 첫 갈림길입니다. - 전체가 고르게 증가하면 처리량 문제 — 느린 다운스트림(①), 병렬성 부족(③), 브로커 병목(⑥)을 차례로 의심하세요.
- 한 파티션만 폭증하면 핫/스큐 파티션(④)이거나 그 파티션 담당 컨슈머의 죽음(⑤·⑦)입니다.
- 톱니파 + 리밸런스 로그는 poll 블로킹(②) 또는 GC(⑤)의 신호.
max.poll.records를 낮추고 처리를 poll 스레드 밖으로 빼는 것이 정석입니다. - 모든 설정은 트레이드오프입니다.
max.poll.records·fetch.*를 키우면 처리량은 오르지만 메모리·지연·추방 위험이 함께 움직입니다. 한 번에 하나씩 바꾸고 랙 그래프로 검증하세요. - 유효 병렬성의 상한은 파티션 수입니다. 컨슈머를 그 이상 늘려도 소용없고, 진짜 처리량을 늘리려면 파티션과 키 설계를 함께 봐야 합니다.
- 다음 편(6편) **「Rebalance Storm」**에서는 ②·⑤가 어떻게 클러스터 전체의 리밸런스 폭풍으로 번지는지, 그리고 그것을 끊는 법을 다룹니다.
참고 자료
- Apache Kafka — Consumer Configs: https://kafka.apache.org/documentation/#consumerconfigs
- Apache Kafka — Consumer Group Tooling: https://kafka.apache.org/documentation/#basic_ops_consumer_group
- Apache Kafka — Design & Replication: https://kafka.apache.org/documentation/#design
- 「Kafka 운영 트러블슈팅 ①」 Consumer Lag 측정과 모니터링
- 「Kafka 운영 트러블슈팅 ⑥」 Rebalance Storm 진단과 차단
— Data Dynamics 엔지니어링 팀