今天我们就来聊一聊,一旦真的遇到了这个问题,需要如何去分析解决?
图片
一般而言,出现消息积压有2个方面的原因:
- 从生产者的角度来说: 可能是业务迅速增长,导致生产者在短时间内生成大量消息,而下游消费者的处理能力无法满足,从而导致消息积压。
- 从消费者的角度来说: 大概率是消费者遇到了一些问题,导致无法及时处理消息。这常见于下游消费逻辑中的远程调用出现大量超时、Redis或数据库发生故障(上次B佬遇到的就是这个问题)等情况。
很明显,业务迅速增长是可遇而不可求的事(常见于营销活动、秒杀等场景),不可能要求生产者少发送消息,所以遇到这个问题只能从消费者的角度寻求解决方案。
一般来说,解决消息积压有如下几个常见方案:
- 增加消费者数量: 如果消息消费者的处理速度无法满足消息产生的速度,可以通过增加消费者数量来提高消费能力。这样可以将负载分散到多个消费者上,加快消息处理速度,减少积压。不过需要注意的是,一般消息队列都有分区的概念,消费者的数量是不能超过分区的数量。
- 增加消息队列的容量: 如果消息队列的容量设置过小,可能会导致消息积压。可以通过增加消息队列的容量来缓解积压问题。但需要注意,过大的消息队列容量可能会增加消息处理的延迟。
- 优化消息消费的逻辑: 检查消息消费逻辑是否存在性能瓶颈或不必要的复杂计算。优化消息消费的逻辑可以提高消费速度,减少消息积压。
- 设置消息消费失败的处理机制: 当消息消费失败时,可以根据业务需求选择合适的处理方式。可以将失败的消息记录下来,后续再次消费;或者将失败的消息发送到死信队列进行处理。
- 监控和报警机制:建立监控和报警机制,及时发现消息积压的情况并采取相应的措施。可以通过监控指标、日志或专业的监控工具来实现。
不过上面的解决方案还是偏于理论了,一旦线上已经产生了大量的消息积压,该如何迅速处理呢?
在实际实现中,可以按照如下步骤快速处理消息积压问题:
- 确认并解决消费端的bug: 保证消费端能够正常处理消息。
- 停止所有消费端: 新建一个Topic,将Partition分区数量调整为原来的10倍。
- 编写数据分发的Consumer程序: 该程序专门消费积压的数据,不做处理,直接将数据写入临时创建的Topic的10个Partition中。(可以参考我在DDD专栏中基于Disruptor的分发组件来实现)
- 临时增加10倍的消费者节点: 重新部署Consumer,订阅新创建的临时Topic,用以快速处理临时Partition分区数据。
通过上述方法,可以迅速处理积压的消息。待积压消息处理完成后,再将系统恢复为原有部署架构,释放临时创建的Topic和相应的机器资源。