走进 RocketMQ- 整体架构与设计
前言
Halo,我是白裤。
RocketMQ,历经十余年的大规模场景磨练,作为业内共识的金融级可靠业务消息首选方案,被广泛应用于互联网、大数据、移动互联网、物联网等领域的业务场景,在日常开发中,我们可能只是对 RocketMQ 进行简单的使用,而对其内部工作原理与设计并没有进行深入的理解,该系列内容将带大家一起慢慢揭开这个家伙的面纱,今天我们就先了解一下 RocketMQ 的整体架构以及模型的设计和工作流程。
数据传输模型设计
在学习 RocketMQ 之前我们先看一个例子,简单了解例子中的一个模型设计。我们知道,在数据的传输中,有数据发送端、数据接收端,如下图所示:
那么如果只是这样简单的数据传输方式会存在什么问题呢?在该方式下,当数据发送端在发送大量数据请求的时候会出现一种情况,就是接收端接收不过来了,这种情况下,发送端就会被阻塞在发送阶段,这样子会严重影响发送端的发送性能,那么有什么方式可以优化一下的吗?答案是肯定的,我们可以在传输过程中增加一个队列,如下图所示:
让发送端将数据直接丢到队列中,接收端到队列中拿数据,这样的话,发送端就不必等待接收端的处理,只要把数据往队列一丢,完事儿。而接收端呢,则不用考虑一下子需要处理接收这么多的数据请求,只需要从队列中一个个拿出来慢慢处理即可。在这里呢,其实队列就起到了异步、缓冲的作用。
接下来我们继续来看一下,现在队列模式中存在着什么问题。队列在内存中,如果我们服务宕机的话,队列里的数据是不是就啪、没了?所以还是得将数据进行持久化的吧?好,我们继续改进成如下图所示的一个架构,为队列添加一个持久化的模块:
这个时候我们的整个队列和持久化就相当于一个数据服务了,数据发送端向数据服务发送消息数据,数据接收端从数据服务接收消息数据,此时就算数据服务宕机,队列中的数据也会被持久化起来,等服务重新启动的时候,从持久化中恢复数据就可以了。这个时候我们可以想一下,如果数据服务宕机了,虽然重启服务可以恢复数据,但是在宕机的这段时间,数据服务是对外提供不了服务的,那么这段时间就会影响我们的这个业务功能,相当于数据发送端发送不了数据,数据接收端也拿不到数据,这咋搞?别慌,像这种问题属于单节点宕机的情况,我们只要保证服务的一个高可用不就好了吗?接下来我们直接开干,让我们的数据服务支持高可用,服务高可用其实有几种方式可以采取,比如主从架构,还有类似 Eureka 的集群模式等等等等,这里我们选择主从来保证这个数据服务的高可用,如下图所示:
这个时候我们可以看到,数据服务现在有主从节点,当数据服务 master 宕机的时候,从节点服务 slave 可以继续提供读请求,但是数据服务不能继续接收写请求,那么怎么办呢?此时我们可以使用多主多从的方式来保证写请求的处理,比如两主两从,这样,当其中一个 master 宕机的时候,它的 slave 节点可以继续提供数据的读取,而另外一个 master 则继续可以提供写请求,等宕机的 master 恢复重启后,只需要同步从节点 salve 的数据读取进度即可,如下图所示:
好,到这里我们的数据服务集群已经发展成两主两从的这么一个模式了,那么其实这个时候有一个问题点就是,我们的数据发送端和数据接收端具体要去哪个数据服务节点请求数据呢?具体的地址是多少呢?这个时候我们得把数据服务集群中的服务节点都要列出来吧?那么接下来我们就来为数据服务集群设计一个服务节点地址路由,这个路由信息我们把它放到一个服务中,提供接口给数据发送端和数据接收端去调用获取,然后还要提供接口给数据服务集群中的服务节点去注册更新我们的路由信息,如下图所示:
这样我们的数据发送端和数据接收端就可以从路由信息服务中获取到最新的数据服务节点信息,然后根据自己的需求将数据发送到指定的数据服务中或者从指定的数据服务中获取数据信息。但现在其实我们很容易就可以看到当前这个路由信息服务的弊端,没错,那就是路由信息服务单节点问题,哈哈,现在是不是对于单节点问题知道怎么去设计解决了?是的,就是集群化。其实这里的路由信息注册与发现很像咱们微服务中的注册中心,那像注册中心有挺多种组件可以去实现的,比如 Eureka、Consul、Zookeeper、Nacos 等等,我们实现的路由信息服务集群化可以像 Eureka 一样,就是服务多节点化来完成服务集群化,我们可以将路由信息服务部署多个节点在多台机器上,然后彼此间也不需要通信,只要与数据服务集群以及数据发送端和接收端可以通信就行,那么我们将路由信息服务集群化设计成如下图所示:
到这里,其实我们的这个数据从发送到获取的这么一个架构的设计演变就差不多了,在当前的这么一个设计下,数据的传输基本没啥大的问题。
RocketMQ 模型设计
通过上文中的例子,我们其实已经大概地了解到了 RocketMQ 模型的一个基础的雏形,接下来让我们一起来看下 RocketMQ 模型的真面目吧。
上图就是 RocketMQ 的一个技术架构图,我们可以看到,其实跟我们前面所讲的例子是不是很类似?好,那么我们接下来分析一下 RocketMQ 的技术架构的组成模块。RocketMQ 分为四大模块:NameServer、Broker、Producer、Consumer。
NameServer
NameServer 类似微服务中的注册中心,它为 Broker 提供了注册与发现,维护着路由信息,同时还检测着 Broker 的心跳以便保持着最新的路由信息,由于它是无状态节点,所以它是可以用集群的方式部署的,节点彼此之间是不互相通信的,但 Broker 会与每个 NameServer 都保持着通信,比如注册、心跳检测,所以每个 NameServer 中都拥有所有 Broker 的路由信息,当一个 NameServer 节点挂了,Broker、Producer、Consumer 还可以跟其他活着的 NameServer 节点通信,除此之外,NameServer 还为 Producer 和 Consumer 提供了队列信息查询的功能,Producer 要将 Topic 对应的消息发送到哪里,Consumer 要去哪里消费 Topic 对应的消息,这些 NameServer 都可以告诉它们。
Broker
Broker 负责的功能比较多,其中最主要的功能是处理消息的投递与消费、消息的存储与同步、消息的查询。在消息的投递和消费方面,Broker 有专门的客户端管理模块来处理消息的发送与接收以及消费者 Topic 订阅信息的维护;消息的存储与同步方面,Broker 不仅为其提供了持久化的处理模块,而且提供保证主从节点之间的数据同步机制;在消息的查询方面,Broker 有专门的消息索引模块去处理大量消息的查询从而提高查询效率。
Producer
Producer 负责消息的发送,从 NameServer 中获取 Topic 对应的 Broker 路由信息进行消息的发送。
Consumer
Consumer 指的是消息的消费者,它有两种消费方式:集群方式和广播方式,同时还支持 push 和 pull 的模式进行消费,pull 我们都知道,就是主动拉取数据,push 的话其实是有个长连接来进行数据的获取。
以上就是 RocketMQ 模型中各大组件的介绍。
RocketMQ 工作流程
接下来我们来看下 RocketMQ 的整体的一个大概的工作流程是怎么样的,如下图所示:
第一步(1):
NameServer 集群启动,当 NameServer 启动之后,NameServer 会开始监听客户端的请求,比如 Producer 拉取路由信息请求、Broker 的注册请求和心跳连接、Consumer 拉取路由信息请求。
第二步(2,3):
Broker 集群启动,然后 Broker 会与 NameServer 集群中所有的节点建立长连接,注册 Broker 的地址信息以及存储在 Broker 上面的 Topic 信息,这个时候 NameServer 上面就会将这些信息保存下来,在此之后,Broker 会与 NameServer 保持长连接并且定时会发送心跳来同步信息。另外,Broker 的 Master 节点与 Slave 节点会保持数据同步,以便支持数据的备份。同时 Broker 还会监听处理 Producer 消息投递和 Consumer 拉取消息的请求。
第三步(4):
Topic 创建,Topic 类似于 Producer 与 Consumer 的一个约定,彼此说好消息发送到哪一个 Topic 下,从哪一个 Topic 中消费消息。关于 Topic 的创建有两种方式,一种是手动创建,我们可以在 console 控制台去创建并且指定 Topic 需要在那些 Broker 上存储,另外一种就是在消息发送的时候,自动创建 Topic。
第四步(5,6,7):
启动 Producer 并发送消息,Producer 启动时会跟 NameServer 集群中的随机节点建立长连接,拉取 Topic 路由信息,因为它需要知道消息应该发送到哪个 Broker 上去,因为 Topic 可能在多个 Broker 上分配了队列,那么 Producer 会根据一定的策略选择队列,与队列所在的 Broker 节点建立长连接进行消息的发送。
第五步(8,9,10):
启动 Consumer 并消费消息,Consumer 启动时也会跟 NameServer 集群中的随机节点建立长连接,拉取订阅的 Topic 路由信息,到对应的 Broker 上获取消息内容。
小结
本章节我们首先了解了一个简单的数据传输的例子,由最初的数据传输双端即数据发送端和数据接收端慢慢演变成一个拥有数据持久化、数据服务高可用、拥有路由服务的这么一个设计,我们简单总结一下这个历程:
[数据发送]-[数据接收]
[数据发送]-[队列]-[数据接收]
[数据发送]-[数据服务(队列、数据持久化、单节点)]-[数据接收]
[数据发送]-[数据服务(队列、数据持久化、服务主从)]-[数据接收]
[数据发送]-[数据服务(队列、数据持久化、服务集群化)]-[数据接收]
[数据发送]-[数据服务(队列、数据持久化、服务集群化)]-[路由服务(单节点)]-[数据接收]
[数据发送]-[数据服务(队列、数据持久化、服务集群化)]-[路由服务(集群化)]-[数据接收]
然后我们介绍了 RocketMQ 的一个模型设计,介绍了 RocketMQ 四大组件模块 NameServer、Broker、Producer、Consumer,分别讲述了各个组件的作用。紧接着我们了解了 RocketMQ 的一个大概的工作流程(具体每个组件的工作细节我们后面在源码解析阶段再进行了解)。
好了,今天我们就学习到这里,下一次我们来学习 RocketMQ 的部署模式以及自己动手进行 RocketMQ 的部署与实战。
版权声明: 本文为 InfoQ 作者【白裤】的原创文章。
原文链接:【http://xie.infoq.cn/article/ff699af755ae83057e5605bf2】。
本文遵守【CC-BY 4.0】协议,转载请保留原文出处及本版权声明。
评论