RocketMQ的消息架构模型以及核心概念

471 阅读8分钟

我正在参加「掘金·启航计划」

详细介绍了RocketMQ的基本概念,以及消息模型。

RocketMQ是一个纯Java开发的分布式的开源消息中间件,具有高性能、高可靠、高实时、分布式等特点。RocketMQ在阿里内部经历了多次双十一的洗礼,在国内非常的流行。Rocket这个单词就是火箭的意思,那是真的非常滴快了。

2010年,阿里基于ActiveMQ 5.x(5.3之前)构建自己的分布式消息中间件Napoli。

2011年,阿里基于Kafka构建自己的分布式消息中间件MetaQ。

2012年,阿里开源了自研的最新一代分布式消息中间件RocketMQ。

2016年,阿里将RocketMQ捐献给apache基金会,成为了apache的顶级开源项目。

1 基本概念

Broker:也称Broker Server,代理服务器。消息中转角色,负责存储消息、转发消息。代理服务器在RocketMQ系统中负责接收从生产者发送来的消息并存储、同时为消费者的拉取请求作准备。代理服务器也存储消息相关的元数据,包括消费者组、消费进度偏移和主题和队列消息等。

Topic:主题,一级消息类型。表示一类消息的集合,每个主题包含若干条消息,每条消息只能属于一个主题,是RocketMQ进行消息订阅的基本单位。

Tag:消息标志,二级消息类型,用于同一主题下区分不同类型的消息。来自同一业务单元的消息,可以根据不同业务目的在同一主题下设置不同标签。标签能够有效地保持代码的清晰度和连贯性,并优化RocketMQ提供的查询系统。消费者可以根据Tag实现对不同子主题的不同消费逻辑,实现更好的扩展性。

Producer:消息生产者,属于RocketMQ客户端角色。负责生产消息,一般由业务系统负责生产消息。一个消息生产者会把业务应用系统里产生的消息发送到broker服务器。RocketMQ提供多种发送方式,同步发送、异步发送、顺序发送、单向发送。同步和异步方式均需要Broker返回确认信息,单向发送不需要。

Consumer:消息消费者,属于RocketMQ客户端角色。负责消费消息,一般是后台系统负责异步消费。一个消息消费者会从Broker服务器拉取消息、并将其提供给应用程序。从用户应用的角度而言提供了两种消费形式:拉取式消费、推动式消费。

  1. 拉取式消费(Pull Consumer):Consumer消费的一种类型,应用通常主动调用Consumer的拉消息方法从Broker服务器拉消息、主动权由应用控制。一旦获取了批量消息,应用就会启动消费过程。
  2. 推动式消费(Push Consumer):Consumer消费的一种类型,该模式下Broker收到数据后会主动推送给消费端,该消费模式一般实时性较高。(实际上还是客户端基于长轮询pull消息)。

Producer Group:同一类Producer的集合,这类Producer发送同一类消息且发送逻辑一致。如果发送的是事务消息且原始生产者在发送之后崩溃,则Broker服务器会联系同一生产者组的其他生产者实例以提交或回溯消费。一般来说同一个服务的多个实例可以作为一个Group。

Consumer Group:同一类Consumer的集合,这类Consumer通常消费同一类消息且消费逻辑一致。消费者组使得在消息消费方面,实现负载均衡和容错的目标变得非常容易。要注意的是,消费者组的消费者实例必须订阅完全相同的Topic。RocketMQ 支持两种消息模式:集群消费(Clustering)和广播消费(Broadcasting)。一般来说同一个服务的多个实例可以作为一个Group。

  1. 集群消费(Clustering):集群消费模式下,相同Consumer Group的每个Consumer实例尝试平均分摊消息。实际上是尝试平均分摊队列,一个队列只会被一个消费者消费,如果某个消费者挂掉,分组内其它消费者会接替挂掉的消费者继续消费。这是默认消费模式。
  2. 广播消费(Broadcasting):广播消费模式下,相同Consumer Group的每个Consumer实例都接收全量的消息。

Message:消息系统所传输信息的物理载体,生产和消费数据的最小单位,每条消息必须属于一个主题。RocketMQ中每个消息拥有唯一的Message ID,且可以携带具有业务标识的Message key。系统提供了通过Message ID和Message key查询消息的功能。

2 消息模型

RocketMQ的消息模型(Message Model)主要由 Producer、Broker、Consumer 三部分组成,其中Producer 负责生产消息,Consumer 负责消费消息,Broker 负责存储消息,典型的发布-订阅模式。

下面是RocketMQ的消息模型图,这比在其他地方常见的消息模型图稍微复杂一点: 在这里插入图片描述

Broker 在实际部署过程中对应一台服务器(RocketMQ服务端),每个 Broker 可以存储多个Topic的消息,每个Topic的消息也可以分片存储于不同的 Broker,Broker和Topic是多对多的关系。

Topic是一个逻辑上的概念。图中的MessageQueue,即消息队列,用于存储消息的物理地址(实际上每个Broker的所有消息的主体都存储于同一个CommitLog文件中,后面会讲到),每个Topic中的消息地址可以存储于多个 MessageQueue 中,MessageQueue又可以分布在不同的Broker上。

如果我们将图中的Broker角色去掉,就变成了更加好理解的消息模型: 在这里插入图片描述

生产者生产了消息之后会向主题发送消息,而主题中存在多个队列(类似于kafka中的分区),实际上生产者是向某一个主题中的某个队列发送消息的,生产者生产的一条消息在正常情况下只会被投递到一个主题下的一个队列中。具体选择哪个队列,以及如何自定义向某个队列发送消息的规则(通常用于实现顺序消费),后面会单独讲到。

RocketMQ的消息消费,实际上是以消费者组作为消费单元的,一个主题可以有多个消费者组同时订阅,一个消费者组中可以有多个消费者,它们共同消费某个主题的全部消息,同时,一个消费者组也能够订阅多个主题。

在消费时,RocketMQ是以队列为基本单位进行消息分配的,一个队列可以被多个消费者组消费,但是一个队列中的消息只能被某个消费者组中的某一个消费者消费(默认集群模式),但是一个消费者可以同时消费多个队列中的消息。消费者和队列是一对多的关系,如上图所示。

一般而言,消费者的数量和队列的数量一致时,消费性能最好。如果消费者小于队列数量,会出现消费者消费多个队列的情况,如果消费者大于队列数量,将会出现空闲的消费者。

Broker中维护了某个消费者组在某个队列上的消费偏移量(offset),如果消费者组中的某个消费者挂掉,分组内其它消费者会接替挂掉的消费者继续消费,消费成功之后offset向前推进,避免再次被消费。

一个主题允许有多个队列的设计的最大好处就是提高并发能力。生产者组的多个生产者可以同时向多个队列投递消息,而消费者组的多个消费者可以同时从多个队列拉取消息消费。

3 消费位移

在RocketMQ中,offset(消费位移)用来管理每个消费队列的不同消费组的消费进度。每次消费者组消费完会返回一个成功的响应,然后再把维护的offset向前推进,这样就不会出现刚刚消费过的消息再一次被消费了。

对offset的管理可以分为本地模式和远程模式,本地模式是以文本文件的形式存储在客户端,而远程模式是将数据保存到broker端,对应的数据结构分别为LocalFileOffsetStore和RemoteBrokerOffsetStore。

当消费模式为广播模式时,offset使用本地模式存储,因为每条消息会被所有的消费者消费,每个消费者管理自己的消费进度,各个消费者之间不存在消费进度的交集。

当消费模式为集群消费时,则使用远程模式管理offset,消息同样会被多个消费者组消费,但不同的是每个消费者只负责消费其中部分队列中的消息,添加或删除消费者,都会使负载发生变动,容易造成消费进度冲突,因此需要集中管理在Broker中。

相关文章:

RocketMQ

如有需要交流,或者文章有误,请直接留言。另外希望点赞、收藏、关注,我将不间断更新各种Java学习博客!