消息堆积

几天没看设备,结果发现设备大量消息堆积。对于消息堆积这种事情,基本一出现就是大问题,比较坑可能会打爆磁盘,或者直接无限Rebalance。我比较熟悉kafka和rabbitmq,以下就用这两种消息中间件来说。

其实对于消息堆积,一般想到的话,就是增加消费者。一开始我打算使用多个线程来进行消费,修改线上代码来加速消费。但是对于kafka来说,出现了堆积,你就算再增加消费者,由于分区数是不变的,每个分区只能有一个group的一个消费者来进行消费。所以白白的增加消费者是没用的。

找到原因,对症下药

对于kafka来说,生产者可能是某个时间段的访问量突然增大。对于我们的业务来说,每秒的数据是固定的,所以不是生产者的问题。kafka的吞吐量也是很大的,基本也不会出现问题。那么原因只可能是下游消费者出现了问题。比如下游需要调用第三方服务,可能会导致消费速度慢。也有可能像我一样,消费者代码写的太垃圾了。其实消息队列的一个作用就是用来堆积的,只是看允不允许巨大的延迟。堆积常见的原因一般是数据库瓶颈,第三方接口响应慢之类的,这种情况下增加消费者和开启多线程,都没什么用。如果业务对实时性要求不高,broker能扛得住,堆积不能算生产事故

解决

首先,要降低对正常业务的影响。减少生产,也要提高消费速度。这也要考虑具体的业务场景。看数据重不重要,看及时性要求。比如可以增加一个开关,积压后打开开关把消息拉取后直接写到数据库里回复ack,后面异步线程再去数据库拉取消息进行处理。
假如Kafka 消息堆积,表现为 Consumer Rebalance。线上 Kafka 突发 rebalance 异常,如何快速解决?这时候,只能先调整一下那几个超时参数,让他先慢慢消费着。 另一方面,再去排查原因。
对于消费者心跳超时问题。一般是调高心跳超时时间session.timeout.ms,调整超时时间session.timeout.ms和心跳间隔时间heartbeat.interval.ms的比例。阿里云官方文档建议超时时间session.timeout.ms设置成 25s,最长不超过 30s。那么心跳间隔时间heartbeat.interval.ms就不超过 10s。
对于消费处理超时问题。一般是增加消费者处理的时间max.poll.interval.ms,减少每次处理的消息数max.poll.records。阿里云官方文档建议 max.poll.records 参数要远小于当前消费组的消费能力
records < 单个线程每秒消费的条数 x 消费线程的个数 x session.timeout的秒数。