现在有一个在线的业务,突然量大了起来,消费端或者说下游系统突然处理不过来了,MQ出现了大量的消息堆积,业务写入MQ异常,有什么办法可以相对平缓得解决呢?

解决思路

  1. 从生产者端解决
    一般系统容量或者处理能力都是规划好的,出现消息堆积的情况,大部分是由于流量暴增引起,这个时候可以考虑控制生产者的速率,对前端机器流量进行限速限流。
  2. 从消费者端解决。
    消费者端解决的思路有两种
  • 假如消费者数还有增加的空间,那么加消费者解决。
  • 假如没有拓展的可能,但吞吐量还没达到MQ的上限,只是消费者消费能力不足,比如消费者总体消费能力已经到达上线(数据库写入能力等),或者类似Kafka的消费者数量与partition数有关,如果前期设计没有做好水平拓展的设计,这个时候多少个partition就只能对应多少个消费者。这个时候我们可以先把一部分消息先打到另外一个MQ中或者先落到日志文件中,再拓展消费者进行消费,优先恢复上游业务
  1. 从整理系统上进行解决。
    第2点有提到就是有些MQ的设计限制,导致的消费者数是没法动态拓展的,这个时候可以考虑将原先队列进行拆分,比如新建一个topic 分担一部分消息,这个方式需要对系统的上下游都要进行调整,在实际操作难度可能比较高,处理起来可能也比较耗时,如果在事前有做好这个设计那事发后就能很好进行调整
  2. 如果采用先将消息消费到日志文件的方式,怎么保证时序性?
    一般消息队列都有时序问题,我们需要根据业务,对消息进行分区路由,比如根据用户纬度,只保证同一个用户的消息时序就行了,比如我把id为1~10000的用户写在一个文件中,10001~20000的写在一个文件中。后面按这个文件单独消费就能保证消息的时序。
  3. 不同MQ的消息堆积能力
    其实主要是看是采用内存堆积还是磁盘堆积了,一般像kafka磁盘堆积的,堆积能力都是很强的不会出现容量不足的写入异常,而像RabbitMQ这种内存堆积的,如果消费者跟不上,很容易就把内存堆满了。

  采用mq内部的方式去增大消费者的速度。因此我们需要知道两个参数属性:

  1、concurrentConsumers
  2、prefetchCount
  concurrentConsumers设置的是对每个listener在初始化的时候设置的并发消费者的个数。
  prefetchCount是每次一次性从broker里面取的待消费的消息的个数。prefetchCount是BlockingQueueConsumer内部维护的一个阻塞队列LinkedBlockingQueue的大小,其作用就是如果某个消费者队列阻塞,就无法接收新的消息,该消息会发送到其它未阻塞的消费者
  如果我们想增大消费者的速度,可以通过配置者两个参数来进行,如下所示

spring.rabbitmq.listener.simple.concurrency: 最小的消费者数量
spring.rabbitmq.listener.simple.max-concurrency: 最大的消费者数量
spring.rabbitmq.listener.simple.prefetch: 指定一个请求能处理多少个消息,如果有事务的话,必须大于等于transaction数量.

  假设用的是 RabbitMQ,RabbtiMQ 是可以设置过期时间的,也就是 TTL。如果消息在 queue 中积压超过一定的时间就会被 RabbitMQ 给清理掉,这个数据就没了。那这就是第二个坑了。这就不是说数据会大量积压在 mq 里,而是大量的数据会直接搞丢

  具体操作步骤和思路如下:

  (1)先修复consumer的问题,确保其恢复消费速度,然后将现有cnosumer都停掉;

  (2)新建一个topic,partition是原来的10倍,临时建立好原先10倍或者20倍的queue数量;

  (3)然后写一个临时的分发数据的consumer程序,这个程序部署上去消费积压的数据,消费之后不做耗时的处理,直接均匀轮询写入临时建立好的10倍数量的queue;

  (4)接着临时征用10倍的机器来部署consumer,每一批consumer消费一个临时queue的数据;

  (5)这种做法相当于是临时将queue资源和consumer资源扩大10倍,以正常的10倍速度来消费数据;

  (6)等快速消费完积压数据之后,得恢复原先部署架构,重新用原先的consumer机器来消费消息;

  

Java mqtt怎样获得订阅之前的消息 mqtt订阅消息堆积_数据