转载:https://blog.csdn.net/binzhaomobile/article/details/73332463
RocketMQ概念模型
一 前言
对于任何一款中间件产品而言,清晰的概念模型是帮助用户正确理解使用它的关键。由于RocketMQ并没有遵循业界现有的JMS或AMQP规范,而且功能集比后两者更加丰富,描述该中间件产品的概念模型是一项比较有挑战的任务。RocketMQ的官方文档《RocketMQ 原理简介》对产品的概念模型给出了比较简洁而清晰的介绍。
本文将针对用户在使用RocketMQ过程中需要重点理解的一些概念进行归纳总结和补充说明。
二 概念模型
1 Topic
首先需要提到的概念是Topic。Topic是RocketMQ中的一个重要概念,RocketMQ的各组件都是围绕着Topic建立起对应关系的。
在RocketMQ官方文档和本文中, Topic在不同的语境下被赋予了两种不同的语义:
1) 消息的Topic属性值
在描述Consumer的订阅设置信息或消息的属性时。
2) Topic属性为某个值的消息(单个消息或消息集合)
在描述Broker,Producer和Consumer的对应关系,Queue以及负载均衡策略时。
2 Broker,Producer和Consumer
如果不考虑负载均衡和高可用,最简单的Broker,Producer和Consumer之间的关系如下图所示:
为了实现消息队列的水平扩展和高可用,RocketMQ引入了Producer Group, Consumer Group, Master/Slave Broker和BrokerCluster概念。它们之间的关系进一步演化为:
其中,Broker Group是为了方便指代一个Master Broker及其Slave Broker组成的集合,本文引入的一个新概念,类似于MongoDB中的复制集(Replica Set)概念。Brokr Group的定义是:Broker名相同的一组Master/Slave Broker,其中包含一个Master Broker(Broker Id为0)和0~N个Slave Broker(Broker Id不为0)。
在上图中我们可以看出,Producer Group、Consumer Group和Topic之间的关系的被强调了:Producer Group生产消息,Consumer Group消费消息。实际的生产和消费行为是组内的各Producer和Consumer按照一致的生产或消费逻辑负责进行的。之所以强调ProducerGroup、Consumer Group和Topic之间的关系,是因为在《RocketMQ用户指南》中,对Consumer Group或Producer Group的说明还不能引起用户对使用规则的足够重视。例如,对ConsumerGroup的说明为:“Consumer 组名,多个Consumer如果属于一个应用,订阅同样的消息,且消费逻辑一致,则应该将它们归为同一组”。而背后的含义其实是:如果一个Consumer Group内的两个Consumer订阅不相同的Topic,会导致各Consumer只消费到一部分Topic。
另外,在上图中Broker Cluster和Broker Group之间的关系定义成1:N的关系,是为了表明两者之间存在包含关系。在RocketMQ的代码中并没有限制一个Broker Group必须从属于一个Broker Cluster。
各概念之间的主要对应关系为:
1) ProducerGroup和Topic之间的关系是多对多的关系
一个Producer Group内的Producer可以生产多个不同Topic的消息;
一个Topic的消息也可以由多个Producer Group内的Producer生产。
2) BrokerGroup和Topic之间的关系是多对多的关系
一个Broker Group可以为多个Topic提供服务;
一个Topic可以由一个或多个Broker Group提供服务。
一个Topic由多个Broker Group提供服务即《RocketMQ用户指南》中提到的多Master,或多Master多Slave模式。
一个Topic由一个Broker Group提供服务即《RocketMQ用户指南》中提到的单Master模式(包含Slave或不包含Slave)。
3) ConsumerGroup和Topic之间的关系是多对多的关系
一个Consumer Group内的Consumer可以消费多个Topic的消息;
一个Topic的消息也可以由多个Consumer Group内的Consumer消费。
在集群消费模式下,一个Topic的消息被多个Consumer Group消费的行为比较特殊,在JMS标准中没有与其对应的消费模式。可以描述为:每个Consumer Group会分别将该Topic的消息消费一遍;在每一个Consumer Group内,各Consumer通过负载均衡的方式消费该Topic的消息。下面的例子可以说明这种消费模式的应用场景:
基于微服务架构的拼车出行应用中,用户完成一次拼车行为后系统需要完成两个动作:扣款和增加用户的积分。拼车管理,支付管理和积分管理被解耦为三个独立的微服务。
应用为支付管理模块和积分管理模块分别指定一个Consumer Group,两个Consumer Group都订阅“拼车结束”对应Topic的消息。拼车结束后,拼车管理模块只需要发出一个“拼车结束”消息就能够驱动另外的两个业务模块分别完成后续的工作。
将一个Consumer Group对应业务系统中的一个独立的业务模块,是一个比较值得推荐的ConsuerGroup划分方法。
3 Topic,Topic分片和Queue (重要)
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呢?
解答这个问题还需要从负载均衡说起。以消息消费为例,借用Rocket MQ官方文档中的Consumer负载均衡示意图来说明:
如图所示,TOPIC_A在一个Broker上的Topic分片有5个Queue,一个Consumer Group内有2个Consumer按照集群消费的方式消费消息,按照平均分配策略进行负载均衡得到的结果是:第一个 Consumer 消费3个Queue,第二个Consumer 消费2个Queue。如果增加Consumer,每个Consumer分配到的Queue会相应减少。Rocket MQ的负载均衡策略规定:Consumer数量应该小于等于Queue数量,如果Consumer超过Queue数量,那么多余的Consumer 将不能消费消息。
在一个Consumer Group内,Queue和Consumer之间的对应关系是一对多的关系:一个Queue最多只能分配给一个Consumer,一个Cosumer可以分配得到多个Queue。这样的分配规则,每个Queue只有一个消费者,可以避免消费过程中的多线程处理和资源锁定,有效提高各Consumer消费的并行度和处理效率。
由此,我们可以给出Queue的定义:
Queue是Topic在一个Broker上的分片等分为指定份数后的其中一份,是负载均衡过程中资源分配的基本单元。