RocketMQ组成架构

480 阅读7分钟

我正在参与掘金新人创作活动,一起开启写作之路

主要有四大核心组成部分:NameServer、Broker、Producer以及Consumer四部分。

NameServer

主要负责对于源数据的管理。

  1. 管理brokers:broker服务器启动时会注册到NameServer上,并且两者之间保持心跳监测机制,以此来保证NameServer知道broker的存活状态;
  2. 路由信息管理:每一台NameServer都存有全部的broker集群信息和生产者/消费者客户端的请求信息; NameServer用于存储Topic、Broker关系信息,功能简单,稳定性高。多个NameServer之间相互没有通信,单台NameServer宕机不影响其他NameServer与集群;即使整个NameServer集群宕机,已经正常工作的Producer,Consumer,Broker仍然能正常工作,但新起的Producer, Consumer,Broker就无法工作。

NameServer压力不会太大,平时主要开销是在维持心跳和提供Topic-Broker的关系数据。但有一点需要注意,Broker向NameServer发心跳时,会带上当前自己所负责的所有Topic信息,如果Topic个数太多(万级别),会导致一次心跳中,就Topic的数据就几十M,网络情况差的话,网络传输失败,心跳失败,导致NameServer误认为Broker心跳失败。

Broker

消息中转角色,负责存储消息,转发消息。底层的通信和连接都是基于Netty实现的请求分发:是client的入口,接收来自生产者消费者的请求

  • client管理:管理客户(产品/消费者)并维护消费者的主题订阅。
  • 数据存储:提供简单的api来查询磁盘上的临时数据
  • 高可用:主从节点间同步数据保证高可用 Broker优势
  1. 负载均衡:Broker上存Topic信息,Topic由多个队列组成,队列会平均分散在多个Broker上,而Producer的发送机制保证消息尽量平均分布到所有队列中,最终效果就是所有消息都平均落在每个Broker上。
  2. 动态伸缩能力(非顺序消息):Broker的伸缩性体现在两个维度:Topic, Broker。
  • Topic维度:假如一个Topic的消息量特别大,但集群水位压力还是很低,就可以扩大该Topic的队列数,Topic的队列数跟发送、消费速度成正比。
  • Broker维度:如果集群水位很高了,需要扩容,直接加机器部署Broker就可以。Broker起来后想Namesrv注册,Producer、Consumer通过Namesrv发现新Broker,立即跟该Broker直连,收发消息。
  1. 高可用&高可靠
  • 高可用:集群部署时一般都为主备,备机实时从主机同步消息,如果其中一个主机宕机,备机提供消费服务,但不提供写服务。
  • 高可靠:所有发往broker的消息,有同步刷盘和异步刷盘机制;同步刷盘时,消息写入物理文件才会返回成功,异步刷盘时,只有机器宕机,才会产生消息丢失,broker挂掉可能会发生,但是机器宕机崩溃是很少发生的,除非突然断电

Producer

消息生产者,负责产生消息,一般由业务系统负责产生消息。
Producer启动时,需要指定Namesrv的地址,从Namesrv集群中选一台建立长连接。如果该Namesrv宕机,会自动连其他Namesrv。直到有可用的Namesrv为止。生产者每30秒从Namesrv获取Topic跟Broker的映射关系,更新到本地内存中。再跟Topic涉及的所有Broker建立长连接,每隔30秒发一次心跳。 RocketMQ提供三种发送方式:

  1. 同步:在广泛的场景中使用可靠的同步传输,如重要的通知信息、短信通知、短信营销系统等。
  2. 异步:异步发送通常用于响应时间敏感的业务场景,发送出去即刻返回,利用回调做后续处理。
  3. 一次性:一次性发送用于需要中等可靠性的情况,如日志收集,发送出去即完成,不用等待发送结果,回调等等。 负载均衡
    生产者发送时,会自动轮询当前所有可发送的broker,一条消息发送成功,下次换另外一个broker发送,以达到消息平均落到所有的broker上。

Consumer

消息消费者,负责消费消息,一般是后台系统负责异步消费。 消费者的消费方式:

  • 广播消费:每个消费者消费Topic下的所有队列。
  • 集群消费:一个topic可以由同一个ID下所有消费者分担消费。具体例子:假如TopicA有6个队列,某个消费者ID起了2个消费者实例,那么每个消费者负责消费3个队列。如果再增加一个消费者ID相同消费者实例,即当前共有3个消费者同时消费6个队列,那每个消费者负责2个队列的消费。 消费者消费方式:
  1. PullConsumer:主动从brokers经纪人处拉取消息。一旦拉取到批量的数据,用户应用的消费进程初始化。
  2. PushConsumer:封装消息拉取、消费进程和内部其他工作维护,留下一个回调接口让用户实现,当消息到达时即可执行用户实现逻辑。所以 Push 称为被动消费类型,但从实现上看还是从消息服务器中拉取消息,不同于 Pull 的是 Push 首先要注册消费监听器,当监听器处触发后才开始消费消息。

Topic:主题,是生产者发送的消息和消费者拉取的消息的规类。Topic与生产者和消费者都是非常松散的关系,一个topic可以有0个或者1个或者多个生产者向其发送消息,换句话说,一个生产者可以同时向不同和topic发送消息。从消费者的解度来说,一个topic可能被0个或者一个或者多个消费组订阅,类似的,一个消费组可以订阅一个或者多个主题只要这个消费组的实例保持他们的订阅一致。

Message:消息,要传输的信息。一个message必须有一个主题,主题可以看做是你的信件要邮寄的地址。一个消息也可以拥有一个可选的tag和额处的键值对。如你可能需要给你的message设置一个业务key和要boker服务上查找此message,以便在开发期间查找问题

Message Queue:消息队列,一个主题被化分为一个或者多个子主题(sub-topics),“消息队列”.
Offset:在RocketMQ 中,所有消息队列都是持久化,长度无限的数据结构,所谓长度无限是指队列中的每个存储单元都是定长,访问其中的存储单元使用Offset 来访问,Offset 为 java long 类型,64 位,理论上在 100年内不会溢出,所以认为是长度无限。 也可以认为 Message Queue 是一个长度无限的数组,Offset 就是下标

Tag:标签,换而言之为子主题,为用户提供额外的灵活性。使用tag,同一业务模块不同目的的messages就可以用相同topic不同tag来标识。比如交易消息又可以分为:交易创建消息、交易完成消息等,一条消息可以没有 Tag 。Tags有益于保持你的代码干净而条理清晰,同时促进使用RocketMQ提供的查询系统的效率。

Message Order:当使用DefaultMQPushConsumer时,你需要确定消费消息的方式: Orderly:顺序地消费消息即表示消费的消息顺序同生产者发送的顺序一致。 Concurrently:并行消费。指定此方式消费,信息消费的最大并行数量仅受限于每个消费者客户端指定的线程池。

Consumer Group:消费组,把同样角色的消费者分组到一起即消费者组

Producer Group:生产者组,是将同样角色生产者的分组在一起。

一次完整的通信流程是怎样的

Producer 与 NameServer集群中的其中一个节点(随机选择)建立长连接,定期从 NameServer 获取 Topic 路由信息,并向提供 Topic 服务的 Broker Master 建立长连接,且定时向 Broker 发送心跳。

Producer 只能将消息发送到 Broker master,但是 Consumer 则不一样,它同时和提供 Topic 服务的 Master 和 Slave建立长连接,既可以从 Broker Master 订阅消息,也可以从 Broker Slave 订阅消息。