什么是消息积压?
在探讨消息积压之前,首先理解消息队列的基本工作流程。其核心链路非常直观:
生产者发送消息 → 队列暂存消息 → 消费者消费消息
这类似于一个高效的快递系统:
- 生产者相当于快递员,持续将包裹送达驿站
- 队列如同驿站仓库,临时存储包裹
- 消费者则是取件人,从仓库提取包裹
在正常状态下,这条链路运行顺畅:生产者发送的消息量,消费者能够及时处理,队列中不会出现消息堆积。

然而,一旦出现供需失衡,生产者发送消息的速度持续大于消费者处理消息的速度,未被消费的消息会在队列中不断堆积,这种状态就称为消息队列积压。
积压若不及时处理,影响会从队列异常扩散到整个业务系统,最直接的问题就是消息延迟加剧:新入队消息处理时间越来越长,一直卡在队列之中,最终因过了业务实效性而失去价值。更严重的是,若积压太久、消息积压太多,还会触发中间件的消息回收策略,直接导致未处理的消息丢失,引发业务数据不一致等问题。
因此,面对积压时,核心目标是在短时间内降低队列堆积量,优先保障核心业务不受影响。
优先救火:如何快速解决积压
基于这一核心目标,优先选择操作成本低、见效快的应急策略,从提升消费能力、聚焦核心处理到分流减压三个维度逐步推进。
1. 临时扩容消费者
临时扩容消费者是快速提升消费能力最直接有效的手段:通过快速扩容消费者集群规模,借助消息队列原生的负载均衡机制,达到更多节点并行处理消息的目的,最终直接提升整体消费吞吐量。
不过,不同消息队列的负载均衡逻辑各有差异,具体表现为:Kafka 会触发分区再平衡,将积压的消息分区均匀分配给新增节点;RabbitMQ 则通过队列竞争模式,让多节点同时拉取队列消息。
这两种方式最终都能实现分散压力、提升消费效率的效果,但仅适用于无分区或分片限制的场景。

如果遇到部分队列存在分区或分片限制的场景,如 Kafka,情况就有所不同。此时消费者数量不可超过分区数,否则多余节点会处于空闲状态,无法发挥作用。
针对这种特殊场景,常规扩容无法解决问题,需通过临时增加分区来突破限制。像 RocketMQ 等中间件就支持动态扩分区功能,可以为扩容的消费者提供足够的处理单元,确保新增节点能真正参与到消息消费中,避免资源浪费。
2. 降级非核心逻辑,优先处理关键消息
扩容消费者往往受限于资源条件,例如临时申请机器需要审批、部分环境无权限快速扩容。此时需要另一种更灵活的应急思路:降级非核心逻辑、优先处理关键消息。核心思路是聚焦核心、简化流程,具体可以从两方面着手。
一方面是筛选消息优先级。先明确哪些是必须立刻处理的核心消息,比如订单支付结果、交易状态变更等直接影响用户体验和业务正确性的消息;而像营销推送、数据统计这类非核心消息,可以暂时让路。
处理时让消费者直接跳过非核心消息,如收到后直接标记为已处理,把资源集中在核心消息上,避免它们被非核心消息挤占而延迟。

另一方面是简化核心消息的处理流程。平时处理消息可能包含完整的校验、日志记录、多系统同步等步骤,积压时可以临时砍掉非必要环节。比如暂时跳过非关键数据的校验、简化日志输出、把同步调用改成异步回调等。这样能缩短单条消息的处理时间,让消费者能更快地处理更多核心消息,等积压缓解后再恢复完整流程。
通过这种抓大放小的方式,既能保证核心业务不受影响,又能快速降低队列压力,为后续彻底解决问题争取时间。
3. 拆分队列减轻压力
无论是临时扩容还是降级非核心逻辑,更多是在提升现有队列消费效率上发力。但如果遇到海量积压消息阻塞新消息的场景,仅靠前两种策略就难以兼顾。
此时,通过拆分队列实现新旧消息分流,成为保障核心业务连续性的关键思路。结合具体场景理解:
假设某个公司做活动,大量消息在几分钟内涌入消息队列,直接造成几亿条数据积压;公司没有钱扩容,按现有能力要处理这些消息需要1小时,但同时还有其它业务的消息需要处理,这类新消息的正常处理速率约为 1000 条/秒。此时若让新消息继续进入原队列,会被前面的海量积压消息堵住,导致日常业务也陷入停滞,形成旧积压未清、新阻塞又至的恶性循环。
这时候如果业务允许,其实可以选择保新,即新消息导入到新的消息队列,这样新消息可以得到及时处理,而旧消息,就等1小时之后慢慢消耗掉即可。

如果老队列积压的太厉害了,也可以用脚本批量拉取老队列消息并转发至临时队列,由专项消费者集中处理,避免老队列持续阻塞。
根源排查:定位积压原因
通过优先救火,紧急缓解了积压,但必须找到问题的根本原因。只有把源头问题解决了,才能避免重复救火。以下是常见的几个排查方向。
1. 消费者问题
先看消费者这边,很多时候积压都是因为消费者消费速度不足。具体可分为两大场景:要么是消费者处理得慢,要么是消费者直接不处理。
消费者处理得慢可能是处理单条消息的速度太慢,可以通过监控看看单条消息要处理多久,如果超过 200 毫秒,那大概率有问题。也可能是处理逻辑太冗余,里面有好几轮同步的数据库查询,或者调用了很多没必要的外部接口,把时间都耗在了等待上;要么就是消费者的资源不够用了,CPU、内存或者 IO 被占满,机器跑不动自然处理得慢。

消费者直接不处理这种情况就更极端了,服务突然宕机、网络断了连不上队列,或者消费者的线程池被耗尽都有可能造成消费者直接罢工。这种情况不用瞎猜,看看消费者的日志就能发现线索,比如有没有 ERROR 级别的异常信息?再结合监控告警,消费QPS是不是一下变成零?这些都能帮我们快速定位消费中断的问题。

2. 生产者问题
再说说生产者那边,有时候积压是因为消息突然变多了。比如遇到秒杀、促销这类活动,生产者发送消息的量会突然暴涨,原本平时每秒只发 1000 条,活动时一下子冲到每秒 10000 条,这时候消费者根本处理不过来,消息自然就堆起来了,只要看看生产者发送 QPS 的曲线,就能清楚是不是流量激增导致的。
另外,还有可能是消息重复发送了,比如生产者的重试机制出了问题,没正确处理队列的 ACK 确认信号,导致同一条消息反复投递;再者也可能是业务逻辑有 bug,比如某个循环没控制好,一直在发送同一条消息,这时候检查一下消息的唯一 ID,比如 msgId,看看有没有大量重复的就能确认。
3. 队列本身配置
最后还需要重点审视队列自身的核心配置是否适配业务并发需求,这一点在 Kafka、RocketMQ 等主流分布式消息队列中尤为关键。这类队列的分区或分片是实现并行消费的核心载体,其底层机制决定了单个分区同一时间只能被一个消费者实例占用消费,因此分区总数直接等同于消费端能达到的最大并行处理能力上限。

若分区数配置不合理,会直接造成消费资源浪费与处理能力瓶颈。例如某 Kafka 主题仅配置 3 个分区,就算为应对积压临时扩容至 10 台消费者机器,但由于分区数量的限制,最终也只有 3 个消费实例能分配到分区并实际处理消息,剩余 7 台机器会处于空闲等待状态,无法参与消费任务,既浪费了服务器资源,也无法有效提升消息处理速度,难以缓解积压问题。
一旦确定了积压的根源,便能精准施策,进行有效的优化。但视野不应局限于眼前的问题,还需对消息队列的生产-传输-消费全链路进行全面审视与评估,构建一套系统化的防积压机制。这不仅能够解决当前的挑战,还能预防未来可能出现的问题,确保流程更加顺畅和高效。
长期优化:建立防积压机制
想要从根源降低消息积压风险,可以通过技术优化与流程规范双管齐下,核心措施可分为以下四类:

1. 优化消费者性能,提升处理效率
消费者是消息处理的核心环节,其处理效率直接决定队列是否会积压。通过优化消费者的处理逻辑、资源分配,能从消化端提升整体吞吐量,具体可从三个方向发力。
方向一:并行化处理独立操作,缩短单条消息耗时
单条消息的处理耗时是影响消费效率的基础单位。若能压缩单条耗时,整体吞吐量自然会提升。如果一条消息的处理逻辑里包含多个独立操作,没必要按顺序一个个等它们完成,完全可以让这些操作并行跑,这样能大幅缩短单条消息的处理时间。
比如处理一条订单消息时,原本需依次执行三个操作,每个操作耗时 200ms,全程共需 600ms:订单数据写入数据库(200ms)→ 调用物流接口(200ms)→ 通知服务发送短信(200ms)
但其实这三个操作互相不依赖,写订单库不用等物流接口,发通知也不用等数据库写完,那就可以启动三个线程:一个线程去写数据库、另一个线程调用物流接口、第三个线程发通知。三个操作一起跑,最快 200ms 就能完成所有任务,单条消息的处理效率直接翻 3 倍。

方向二:批量处理消息,减少交互损耗
在并行化优化单条消息耗时后,还需解决交互瓶颈。消费端频繁的网络交互、磁盘 IO 会浪费大量时间在等待上,通过批量拉取和批量处理能有效减少这类损耗,让消费者把更多时间用在核心业务处理上。
首先开启消费者的批量拉取功能,就像 Kafka 里的 fetch.max.records 参数,设置合适的值后,消费者一次能从队列里拉取多条消息,而不是一条一条地取,这样能减少和消息队列之间的网络交互次数。

拿到批量消息后再进行批量处理,像用 MyBatis 的批量插入功能,把一批数据一次性提交给数据库,比起单条插入能大幅减少磁盘 IO 的次数。

需要注意的是,批量大小需结合实际场景调整:太大可能占用过多内存,太小则无法体现批量优势,一般建议根据消息体积、服务器配置测试出最优值。
方向三:资源隔离,保障核心业务优先级
除此之外,还需应对资源抢占问题,主要手段是资源隔离:通过给核心消息和非核心消息分别配置独立的消费集群,避免非核心消息抢占核心业务的资源,影响关键流程。
比如支付和订单就是核心消息,日志和通知就是非核心消息。要是图省事把这两类消息堆在同一个消费集群里处理,风险就很大了:万一某天非核心消息突然爆量,比如做活动时用户行为日志激增,或者系统升级后日志输出变多,这些消息就会像占路的大车一样,把消费集群的 CPU、内存、网络带宽全占满。这时候核心消息再进来,就会发现没资源可用了,只能排队等着,原本几百毫秒就能处理完的订单消息,可能要等好几分钟,严重的甚至会导致订单状态同步延迟,用户付了钱却看不到订单,商家收不到支付通知,整个关键业务流程都会被拖慢。
所以更合理的做法是,给它们分别配置独立队列和独立消费集群。

- 核心消息专门用一套性能有保障、资源预留充足的集群,比如用配置更高的服务器,还提前做好弹性扩容策略,确保哪怕核心消息量突增,也能稳稳处理;
- 非核心消息则用另一套集群,资源配置可以根据其流量波动灵活调整,就算这类消息偶尔占满资源,也不会影响到核心集群的正常运转。
这样一来,核心业务和非核心业务各走各的路,核心流程的稳定性就有了兜底,用户体验和业务可靠性也能得到保障。
2. 优化消息设计,减少流程阻碍
解决了消化端的效率问题后,还需从消息设计入手,减少流程阻碍。
消息瘦身:给消息减减肥
消息不是内容越多越好,反而简洁才高效。传递消息时,只保留业务必需的核心字段就行。比如处理订单消息,没必要把用户的姓名、地址、联系方式等完整信息都塞进去,只需要传个用户 ID,消费端按需去数据库查详情就够了。

这样做能显著缩小单条消息的体积,尽量控制在 100KB 以内。别小看这一点,消息小了,网络传输时占用的带宽更少,队列存储时也更省空间,消费端解析起来也更快,从发送到处理的整个链路耗时都会缩短,间接减少了积压的可能性。
配置死信队列:给问题消息找个专属位置
消息处理难免会遇到临时故障,数据库突然连接不上、远程服务超时等等,这时消息会处理失败。如果让这些失败的消息一直留在原队列里反复重试,很容易阻塞后面的正常消息。就像路上的故障车不挪走,会堵死整条路。死信队列就是专门解决这个问题的:配置好规则后,处理失败达到一定次数的消息会被自动转移到死信队列,原队列能继续处理新消息。之后可以通过定时任务批量重试死信消息,或者人工介入排查具体原因。既保证了正常流程不被打断,也不会漏掉需要处理的消息。

设置消息过期策略:让过期消息自动退场
不是所有消息都需要永久保存,有些消息过了特定时间就没价值了。例如普通的系统操作日志,超过 24 小时可能就没必要再处理了;非核心的营销通知,过了活动时间也失去了意义。给这类时效性低的消息设置 TTL,也就是消息生存时间,比如 2 小时或 1 天,过期后队列会自动清理它们,不用再占用存储资源。这样一来,队列里始终是有价值的消息,存储压力小了,消息检索和消费的效率也会更高,从底层减少了积压的隐患。
3. 做好流量控制,避免超出承载能力
用了上文提到的方法之后,消费能力上去了、也更可靠了,但还需要配合流量控制来优化。针对流量控制,可以从两方面来思考:一是临时增加容量太仓促,需要提前规划,避免被打个措手不及;二是不能无限扩容,终有穷尽和业务能负担的极限,不能说突然有个 1000w/s 的请求的瞬间高峰,立刻扩容几千台机器给支撑吧,那成本得多大。针对这两方面,需要做如下部署。
提前容量规划
消息队列的处理能力不能走一步看一步,得根据历史数据提前布局。可以查阅过去半年甚至一年的流量记录,找到业务高峰期的消息量。

比如日常每秒处理 1000 条消息,那规划时就得按 3 倍甚至更高的标准来准备,这样遇到突发流量才不会慌。具体可分为两步:一方面要算好队列分区数,比如 Kafka 的分区得足够多,保证消费者能并行处理;另一方面需要给消费者服务器配足资源,CPU、内存这些不能抠门,确保就算消息量冲到峰值,消费者吃掉消息的速度也始终比生产者喂进来的快,从根上避免积压。
生产者限流
消息发送端得有刹车机制,不能一股脑把消息全灌进队列。可以用令牌桶算法来控制节奏,设定好每秒最多发多少条消息,超过这个量就先拦住,等有令牌了再发,避免突发流量直接冲垮队列。遇到流量实在超标的情况,非核心业务就要懂让路:比如营销推送、用户行为分析这类消息,临时停掉也不影响主要交易,先把资源让给订单、支付这些核心消息,保证关键业务能正常跑。

峰值预演
大促、秒杀这种流量高峰就像考试,考前得好好复习。活动开始前一两周,最好用压测工具模拟几倍于日常的消息量,看看消费者能不能扛住,比如预计双 11 零点会有每秒 5000 条订单消息,就用压测工具发 8000条/s 试试水。如果发现处理延迟变长,就赶紧加服务器、扩线程,把资源提前配到位。这样等活动真的开始,消息处理就能从容应对,不会手忙脚乱地出现积压。
4. 完善监控与告警,及时发现问题
前面我们讲了预防问题、解决问题,但是总有问题真出现的时候,这时候最重要的就是能及时发现问题。在后端领域,就是通过监控来实现问题发现的及时性。监控不能眉毛胡子一把抓,得聚焦核心监控指标,盯着最能反映队列健康状态的核心指标。
队列层面监控
要重点看积压消息的数量,这就像水库的水位,一旦超过安全线就得警惕;还要盯消息增长速率,如果突然从每秒 1000 条涨到 5000 条,可能预示着潜在的积压风险;另外,消息过期比例也不能忽视,要是大量消息还没被消费就因超时被删除,可能意味着消费能力严重不足。
消费侧监控
我们需要关注每秒处理多少条消息,这直接反映处理效率;单条消息的平均处理耗时也很关键,突然从 200ms 涨到 1 秒,可能是消费逻辑出了问题;线程池利用率、消费失败率也要实时跟踪,前者过高说明资源快耗尽,后者飙升可能意味着业务逻辑有 bug。
生产侧监控
要盯着发送 QPS 是否异常波动,发送失败率是否突然升高,如果失败率升高,可能是队列满了或网络问题,还要重点关注消息重复率,重复消息太多会浪费消费资源,也可能引发业务问题。
理清楚监控指标之后,就需要设置告警策略,可以给关键指标设置不同级别的阈值:比如积压消息超过 10 万条触发警告,超过 50 万条升级为紧急;消息增长速率超过 5000 条/秒时自动告警。
告警渠道也得多样化,轻微问题可以发钉钉或者企业微信群通知,让团队成员留意;严重问题就得直接发短信甚至电话提醒,确保责任人员能第一时间看到。目标是让任何异常都能在 5 分钟内被发现,毕竟消息积压就像滚雪球,发现得越早,处理起来越轻松,造成的影响也越小。

总结
针对消息积压问题,从预防到应急处理,本文介绍了多种实战思路。核心逻辑在于:通过监控与告警机制及时检测异常;通过容量规划与动态调整确保消费能力高于消息增量;并通过资源隔离与容错设计减少故障影响。许多团队在系统异步化过程中常遇到积压挑战,如大促期间消息堆积导致订单延迟,或单条失败消息阻塞队列。希望这些经验能帮助避免常见陷阱,使消息队列成为系统解耦和效率提升的有效工具。

