切换主题
13. 消费堆积与调优:大促后消息处理不过来
线上告警
大促期间,订单创建消息暴涨。下单服务还能发消息,但通知服务和积分服务消费越来越慢。监控里出现消息堆积。
这时不要第一反应就加机器。先判断瓶颈在哪里。
堆积的常见原因
| 原因 | 现象 |
|---|---|
| 单条处理太慢 | 消费耗时高 |
| 下游接口慢 | 消费线程阻塞 |
| 数据库连接池不足 | 消费线程等待连接 |
| 消费线程太少 | CPU 和下游都空闲但消费慢 |
| 消息太大 | 网络和反序列化耗时高 |
| 重试消息过多 | 正常消息被失败消息拖住 |
PushConsumer 参数
@RocketMQMessageListener 提供几个关键参数:
java
@RocketMQMessageListener(
endpoints = "${demo.points.rocketmq.endpoints}",
topic = "order-event-topic",
consumerGroup = "points-service-group",
tag = "order-paid",
consumptionThreadCount = 32,
maxCachedMessageCount = 2048,
maxCacheMessageSizeInBytes = 67108864
)
public class PointsOrderPaidListener implements RocketMQListener {
// ...
}| 参数 | 调整思路 |
|---|---|
consumptionThreadCount | 消费逻辑轻、下游能扛住时可以增加 |
maxCachedMessageCount | 本地缓存能力,过大可能增加内存压力 |
maxCacheMessageSizeInBytes | 消息体大时关注内存 |
requestTimeout | 网络或服务端慢时关注 |
调优顺序
- 先看单条消费耗时。
- 再看下游接口和数据库。
- 再调消费线程数。
- 再考虑扩容消费者实例。
- 最后才考虑拆 topic、拆业务流。
不要把 consumptionThreadCount 当万能按钮。如果消费逻辑会打数据库,线程数翻倍可能只是让数据库更快崩。
小技巧
每个消费者都要打三类日志:
text
开始消费:messageId、key、tag、consumerGroup
消费成功:耗时、业务主键
消费失败:异常类型、是否可重试、业务主键有了这些日志,排查堆积时才能知道是消息系统慢,还是业务慢。
常见坑
只看堆积数量,不看消费耗时。
堆积是结果,耗时才接近原因。线程数调太大。
下游承受不住,失败率上升,重试更多,堆积更严重。失败消息和正常消息混在一起拖慢系统。
要有失败分类和补偿机制。
练习题
- 消费堆积时,第一步看什么指标?
- 什么时候增加
consumptionThreadCount是危险的? - 为什么失败消息过多会造成更大堆积?
参考答案
- 看消费耗时、失败率、重试量、下游接口耗时、数据库连接池。
- 当瓶颈在数据库或下游接口时,增加线程会放大压力。
- 失败消息反复重试会占用消费资源,挤压正常消息。
来源
- RocketMQ 消费类型:https://rocketmq.apache.org/docs/featureBehavior/06consumertype/
RocketMQMessageListener参数:https://github.com/apache/rocketmq-spring/blob/rocketmq-spring-all-2.3.4/rocketmq-v5-client-spring-boot/src/main/java/org/apache/rocketmq/client/annotation/RocketMQMessageListener.javaDefaultListenerContainer:https://github.com/apache/rocketmq-spring/blob/rocketmq-spring-all-2.3.4/rocketmq-v5-client-spring-boot/src/main/java/org/apache/rocketmq/client/support/DefaultListenerContainer.java