消息队列产生严重消息堆积怎么处理?

2,875 阅读3分钟

1. 为什么产生消息堆积?

大多是因为 Consumer 出问题了,没有及时发现,或者故障恢复需要较长的时间,导致大量消息积压在 MQ 中。

2. 消息堆积会有什么后果呢?

2.1 消息被丢弃

例如 RabbitMQ 有一个消息过期时间 TTL,过期的消息会被扔掉,这样消息就彻底没有了。

2.2 磁盘满了

如果堆积量太大,可能导致磁盘空间不足,那么新消息就进不来了。

2.3 海量消息待处理

如果消息没过期,并且磁盘空间也够用,那么就是产生海量消息等待被消费,Consumer 的噩梦。

3. 如何应对呢?

3.1 消息被丢弃的情况

首先,要实现防止消息过期问题,不应该设置过期时间。

如果就是设置了过期时间,导致了消息丢失,怎么补救呢?

那就只能在夜深人静,趁着访问量最低的时候,写一个临时程序来补消息了。

例如有订单消息丢了,那就需要找出哪些订单消息丢了,然后重新发到队列。

3.2 磁盘不足的情况

系统通常都是有监控的,达到空间阈值时就会发警报,这时就要马上处理了。

例如,在其他机器上创建临时的消息队列,再写一个临时的 Consumer,作为消息的中转,把消息积压队列中的消息取出来,放到临时队列里面去。

快速疏散积压的消息,让磁盘空间恢复正常水平。

3.3 快速处理海量积压消息

Consumer 恢复正常之后,面对堆积如山的消息,怎么处理呢?

如何按照之前正常情况处理的话,猴年马月才能消费完,此过程中还有新消息在不断进来。

例如,积压了 100 万条,有 3 个 Consumer,每一个每秒能处理 200 条,3 个 Consumer 每秒一共能处理 600 条。

大概需要一个多小时才能处理完。

这一个多小时又会积压多少新的消息呢?

所以正常处理肯定不行,需要提速。

例如 Kafka,这个消息积压的 Topic 有 3 个 Partition,那最多就能用 3 个 Consumer,所以增加 Consumer 没有用。

还是可以使用临时队列的方式。

新建一个 Topic,设置为 20 个 Partition

Consumer 不再处理业务逻辑了,只负责搬运,把消息放到临时 Topic 中

这 20 个 Partition 可以有 20个 Consumer 了,它们来处理原来的业务逻辑。

这 20 个 Consumer 每秒一共能处理 4000 条了,这样几分钟就可以处理完积压的 100 万条。

这几分钟新来的消息也不会太多,所以很快就可以恢复正常水平,之后,再把整体结构恢复为原来的形式。

小结一下,消息积压还是比较麻烦的,最好是提前防范,做好硬件和消息系统的健康监控。如果出现消息丢失,就要人工查找丢失的消息,然后补上。在消费不过来的时候,可以考虑使用临时队列作为中转,提升处理能力。

推荐阅读

OAuth2 图解

轻松理解 Kubernetes 的核心概念

开发者必须要了解的架构技术趋势:Service Mesh