线上消息队列发生积压,如何快速解决?

73 阅读3分钟

以下文章来源 飘渺Jam JAVA日知录 

如何解决线上消息队列的消息积压问题?

如果你的简历上写了熟练掌握消息队列,那么这是一个非常容易被问到的问题,同时也是一个非常现实的问题,很有可能一不小心就被你遇到了。

今天我们就来聊一聊,一旦真的遇到了这个问题,需要如何去分析解决?

图片

一般而言,出现消息积压有2个方面的原因:

1、从生产者的角度来说:  可能是业务迅速增长,导致生产者在短时间内生成大量消息,而下游消费者的处理能力无法满足,从而导致消息积压。

2、从消费者的角度来说:  大概率是消费者遇到了一些问题,导致无法及时处理消息。这常见于下游消费逻辑中的远程调用出现大量超时、Redis或数据库发生故障(上次B佬遇到的就是这个问题)等情况。

很明显,业务迅速增长是可遇而不可求的事(常见于营销活动、秒杀等场景),不可能要求生产者少发送消息,所以遇到这个问题只能从消费者的角度寻求解决方案。

一般来说,解决消息积压有如下几个常见方案:

增加消费者数量:  如果消息消费者的处理速度无法满足消息产生的速度,可以通过增加消费者数量来提高消费能力。这样可以将负载分散到多个消费者上,加快消息处理速度,减少积压。不过需要注意的是,一般消息队列都有分区的概念,消费者的数量是不能超过分区的数量。

增加消息队列的容量:  如果消息队列的容量设置过小,可能会导致消息积压。可以通过增加消息队列的容量来缓解积压问题。但需要注意,过大的消息队列容量可能会增加消息处理的延迟。

优化消息消费的逻辑:  检查消息消费逻辑是否存在性能瓶颈或不必要的复杂计算。优化消息消费的逻辑可以提高消费速度,减少消息积压。

设置消息消费失败的处理机制:  当消息消费失败时,可以根据业务需求选择合适的处理方式。可以将失败的消息记录下来,后续再次消费;或者将失败的消息发送到死信队列进行处理。

监控和报警机制:建立监控和报警机制,及时发现消息积压的情况并采取相应的措施。可以通过监控指标、日志或专业的监控工具来实现。

不过上面的解决方案还是偏于理论了,一旦线上已经产生了大量的消息积压,该如何迅速处理呢?

在实际实现中,可以按照如下步骤快速处理消息积压问题:

确认并解决消费端的bug:  保证消费端能够正常处理消息。

停止所有消费端:  新建一个Topic,将Partition分区数量调整为原来的10倍。

编写数据分发的Consumer程序:  该程序专门消费积压的数据,不做处理,直接将数据写入临时创建的Topic的10个Partition中。(可以参考我在DDD专栏中基于Disruptor的分发组件来实现)

临时增加10倍的消费者节点:  重新部署Consumer,订阅新创建的临时Topic,用以快速处理临时Partition分区数据。

通过上述方法,可以迅速处理积压的消息。待积压消息处理完成后,再将系统恢复为原有部署架构,释放临时创建的Topic和相应的机器资源。