从「什么是积压」到「为什么会积压」,再到「怎么止血、怎么根治、怎么预防」——一套能直接上手的方法论。
MQ(Message Queue,消息队列) 用来在系统之间异步传递消息。正常情况下,生产者发得快、消费者也消费得快,队列里基本不囤货。 所谓 消息积压(Backlog / Accumulation),指的是:生产者发送消息的速率持续大于消费者处理消息的速率,导致消息在 Broker(消息中间件)里越堆越多、长时间得不到消费。
| 指标 | 含义 | 怎么看 |
|---|---|---|
| 堆积量 / Lag | 队列里没被消费的消息条数(Kafka 叫 consumer lag) | lag 持续 > 0 且在增长 = 正在积压;lag 回落 = 在恢复 |
| 消费延迟 | 一条消息从生产到被消费经历的时长 | 延迟从毫秒级涨到秒/分钟级,就是积压信号 |
| 生产 TPS vs 消费 TPS | 单位时间生产条数 vs 消费条数 | 生产 TPS 长期 > 消费 TPS,必然积压 |
积压的本质只有一句话:消费跟不上生产。但具体「为什么跟不上」,可以归纳成六大类。先定位属于哪一类,再对症下手。
六类原因里,真实生产环境中 80% 的积压由下面三件事贡献。优先怀疑它们,能省掉大量排查时间。
消费方法里有一条没走索引的 SQL、一次同步调用第三方接口超时、或一个串行循环。单条消息耗时从 5ms 变成 500ms,吞吐直接掉 100 倍。这是积压最普遍、也最容易被忽视的原因。
日常 1 个消费者刚好够,流量涨了 5 倍却还是 1 个实例、单线程消费。没有水平扩展 + 弹性伸缩,消费能力是硬上限,迟早被压垮。
大促 / 秒杀 / 批量任务一上来就是平时几十倍的瞬时流量,队列瞬间灌爆,而消费端没有任何限流、降级、临时扩容的预案,只能眼睁睁看着 lag 飙升。
一句话总结:积压 = 消费慢 × 没扩容 × 突发流量无预案。三件事同时占一个,就容易出事;三个都占,必出事。
解决分两层:第一层「紧急止血」是救火,先让 lag 不再涨、开始回落;第二层「根治优化」是治本,避免下次再积压。
遇到积压不要慌,按下面五步走,每一步都有明确产出。这是一套可以直接抄作业的排查与处理流程。
看 consumer lag、消费延迟、生产/消费 TPS 曲线。设置告警阈值(如 lag > 1 万且持续增长自动报警),别等用户投诉才发现。
看消费单条耗时(是不是慢 SQL / 外部调用);看消费 TPS(是不是实例不够);看分区数(是不是并行度受限);看错误日志(是不是重试风暴);看 Broker 指标(是不是磁盘 / 网络)。先量再猜。
按第 4 节「止血」操作:临时扩容消费者 + 多线程消费 + 提分区数;非核心消息降级跳过;必要时限流生产者。目标是先止住上涨、开始下降。
优化消费逻辑(异步 / 批处理 / 去慢 SQL);消费端接弹性伸缩(按 lag 自动扩缩);核心 / 非核心消息隔离;接入限流削峰;保证幂等。让消费能力长期 > 峰值生产。
做容量规划与压测,知道系统上限在哪;准备大促 / 秒杀的扩容与降级预案;把「积压应急手册」固化成 runbook,定期演练。
最好的处理是「让它不发生」。把下面几件事做在前面,积压基本不会成为故障。
| 预防手段 | 具体做法 | 解决哪类问题 |
|---|---|---|
| 实时监控 lag | Kafka exporter / RocketMQ dashboard 接 Prometheus + Grafana,盯 consumer lag | 发现慢、定位快 |
| 分级告警 | lag 超阈值(如 1 万)warning,超更大值(如 10 万)page 值班 | 早发现早处理 |
| 弹性伸缩 | 消费端按 lag 自动扩缩容(K8s HPA / 自定义指标) | 消费者不足 |
| 容量规划 + 压测 | 提前测出单消费者吞吐上限,按比例预留实例与分区 | 突发流量 |
| 限流削峰 | 生产端令牌桶 / 漏桶,洪峰平滑后入队;非核心消息走降级通道 | 突发流量 |
| 消息分级隔离 | 核心 / 非核心分 topic、分队列,互不影响 | 重试风暴 / 局部堵塞 |
| 幂等 + 死信队列 | 重复消费安全;失败消息进 DLQ 不阻塞主链路 | 消费失败 |