이 글에서 얻는 것
- Consumer Lag이 무엇인지(어떤 오프셋의 차이인지) 정확히 정의하고, 원인을 분류할 수 있습니다.
- lag이 늘 때 “스케일 아웃이 정답인지, 처리 최적화가 정답인지, 실패 메시지 분리가 정답인지” 판단 기준이 생깁니다.
- 리밸런스가 왜 발생하는지(session timeout, max.poll.interval)와 운영에서 줄이는 방법을 이해합니다.
- 커밋 전략이 중복/유실/지연에 미치는 영향을 감각적으로 연결할 수 있습니다.
0) Lag의 정의부터 정확히
파티션 기준으로 lag은 보통:
log_end_offset(브로커에 쌓인 최신 오프셋)
vscommitted_offset(컨슈머 그룹이 “여기까지 처리했다”고 커밋한 오프셋)
의 차이로 봅니다.
즉, lag이 커진다는 건 “브로커에는 쌓이는데, 우리는 처리/커밋이 따라가지 못한다”는 뜻입니다.
1) lag이 늘어나는 대표 원인 5가지
1-1) 생산 속도 > 소비 처리량
가장 단순한 케이스입니다.
- 파티션 수가 부족하면 컨슈머를 늘려도 효과가 없습니다(파티션당 1 컨슈머).
- 파티션을 늘리면 병렬성이 올라가지만, 키/정렬 요구와 충돌할 수 있습니다.
1-2) 특정 메시지가 너무 느리다(“독” 메시지)
한 메시지가 5초씩 걸리면 해당 파티션 전체가 막힙니다.
대응:
- 실패/지연 메시지는 retry 토픽/DLQ로 분리
- “느린 외부 API 호출”을 분리(벌크헤드/타임아웃/재시도)
1-3) 컨슈머가 poll()을 제때 못 한다
컨슈머는 일정 주기로 poll()을 호출해야 하트비트를 보내고 그룹에서 살아남습니다.
처리가 너무 오래 걸려 max.poll.interval.ms를 넘으면 리밸런스가 발생할 수 있습니다.
1-4) 리밸런스가 잦다
리밸런스는 파티션 할당이 바뀌는 동안 처리가 멈추거나 지연이 튈 수 있습니다.
원인:
- 컨슈머의 잦은 재시작/스케일링
- 네트워크 이슈로 세션 타임아웃
max.poll.interval.ms초과
1-5) 커밋/DB 병목
처리는 끝났는데 커밋/DB 업데이트가 병목이면 lag이 “커밋 기준”으로 계속 남을 수 있습니다.
2) 대응 전략: 무엇부터 해야 하나
2-1) 먼저 “독 메시지/실패”를 분리
한 파티션을 막는 메시지가 있으면 스케일 아웃으로도 해결이 안 됩니다. retry/DLQ로 분리하는 것이 1순위인 경우가 많습니다.
2-2) 처리 최적화(배치/병렬/IO 줄이기)
- DB writes는 batch upsert로 줄일 수 있는지
- 외부 호출은 타임아웃/재시도/서킷브레이커로 고립하는지
- 한 메시지 처리에 불필요한 N+1/조회가 없는지
2-3) 스케일 아웃(파티션/컨슈머)
처리량이 충분히 최적화됐는데도 생산량이 더 많다면, 파티션/컨슈머 확장이 필요합니다. 단, 키 기반 정렬 요구가 있으면 “핫 키”가 병목이 될 수 있으니 키 설계를 함께 봐야 합니다.
3) 리밸런스 이해하기: session timeout vs max poll interval
session.timeout.ms / heartbeat.interval.ms
브로커(그룹 코디네이터)는 하트비트를 못 받으면 컨슈머를 죽었다고 판단하고 리밸런스를 합니다.
max.poll.interval.ms
poll() 호출 간격이 너무 길면 “처리가 멈춘 컨슈머”로 판단하고 리밸런스를 합니다.
실무 감각:
- “처리가 오래 걸리는 로직”이면
max.poll.interval.ms조정이 필요할 수 있지만, - 근본적으로는 “한 레코드 처리 시간을 줄이거나, 느린 레코드를 분리”하는 게 더 안전합니다.
추가로:
- Cooperative rebalancing(점진적 리밸런스)을 사용하면 리밸런스 충격을 줄일 수 있습니다(환경/클라이언트 지원 여부 확인).
4) 커밋 전략: 지연/중복/유실을 결정한다
- 자동 커밋: 단순하지만 “처리 전 커밋”이 섞일 수 있어 중복/유실을 통제하기 어렵습니다.
- 수동 커밋: 처리 완료 후 커밋(보통 기본). 다만 중복은 생길 수 있으니 멱등 처리가 필요합니다.
운영에서 흔한 선택:
- 처리 후 커밋 + 멱등 처리
- 커밋은 레코드마다가 아니라 “배치 단위”로 하여 비용을 줄이기(너무 커지면 재처리 범위가 커짐)
5) 모니터링: 어떤 지표를 봐야 하나
최소:
- partition별
lag(절대값 + 증가율) records-consumed-rate/records-lag-max- 리밸런스 횟수/시간
- 처리 시간 분포(p95/p99), 실패율(DLQ 유입)
알람은 보통:
- lag 절대값이 일정 기준을 넘거나,
- lag 증가율이 일정 시간 이상 지속될 때
두 조건을 함께 봐야 노이즈가 줄어듭니다.
연습(추천)
- 일부러 처리 시간을 늘려
max.poll.interval.ms초과로 리밸런스를 재현해보기 - 실패 메시지를 retry 토픽으로 분리했을 때 lag/지연이 어떻게 개선되는지 비교해보기
- 파티션 수/컨슈머 수를 바꿔가며 lag이 어디서부터 줄어들지(또는 안 줄어들지) 관찰해보기
💬 댓글