消费积压如何处理
# 一、消费积压
首先需要明确一个概念:消费积压是我们所需要的,我们需要消息队列来提供这个能力,为我们下游系统提供一种缓冲。而消费积压如果积压到一定程序,比如多少条消息在一定时间段内没有消费完,这才是我们需要关注的点。
而消费积压的直接原因:是系统中的某个部分出现了性能问题,来不及处理上游发送的消息,才会导致消息积压。
由于消息队列本身的处理能力要远大于业务系统的处理能力。主流消息队列的单个节点,消息收发的性能可以达到每秒钟处理几万至几十万条消息的水平,而业务系统每分钟能处理几百或者几千消息已经算不错性能,所以我们的优化重点在于:
- 如何在消息收发两端保持一个高性能。
- 如果出现消费积压,如何进行紧急处理,最大程度地避免消息积压对业务的影响。
# 二、发送端和消费端优化
# 1、发送端优化
对于发送端而言,一般是不会存在性能瓶颈的,如果说,你的代码发送消息的性能上不去,你需要优先检查一下,是不是发消息之前的业务逻辑耗时太多导致的。
# 2、消费端优化
消息队列中,大部分的性能问题都出现在消费端,如果消费的速度跟不上发送端生产消息的速度,就会造成消息积压。
- 如果只是短暂消费速度跟不上,只要消费端的性能恢复之后,超过发送端的性能,那么积压的消息就可以被消化掉。
- 如果消费端的性能一直比生产速度慢,消息队列的存储就会被堆满无法提供服务,甚至导致消息丢失。
所以,一定要保证消费端的消费性能要高于生产端的发送性能,这样的系统才能健康的持续运行。
常见优化方式有两种:
- 消费端的性能通过优化消费业务逻辑来提高
- 通过水平扩容,增加消费端的并发数来提升总体的消费性能。特别需要注意的一点是,在扩容 Consumer 的实例数量的同时,必须同步扩容主题中的分区(也叫队列)数量,确保 Consumer 的实例数和分区数量是相等的。
如果 Consumer 的实例数量超过分区数量,这样的扩容实际上是没有效果的。原因我们之前讲过,因为对于消费者来说,在每个分区上实际上只能支持单线程消费。
# 三、消费积压如何处理
消费积压主要有两种情况:
- 日常系统正常运转的时候,没有积压或者只有少量积压很快就消费掉了,这种情况基本上可以忽略
- 某一个时刻,突然就开始积压消息并且积压持续上涨。这种情况下需要在短时间内找到消息积压的原因,迅速解决问题才不至于影响业务。
而消费积压从最粗粒度的原因,只有两种:要么是发送变快了,要么是消费变慢了。
发送变快
如果是单位时间发送的消息增多,比如说是赶上大促或者抢购,短时间内不太可能优化消费端的代码来提升消费性能,唯一的方法是通过扩容消费端的实例数来提升总体的消费能力。
如果短时间内没有足够的服务器资源进行扩容,没办法的办法是,将系统降级,通过关闭一些不重要的业务,减少发送方发送的数据量,最低限度让系统还能正常运转,服务一些重要业务。
消费变慢
通过打印堆栈信息,看一下你的消费线程是不是卡在什么地方不动了,比如触发了死锁或者卡在等待某些资源上了。
如果消费速度和发送速度一样,但是还是导致消费积压,需要检查一下你的消费端,是不是消费失败导致的一条消息反复消费这种情况比较多,这种情况也会拖慢整个系统的消费速度。