(面试题)消息队列如何处理消息积压呢?

一、提前预防,通过优化性能的方式,来避免出现消息积压

消息队列处理能力能够达到每秒几万甚至几十万条消息的水平,而业务系统需要处理的业务逻辑比消息队列复杂,所以单个节点能够处理几百到几千的请求,就已经算是性能很好的了。因此,对于消息队列的性能优化,我们更关注的事,在消息的收发两端,我们的业务代码怎么和消息队列配合,达到一个最佳的性能。

1. 发送端性能优化

因为发送端一般都是要先执行自己的业务逻辑,然后再发送消息的,所以发送端发送消息的性能比较低,有可能是因为在发消息之前,执行业务逻辑耗时太长了。

(1)那要如何解决业务逻辑执行耗时过长这件事呢?

设置合适的并发和批量大小,就能够达到很好的发送性能。

(2)发送消息过程中需要考虑哪些步骤的耗时?

Producer发送消息的过程,Producer发消息给BrokerBroker收到消息后返回确认响应,这是一次完整的交互。假设这一次交互的平均时延时 1ms,我们把这 1ms 的时间分解开,它包括了下面这些步骤的耗时:

  • 发送端准备数据、序列化消息、构造请求等逻辑的时间,也就是发送端在发送网络请求之前的耗时;
  • 发送消息和返回响应在网络传输中的耗时;
  • Broker 处理消息的时延。

如果是单线程发送,每次只发送1条消息,那么每秒只能发送 1000 ms / 1ms * 1条 / ms = 1000条消息,这种情况下并不能发挥出消息队列的全部实力。

那么我们就可以增加每次发送消息的批量大小,或者增加并发,从而成倍提升发送性能。至于到底是选择批量发送 还是增加并发,主要取决于发送端程序的业务性质。简单来说,只要能够满足你的性能要求,怎么方便就怎么实现。

(3)举例

  • 如果说你的消息发送端是一个微服务,主要接收 RPC 请求处理在线业务。很自然的,微服务在处理每次请求的时候,就在当前线程直接发送消息就可以了,因为所有 RPC 框架都是多线程支持多并发的,自然也就实现了并行发送消息。并且在线业务比较在意的是请求响应时延,选择批量发送必然会影响 RPC 服务的时延。这种情况,比较明智的方式就是通过并发来提升发送性能。
  • 对于一个离线分析系统来说,离线系统并不关心时延,更注重整个系统的吞吐量。发送端的数据都是来自于数据库,这种情况就更适合批量发送,你可以批量从数据库读取数据,

2. 消费端性能优化

如果消费速度一直比生产速度慢,时间长了,整个系统就会出问题。要么消息队列的存储被填满无法提供服务,要么消息丢失

所以,我们在设计系统的时候,一定要保证消费端的消费性能要高于生产端的发送性能,这样的系统才能监控地持续运行。

如何提高消费端性能

  1. 优化消费业务逻辑
  2. 水平扩容,增加消费端的并发数来提高总体的消费性能
    • 因为对于消费者来说,在每个分区(也叫队列)上只能支持单线程消费,所以扩容 Consumer的实例数量的同时,也必须同步扩容主题中的分区数量,确保Consumer的实例数和分区数是相等的。如果Consumer的实例数量超过分区数量,这样的扩容实际上是没有效果的。

  3. 将消息放到内存队列中,可以快速地返回响应,而处理消息的业务线程可以实现并行消费,提高系统的吞吐量和性能,解决了单个 Consumer 不能并行消费的问题。

二、线上系统出现了消息积压,如何紧急处理

1. 分析消息积压出现的原因

(1)关于消息积压的出现,最粗粒度的原因,只有两种:

  1. 消息发送变快了
  2. 系统消费的速度变慢了

(2)常见原因大致有如下三个:

  1. 任务产生的服务过多,任务处理的服务过少,不均衡;
  2. 任务处理时间太长,也导致生产过剩;
  3. 中间件本身容量偏小,需要扩容或集群化管理;

2. 解决问题

(1)对任务生成进行流量控制
(2)监控,扩容消费端实例来提升总体的消费能力
(3)系统降级,关闭一些不重要的业务,减少发送方发送的数据量
(4)消费变慢了,可以检查日志,看看是否有大量消费错误;可以看看线程是不是卡在什么地方不动,比如:等待某些资源或者触发死锁


三、参考资料

  1. 消息队列高手课
  2. 架构设计 | 异步处理流程,多种实现模式详解

猜你喜欢

转载自blog.csdn.net/e2788666/article/details/131396845