MQ消息积压解决方案
出现原因
当消息队列(MQ)中的消息出现积压时,通常意味着消费者处理消息的速度低于生产者发送消息的速度。解决消息积压问题可以从以下几个方面入手:
1. 增加消费者实例
- 水平扩展:添加更多的消费者实例,以提高处理能力。确保所有消费者均在同一消费者组内,MQ 会自动分配消息队列。
但还是需要具体场景,不同的场景下情况是不一样的
- 场景一:若消费者的数量小于 MessageQueue 的数量,增加消费者可以加快消息消费速度,减少消息积压。比如一个 Topic 有 4 个 MessageQueue,2 个消费者进行消费,如果增加一个消费者,可以加快拉取消息的频率
- 场景二: 如果消费者的数量大于等于 MessageQueue 的数量,增加消费者是没有用的。比如一个 Topic 有 4 个 MessageQueue,并且有 4 个消费者进行消费
对于场景一来说也有特殊情况;若本地消息消费的慢,就会延迟一段时间后再去拉取。
消费者拉取的消息存在 ProcessQueue,消费者是有流量控制的,如果出现下面四种情况,就不会主动去拉取
-
ProcessQueue 保存的消息数量超过阈值(默认 1000,可以配置)
-
ProcessQueue 保存的消息大小超过阈值(默认 100M,可以配置)
-
对于非顺序消费的场景,ProcessQueue 中保存的最后一条和第一条消息偏移量之差超过阈值(默认 2000,可以配置)
-
对于顺序消费的场景,ProcessQueue 加锁失败,也会延迟拉取,这个延迟时间是 3s。
拉取慢本质原因是消费者消费慢,导致下次去拉取的时候 ProcessQueue 中积压的消息超过阈值
2. 优化消费者代码
- 性能调优:检查消费者的逻辑,确保没有不必要的阻塞或延迟。优化处理逻辑,可以使用异步处理、批量消费等方式。
- 提高并发:如果可能,增加消费者的并发处理能力,例如使用多线程或并发框架。
3. 调整消息生产速率
- 限流:如果生产者发送消息的速率过快,可以对生产者进行限流,控制消息的发送速率,使其与消费者的处理能力相匹配。
4. 使用消息优先级
- 优先级队列:如果某些消息比其他消息更重要,可以将它们设为高优先级,以便优先处理。
5. 增加消息队列的容量
- 扩展队列:检查消息队列的存储限制,如果达到上限,可以考虑扩展存储容量,以防止消息丢失。
6. 消息过期和清理
- 设置过期时间:对于不再需要的消息,可以设置过期时间,允许系统自动清理。
- 定期监控:定期检查和清理无效消息,减轻队列负担。
7. 监控与报警
- 建立监控:使用监控工具(如 Prometheus、Grafana 等)监控消息队列的状态,及时发现问题。
- 报警机制:建立报警机制,当消息积压达到一定阈值时,及时通知相关人员进行处理。
8. 负载均衡
- 分布式架构:如果使用了分布式消息队列,确保各个节点之间的负载均衡,避免某一节点过载。
常见6种负载策略
- 平均负载策略
- 把消费者进行排序;
- 计算每个消费者可以平均分配的 MessageQueue 数量;
- 如果消费者数量大于 MessageQueue 数量,多出的消费者就分不到;
- 如果不可以平分,就使用 MessageQueue 总数量对消费者数量求余数 mod;
- 对前 mod 数量消费者,每个消费者加一个,这样就获取到了每个消费者分配的 MessageQueue 数量。
- 循环分配策略
- 遍历消费者,把 MessageQueue 分一个给遍历到的消费者;
- 如果 MessageQueue 数量比消费者多,需要进行多次遍历,遍历次数等于 (MessageQueue 数量/消费者数量)
- 自定义分配策略
这种策略在消费者启动的时候可以指定消费哪些 MessageQueue - 按照机房分配策略
这种方式 Consumer 只消费指定机房的 MessageQueue - 按照机房就近分配
这种策略 broker 的命名必须按照格式:机房名@brokerName,因为消费者分配队列的时候,首先按照机房名称过滤出所有的 MessageQueue,然后再按照平均分配策略进行分配 - 一致性 Hash 算法策略
把所有的消费者经过 Hash 计算分布到 Hash 环上,对所有的 MessageQueue 进行 Hash 计算,找到顺时针方向最近的消费者节点进行绑定
以下是简单实现
import java