Q:刚开始是对这个疑问抱有质疑态度的,因为使用消息队列的其中目的就是削峰填谷,来避免高流量时,对下游服务的冲击,所以使用消息队列进行缓冲,下游根据自己的消费能力去消费,
我感觉这就是消息积压本就是使用消息队列的功能,怎么会是问题呢?
A:首先消息积压是正常现象,但凡是过多就不正常了。积压越来越多就需要处理了。就像一个水库,日常蓄水是正常的,但下游泄洪能力太差,导致水库水位一直不停的上涨,这个就不正常了。
消息发送主要涉及三方:producer/consumer/broker,所以发生消息积压要从这三方来看。
1、broker
其实不用太关注消息队列,因为消息队列本身的处理能力要远远大于业务系统的处理能力。主流消息队列的单个节点,消息收发的性能可以达到每秒钟处理几万至几十万条消息的水平,还可以通过水平扩展 Broker 的实例数成倍地提升处理能力。
2、producer端性能优化
producer端对消息积压的影响不大,但是对producer端发送消息的性能有要求。一般是先执行自己的业务逻辑,最后再发送消息。如果说,你的代码发送消息的性能上不去,你需要优先检查一下,是不是发消息之前的业务逻辑耗时太多导致的。
对于发送消息的业务逻辑来说,设置批量发送及批量发送的大小可以提高发送端的发送性能
Producer 发送消息的过程,Producer 发消息给 Broker,Broker 收到消息后返回确认响应,这是一次完整的交互。假设这一次交互的平均时延是 1ms,我们把这 1ms 的时间分解开,它包括了下面这些步骤的耗时:发送端准备数据、序列化消息、构造请求等逻辑的时间,也就是发送端在发送网络请求之前的耗时;发送消息和返回响应在网络传输中的耗时;Broker 处理消息的时延。如果是单线程发送,每次只发送 1 条消息,那么每秒只能发送 1000ms / 1ms * 1 条 /ms = 1000 条 消息,这种情况下并不能发挥出消息队列的全部实力。
无论是增加每次发送消息的批量大小,还是增加并发,都能成倍地提升发送性能。至于到底是选择批量发送还是增加并发,主要取决于发送端程序的业务性质。
发生消息积压后,producer端服务降级,关闭一些非核心业务,减少消息的产生。
3、consumer端性能优化
发生消息积压,主要原因就是消费端的消费能力跟不上生产端的生产速度。
扩容consumer实例,注意扩容后必须同步扩容主题中的分区(也叫队列)数量,确保 Consumer 的实例数和分区数量是相等的,因为在队列中的消费是单线程的,如果只
扩容了consumer实例,没有扩容队列数量,则不会有效果的。
例如 Kafka,这个消息积压的 Topic 有 3 个 Partition,那最多就能用 3 个 Consumer,所以增加 Consumer 没有用。
还是可以使用临时队列的方式作为中转,提升处理能力。
等待积压的消息被消费,恢复到正常状态,撤掉扩容服务器。