最近和大佬聊MQ底层设计时,被说到“发生消息大量挤压后如何处理”时没反应过来,惭愧惭愧。

  虽然线上没遇到过这样的问题,但我事后想了一下,这种情况还是得具体问题具体分析。比如消费端有问题,不消费了或者消费慢了,消费速度跟不上;再比如消息中心有问题,消息没有出口、配置中心的订阅关系出错或没有更新,消息端已经不再监听这个Topic了。

  对于上面这两种情况,简单的一般先检查消息中心是否正常,订阅关系是否正确,然后检查消息是否持久订阅。但既然设置了TTL就证明这个消息不重要,丢弃时打日志方便排查就可以了。如果是持久化订阅,就要排查消息端为什么出故障了。除Dump机器状态、保留现场外,剩下的就是 如何快速消费消息 了。

  

java订阅mqtt信息队列 mqtt订阅消息堆积_大数据

  “如何快速消费消息”这其实是“消息挤压如何处理”这个问题的本质,因为即使消费端恢复消费速度,一个消费者一秒1000条消息,一个小集群10台机器一秒也就1W条消息,几百万条、千万条消息也得等上个把小时;而如果消费端盲目扩容也不可取,很容易造成消费端下游服务的崩溃,所以要做好流。

  我思考了一下,可以从这几个方面考虑:

  1. 当消息中心挤压了大量消息时,当时无论怎么做都是补救措施,所以架构层面要求,事前要做好压测,压测要完备。但压测也有覆盖不到的比如不可预知的突发流量,不能等到消息挤压了百万、千万才通知我们,所以事中要求做好监控,比如消息队列的长度、消费速率等监控指标,消息挤压到比如50%就必须要告警了;
  2. 消息挤压发生后,要做好紧急预案:
  • 考虑是否节流。当发生消息大量挤压时,为了保护核心消费链路和消息中心本身的安全性,对部分发布者拒绝发布消息。而在消息队列,考虑抛弃非重要消息,只处理核心消息。这部分丢弃的数据可以事后回查出来做业务补偿,这没什么问题;
对于推模式而言,在于怎么调整重投策略,对于拉模式而言,在于怎么调整拉取策略。当然,长轮询+阻塞场景下,本质还是看Broker端的重投策略。
  • 考虑是否蓄洪。MQ持久化都支持MMAP内存换入+异步刷盘到文件比如Kafka,但这有上限即机器本身的磁盘空间,通过接入DB,超过一定阈值后将消息写入到数据库中,等到业务峰值过去后再慢慢消化。

 

  暂时没想到其它思路,如果有什么不同的意见建议,欢迎拍砖