Queue是RocketMQ中的另一个重要概念。在对该概念进行分析介绍前,我们先来看一张图:
为了简化分析过程,在这张图中没有包含Slave Broker。Broker1,Broker2和Broker3都是Master Broker。如果各Master Broker有Slave Broker,Slave Broker中的结构和其对应的Master Broker完全相同。
从本质上来说,RocketMQ中的Queue是数据分片的产物。为了更好地理解Queue的定义,我们还需要引入一个新的概念:Topic分片。在分布式数据库和分布式缓存领域,分片概念已经有了清晰的定义。同理,对于RocketMQ,一个Topic可以分布在各个Broker上,我们可以把一个Topic分布在一个Broker上的子集定义为一个Topic分片。对应上图,TopicA有3个Topic分片,分布在Broker1,Broker2和Broker3上,TopicB有2个Topic分片,分布在Broker1和Broker2上,TopicC有2个Topic分片,分布在Broker2和Broker3上。将Topic分片再切分为若干等分,其中的一份就是一个Queue。每个Topic分片等分的Queue的数量可以不同,由用户在创建Topic时指定。
我们知道,数据分片的主要目的是突破单点的资源(网络带宽,CPU,内存或文件存储)限制从而实现水平扩展。RocketMQ在进行Topic分片以后,已经达到水平扩展的目的了,为什么还需要进一步切分为Queue呢。解答这个问题还需要从负载均衡说起。以消息消费为例,借用RocketMQ官方文档中的Consumer负载均衡示意图来说明:
如图所示,TOPIC_A在一个Broker上的Topic分片有5个Queue,一个ConsumerGroup内有2个Consumer按照集群消费的方式消费消息,按照平均分配策略进行负载均衡得到的结果是:第一个Consumer消费3个Queue,第二个Consumer消费2个Queue。如果增加Consumer,每个Consumer分配到的Queue会相应减少。RocketMQ的负载均衡策略规定:Consumer数量应该小于等于Queue数量,如果Consumer超过Queue数量,那么多余的Consumer将不能消费消息。
在一个ConsumerGroup内,Queue和Consumer之间的对应关系是一对多的关系:一个Queue最多只能分配给一个Consumer,一个Cosumer可以分配得到多个Queue。这样的分配规则,每个Queue只有一个消费者,可以避免消费过程中的多线程处理和资源锁定,有效提高各Consumer消费的并行度和处理效率。
由此,我们可以给出Queue的定义:Queue是Topic在一个Broker上的分片等分为指定份数后的其中一份,是负载均衡过程中资源分配的基本单元。