Halo

A magic place for coding

0%

RocketMQ 消费模式详解

RocketMQ 消费模式详解

Background

   在使用消息队列进行解耦的微服务架构中,如何让 mq 不成为流量的瓶颈呢?关于 mq 的并发消费,真的只是增加机器就能达到水平扩容的效果吗?在这篇博客我将介绍 RocketMQ 的消费机制,以及如何去提高消费能力。


Problem

   先来看看面对的是什么问题。假设以下两种场景:

  1. 在抢红包场景下,服务端收到来自客户端的请求,需要写入数据库的,在高峰时期客户端的请求量很大,需要用到 MQ 来削峰填谷。这个时候如果消费能力比较弱的话,可能客户端查询余额的时候就会不准确,因为数据还没有写入,都在 MQ 中 ** 积压 **。
  2. 在日志分析场景下,各个服务的日志信息都写入到 MQ 中,然后有固定的数据分析服务去汇总信息。各个服务产生的日志信息是非常巨量的,如果消费能力不高的话,就会导致分析结果比较滞后。

   以上两个问题都是消息在队列中积压导致的,所以我们需要尽可能地提高消费能力,不让消息在队列中积压。


Solution

   提升消费能力一般有两种:** 垂直扩展 ** 和 ** 水平扩展 垂直扩展 ** 指的是使用性能更高的机器,这个提升是有限的,而且价格也是更加昂贵的,所以一般我们不会选择这种方法。** 水平扩展 ** 指的是使用更多的同类型机器,通过分布式、并发等操作,提升系统的整体性能。提升 MQ 的消费能力,我们考虑的时候水平方向上的扩展。这里我讨论两种方式,一个是增加机器(实例),另一个是增加 worker(线程)。我们关注的重点是怎么样增加才是最有效的?

   首先我们要理解 RocketMQ 是怎么样消费消息的。RocketMQ 实际上有很多个 queue,这些 queue 是对应着 broker。比如说一个 broker 对应 5 个 queue,那么如果有 3 个 broker,那么这个 topic 就一共有 15 个 queue。RocketMQ 的消费是以 Consumer Group 的形式消费的,所以在最后的消费阶段,实际上就是 Consumer Group 去消费所有的 queue。这其中就有负载均衡的问题了。

   这里的负载均衡说的是每一个机器(实例)均分所有的 queue。假设有 5 个 queue,两个机器(实例),那么 A 机器(实例)消费 3 个 queue,B 机器消费 2 个 queue。这个时候如果新增了一个 C 机器,那么原来 A 机器消费的 1 一个 queue 将会由 C 机器来负责。这也就解释了为什么增加机器能够提升消费能力。从上面这个例子还能看出一个问题,就是机器的数量是不能超过 queue 的数量的,因为 queue 会分配到机器上,如果有 8 台机器,那么 6 台机器各自负责 1 个 queue,多余的 2 台机器将浪费掉,所以这是消费扩容的第一个要点:** 机器(实例)数量不得多余 queue 的数量 **。

   然后我们进入到单个机器(实例)中,去看是具体怎么消费的。很明显,消费一个队列最简单的方式就是一个一个消息拿出来,处理完一个再进行下一个。但是我们仍然有可能把这个速度提升上去。在 ** 乱序消费 ** 模式下,RocketMQ 允许采用多线程(多个 worker)的模式去消费,也就是说对于同一个 queue,可以用多个 worker 同时去消费,这样消费的性能就大大提升了,而且这个提升比起提升机器要方便得多,也灵活得多。这是消费扩容的第二个要点:** 乱序消费模式下可以通过增加 worker 数量来提升消费能力 **。

   通过上面两个方法,RocketMQ 的消费能力 = worker 数量 * 机器(实例)数量。所以大家以后在遇到类似的情况下,就不要盲目增加机器数量了。


Reference

  1. RocketMQ 负载均衡特性
  2. RocketMQ Operations_Consumer

Welcome to my other publishing channels