Kafka 消费积压(Consumer Lag)怎么处理?
更新时间:2026-09-18。问题驱动短答页。积压 = 生产速度持续 > 消费速度。先判断「为什么慢」,再决定扩容还是提速。
一句话回答
先用 kafka-consumer-groups.sh --describe 看 LAG、当前 offset 和 LOG-END-OFFSET,区分是消费者挂了、突发流量还是单条处理慢;应急扩消费者(不超过分区数)/扩分区来增加并行度,根治要提高单条吞吐(批量、异步、优化下游)、处理毒消息,并监控 rebalance。
第一步:量化积压
bash
kafka-consumer-groups.sh --bootstrap-server kafka:9092 \
--group order-group --describe
# TOPIC PARTITION CURRENT-OFFSET LOG-END-OFFSET LAG CONSUMER-ID
# LAG = LOG-END-OFFSET - CURRENT-OFFSET,即落后多少条判断思路:
- LAG 持续增长:消费速度 < 生产速度,扩容或提速。
- LAG 突增后稳定:突发流量(大促/补数),看能否追平。
- CURRENT-OFFSET 不动:消费者挂了或卡在某条「毒消息」反复重试。
- 个别分区 LAG 高:分区数据/处理不均(热点 key)。
处理手段
| 手段 | 前提/做法 | 说明 |
|---|---|---|
| 扩消费者实例 | 实例数 ≤ 分区数 | 超过分区数的实例会空闲,这是最常见误区 |
| 扩分区 | 给 topic 增加 partition | 提升并行上限,但新分区只对新数据生效,且影响按 key 顺序 |
| 批量拉取/处理 | 调大 max.poll.records,批量写库 | 减少往返,吞吐立竿见影 |
| 异步/多线程处理 | poll 与处理解耦 | 注意 offset 提交要在处理完成后,否则会丢/重复 |
| 优化下游 | 消费逻辑里的 DB/接口才是瓶颈 | 写库批量化、加缓存,下游慢时配合熔断 |
| 处理毒消息 | 坏消息导致无限重试卡死分区 | 重试有限次后进死信队列(DLQ),不阻塞主流程 |
| 限生产端 | 消费短期无法追上 | 上游限流/降级,防止磁盘保留期内数据被删 |
容易忽略的两个点
- 分区数是并行度天花板:一个分区同一消费组内只能被一个消费者消费。10 个分区开 20 个实例,一半空转;要更高并行必须先扩分区。
- rebalance 期间停消费:消费者加入/退出(如心跳超时、处理超
max.poll.interval.ms)触发 rebalance,期间短暂不消费会表现为周期性 LAG 抖动。长任务要调大 session/max-poll 间隔或用 CooperativeSticky。
应急 vs 根治
- 应急:临时扩消费者到分区上限、跳过/隔离卡住的坏消息、必要时临时降低生产速率。
- 根治:按峰值容量规划分区数和消费者数、消费逻辑批量+异步、下游做容量匹配、把 LAG 和 rebalance 纳入告警;积压过多时还要确认没超过日志保留时间导致「追不回」。
坑
- 扩消费者却没扩分区:实例空转,LAG 不动。
- 用多线程处理但提前提交 offset:处理失败时消息既没成功又被标记消费,造成丢失;应处理完再提交(at-least-once 配合幂等)。
- 只盯 broker 不盯下游:消费者九成的「慢」是卡在它写的 DB/调的接口上。
- 忽略消息顺序:扩分区后按 key 的局部有序性可能变化,顺序敏感业务要保证同 key 同分区。
Kafka 与 RabbitMQ 的架构差异见 Kafka 与 RabbitMQ 选型;重复投递的处理见 消息重复消费怎么解决;下游变慢的防护见 服务熔断、降级与隔离。
总结
处理 Kafka 积压先用 kafka-consumer-groups 看 LAG 与 LOG-END-OFFSET 分清是消费者宕机、突发流量还是消费慢,记住分区数是并行度上限——扩消费者实例不能超过分区数、要更高并行先扩分区;提速靠加大 max.poll.records 批量处理、poll 与处理异步解耦、批量写库和优化真正的瓶颈下游,坏消息用有限重试+死信队列避免卡死,同时用合理的 session/max-poll 间隔和 CooperativeSticky 减少 rebalance 停顿,offset 在处理成功后提交以配合幂等不丢不重。