RocketMQ(二):领域与消息传输模型
RocketMQ 是一款典型的分布式架构下的中间件,使用异步通信方式和发布订阅的消息传输模型。
RocketMQ的异步通信,系统拓扑简单、上下游耦合较弱,主要应用于异步解耦,流量削峰填谷等场景。
1、领域模型
RocketMQ 中消息的生命周期主要分为消息生产、消息存储、消息消费三部分。生产者生产消息并发送至 RocketMQ 服务端,消息被存储在服务端的主题中,消费者通过订阅主题消费消息。
1、消息生产者
生产者(Producer):RocketMQ 中用于产生消息的运行实体。
生产者(Producer)一般集成于业务调用链路的上游,将业务消息按照要求封装成 RocketMQ 的消息(Message)并发送至服务端。
2、消息存储
2.1、Topic - 主题
Topic是 RocketMQ 中消息传输和存储的顶层容器,用于标识同一类业务逻辑的消息。
Topic是消息传输和存储的分组容器,主题内部由多个队列组成,消息的存储和水平扩展实际是通过主题内的队列实现的。
1、作用
定义数据的分类隔离: 在 RocketMQ 的方案设计中,建议将不同业务类型的数据拆分到不同的主题中管理,通过主题实现存储的隔离性和订阅隔离性。
定义数据的身份和权限:RocketMQ 的消息本身是匿名无身份的,同一分类的消息使用相同的主题来做身份识别和权限管理。
2、逻辑概念
主题是 Apache RocketMQ 的顶层存储,所有消息资源的定义都在主题内部完成,但主题是一个逻辑概念,并不是实际的消息容器。
主题内部由多个队列组成,针对主题的所有约束和属性设置,最终也是通过主题内部的队列来实现。
3、内部属性
1、主题名称
定义:主题的名称,用于标识主题,主题名称集群内全局唯一。
取值:由用户创建主题时定义。
2、队列列表
定义:队列作为主题的组成单元,是消息存储的实际容器,一个主题内包含一个或多个队列,消息实际存储在主题的各队列内。
取值:系统根据队列数量给主题分配队列,队列数量创建主题时定义。
约束:一个主题内至少包含一个队列。
3、消息类型
RocketMQ 支持的主题类型如下:
3.1、Normal: 普通消息
3.2、FIFO:顺序消息
RocketMQ 通过消息分组MessageGroup标记一组特定消息的先后顺序,可以保证消息的投递顺序严格按照消息发送时的顺序。
3.3、Delay:定时/延时消息
通过指定延时时间控制消息生产后不要立即投递,而是在延时间隔后才对消费者可见。
3.4、Transaction:事务消息
RocketMQ 支持分布式事务消息,支持应用数据库更新和消息调用的事务一致性保障。
在RocketMQ中,每个Topic只支持一种消息类型。
2.2、Message Queue - 消息队列
队列Queue是 RocketMQ 中消息存储和传输的实际容器,也是 RocketMQ 消息的最小存储单元,RocketMQ 的所有主题都是由多个队列组成。
1、消息队列作用
存储顺序性 :队列具备顺序性,即消息按照进入队列的顺序写入存储,同一队列间的消息存在顺序关系,队列头部为最早写入的消息,队列尾部为最新写入的消息。
消息在队列中的位置和消息之间的顺序通过位点(Offset)进行标记管理。
2、存储容器
RocketMQ 默认提供消息可靠存储机制,所有发送成功的消息都被持久化存储到队列中,配合生产者和消费者客户端的调用可实现至少投递一次。
RocketMQ 队列模型和Kafka的分区(Partition)模型类似。在 Apache RocketMQ 消息收发模型中,队列属于主题的一部分,虽然所有的消息资源以主题粒度管理,但实际的操作实现是面向队列。例如,生产者指定某个主题,向主题内发送消息,但实际消息发送到该主题下的某个队列中。
RocketMQ 中通过修改队列数量,以此实现横向的水平扩容和缩容。
2.3、Message - 消息
消息是 RocketMQ 中的最小数据传输单元。生产者将业务数据的负载和拓展属性包装成消息发送到 RocketMQ 服务端,服务端将消息投递到消费端进行消费。
1、消息的特点
1.1、不可变
消息产生后,内容不会发生改变,即使经过传输链路的控制也不会发生变化,消费端获取的消息都是只读消息视图。
1.2、持久化
RocketMQ 会默认对消息进行持久化,即将接收到的消息存储到 RocketMQ 服务端的存储文件中,保证消息的可回溯性和系统故障场景下的可恢复性。
2、内部属性
2.1、主题名称 - TOPIC
当前消息所属的主题的名称。集群内全局唯一。
2.2、消息类型
当前消息的类型,RocketMQ 支持的消息类型如下:Normal、FIFO、Delay、Transaction。
2.3、消息队列
实际存储当前消息的队列。
2.4、消息位点
当前消息存储在队列中的位置。
2.5、消息ID
消息的唯一标识,集群内每条消息的ID全局唯一。生产者客户端系统自动生成。固定为数字和大写字母组成的32位字符串。
2.6、索引Key列表
消息的索引键,可通过设置不同的Key区分消息和快速查找消息。
2.7、过滤标签Tag(可选)
消息的过滤标签。消费者可通过Tag对消息进行过滤,仅接收指定标签的消息。一条消息仅支持设置一个标签。
2.8、定时时间
定义:定时场景下,消息触发延时投递的毫秒级时间戳。由消息生产者定义。最大可设置定时时长为40天。
2.9、消息发送时间
消息发送时,生产者客户端系统的本地毫秒级时间戳。消息发送时间是以客户端系统时钟为准。
2.10、消息保存时间戳
定义:消息在 RocketMQ 服务端完成存储时,服务端系统的本地毫秒级时间戳。 对于定时消息和事务消息,消息保存时间指的是消息生效对消费方可见的服务端系统时间。
2.11、消费重试次数
定义:消息消费失败后,RocketMQ 服务端重新投递的次数。每次重试后,重试次数加1。由服务端系统标记。首次消费,重试次数为0;消费失败首次重试时,重试次数为1。
2.12、消息负载
业务消息的实际报文数据。由生产者负责序列化编码,按照二进制字节传输。
3、消息消费
3.1、消费者分组(ConsumerGroup)
消费者分组:用于统一管理底层运行的多个消费者(Consumer),是 RocketMQ 系统中承载多个消费行为一致的消费者的负载均衡分组。
消费者分组是一个逻辑概念,同一个消费组的多个消费者必须保持消费逻辑和配置一致,共同分担该消费组订阅的消息,实现消费能力的水平扩展。
1、消费行为
同一分组下的多个消费者将按照分组内统一的消费行为和负载均衡策略消费消息。
1.1、订阅关系
RocketMQ 以消费者分组的粒度管理订阅关系,实现订阅关系的管理和追溯。
2.2、投递顺序性
RocketMQ 的服务端将消息投递给消费者消费时,支持顺序投递和并发投递,投递方式在消费者分组中统一配置。
1.3、消费重试策略
消费者消费消息失败时的重试策略,包括重试次数、死信队列设置等。
2、内部属性
2.1、消费者分组名称
消费者分组的名称,用于区分不同的消费者分组。集群内全局唯一。
2.2、投递顺序性
消费者消费消息时,RocketMQ 向消费者客户端投递消息的顺序。 根据不同的消费场景,RocketMQ 提供顺序投递和并发投递两种方式。 默认投递方式为并发投递。
2.3、消费重试策略
消费者消费消息失败时,系统的重试策略。消费者消费消息失败时,系统会按照重试策略,将指定消息投递给消费者重新消费。
重试策略包括:
1、最大重试次数:表示消息可以重新被投递的最大次数,超过最大重试次数还没被成功消费,消息将被投递至死信队列或丢弃。
2、重试间隔:RocketMQ 服务端重新投递消息的间隔时间。 最大重试次数和重试间隔的取值范围及默认值。重试间隔仅在PushConsumer消费类型下有效。
2.4、订阅关系
当前消费者分组关联的订阅关系集合包括消费者订阅的主题,以及消息的过滤规则等。
订阅关系由消费者动态注册到消费者分组中,RocketMQ 服务端会持久化订阅关系并匹配消息的消费进度。
3.2、消费者(Consumer)
消费者是 RocketMQ 中用来接收并处理消息的运行实体。 消费者通常被集成在业务系统中,从 RocketMQ 服务端获取消息,并将消息转化成业务系统可用的信息,供业务逻辑处理。
1、传输行为
1.1、消费者类型
RocketMQ 面向不同的开发场景提供了多样的消费者类型,包括PushConsumer类型、SimpleConsumer类型、PullConsumer类型(仅推荐流处理场景使用)等。
1.2、消费者本地运行配置
消费者根据不同的消费者类型,控制消费者客户端本地的运行配置。如消费者客户端的线程数,消费并发度等,实现不同的传输效果。
2、内部属性
2.1、消费者分组名称
当前消费者关联的消费者分组名称,消费者必须关联到指定的消费者分组,通过消费者分组获取消费行为。
2.2、客户端ID
消费者客户端的标识,用于区分不同的消费者。集群内全局唯一。
客户端ID由Apache RocketMQ 的SDK自动生成,主要用于日志查看、问题定位等运维场景,不支持修改。
2.3、通信参数
接入点信息(必选):连接服务端的接入地址,用于识别服务端集群。 接入点必须按格式配置,建议使用域名,避免使用IP地址,防止节点变更无法进行热点迁移。
身份认证信息(可选):客户端用于身份验证的凭证信息。 仅在服务端开启身份识别和认证时需要传输。
请求超时时间(可选):客户端网络请求调用的超时时间。。
2.4、消费监听器
RocketMQ 服务端将消息推送给消费者后,消费者调用消息消费逻辑的监听器。使用PushConsumer类型的消费者消费消息时,消费者客户端必须设置消费监听器。
3.3、订阅关系(Subscription)
订阅关系是 RocketMQ 系统中消费者获取消息、处理消息的规则和状态配置,即RocketMQ 发布订阅模型中消息过滤、重试、消费进度的规则配置。
订阅关系以消费组粒度进行管理,消费组通过定义订阅关系控制指定消费组下的消费者如何实现消息过滤、消费重试及消费进度恢复等。
RocketMQ 的订阅关系除过滤表达式之外都是持久化的,即服务端重启或请求断开,订阅关系依然保留。
1、订阅关系注册
订阅关系由消费者分组动态注册到服务端系统,并在后续的消息传输中按照订阅关系定义的过滤规则进行消息匹配和消费进度维护。
1.1、订阅关系配置传输行为
消息过滤规则:用于控制消费者在消费消息时,选择主题内的哪些消息进行消费,设置消费过滤规则可以高效地过滤消费者需要的消息集合,灵活根据不同的业务场景设置不同的消息接收范围。
消费状态:RocketMQ 服务端默认提供订阅关系持久化的能力,即消费者分组在服务端注册订阅关系后,当消费者离线并再次上线后,可以获取离线前的消费进度并继续消费。
1.2、订阅关系判断原则
RocketMQ 的订阅关系按照消费者分组和主题粒度设计,因此,一个订阅关系指的是指定某个消费者分组对于某个主题的订阅,判断原则如下:
1、不同消费者分组对于同一个主题的订阅相互独立如下图所示,消费者分组Group A和消费者分组Group B分别以不同的订阅关系订阅了同一个主题Topic A,这两个订阅关系互相独立,可以各自定义,不受影响。
2、同一个消费者分组对于不同主题的订阅也相互独立如下图所示,消费者分组Group A订阅了两个主题Topic A和Topic B,对于Group A中的消费者来说,订阅的Topic A为一个订阅关系,订阅的Topic B为另外一个订阅关系,且这两个订阅关系互相独立,可以各自定义,不受影响。
2、内部属性
2.1、过滤类型
订阅关系中设置消息过滤规则后,系统将按照过滤规则匹配主题中的消息,只将符合条件的消息投递给消费者消费,实现消息的再次分类。
TAG过滤:按照Tag字符串进行全文过滤匹配。
SQL过滤:按照SQL语法对消息属性进行过滤匹配。
2.2、过滤表达式
自定义的过滤规则表达式。
2、通信方式
分布式系统架构思想下,将复杂系统拆分为多个独立的子模块,需要考虑子模块间的远程通信,典型的通信模式分为以下两种,一种是同步的RPC远程调用;一种是基于中间件代理的异步通信方式。
1、同步通信方式
同步RPC调用模型下,不同系统之间直接进行调用通信,每个请求直接从调用方发送到被调用方,然后要求被调用方立即返回响应结果给调用方,以确定本次调用结果是否成功。
注意:此处的同步并不代表RPC的编程接口方式,RPC也可以有异步非阻塞调用的编程方式,但本质上仍然是需要在指定时间内得到目标端的直接响应。
2、异步通信方式
异步消息通信模式下,各子系统之间无需强耦合直接连接,调用方只需要将请求转化成异步事件(消息)发送给中间代理,发送成功即可认为该异步链路调用完成,剩下的工作中间代理会负责将事件可靠通知到下游的调用系统,确保任务执行完成。该中间代理一般就是消息中间件。
3、异步通信的优势
1、系统拓扑简单由于调用方和被调用方统一和中间代理通信,系统是星型结构,易于维护和管理。
2、上下游耦合性弱上下游系统之间弱耦合,结构更灵活,由中间代理负责缓冲和异步恢复。 上下游系统间可以独立升级和变更,不会互相影响。
3、容量削峰填谷基于消息的中间代理往往具备很强的流量缓冲和整形能力,业务流量高峰到来时不会击垮下游。
3、消息传输模型
主流的消息中间件的传输模型主要为点对点模型和发布订阅模型。
1、点对点模型
点对点模型也叫队列模型,具有如下特点:
消费匿名:消息上下游沟通的唯一的身份就是队列,下游消费者从队列获取消息无法申明独立身份。
一对一通信:基于消费匿名特点,下游消费者即使有多个,但都没有自己独立的身份,因此共享队列中的消息,每一条消息都只会被唯一一个消费者处理。因此点对点模型只能实现一对一通信。
2、发布订阅模型
发布订阅模型具有如下特点:
消费独立:相比队列模型的匿名消费方式,发布订阅模型中消费方都会具备的身份,一般叫做订阅组(订阅关系),不同订阅组之间相互独立不会相互影响。
一对多通信:基于独立身份的设计,同一个主题内的消息可以被多个订阅组处理,每个订阅组都可以拿到全量消息。因此发布订阅模型可以实现一对多通信。
3、传输模型对比
点对点模型更为简单,发布订阅模型的扩展性更高。
RocketMQ 使用的传输模型为发布订阅模型,因此也具有发布订阅模型的特点。