RocketMQ源码分析(一)总体架构

1 系列

  • 总体架构图
  • producer端发送消息
  • broker端接收消息
  • broker端消息的存储
  • consumer消费消息
  • 分布式事务的实现
  • 定时消息的实现
  • 关于顺序消费
  • 关于重复消息
  • 关于高可用

2 总体架构图

先来看下官方给出的总体架构图c#

RocketMQ的架构图

  • Producer集群:拥有相同的producerGroup,通常来说,Producer没必要要有集群的概念,这里的集群仅仅在RocketMQ的分布式事务中有用到微信

  • Name Server集群:提供topic的路由信息,路由信息数据存储在内存中,broker会定时的发送路由信息到nameserver中的每个机器,来进行更新,因此name server集群能够简单理解为无状态(实际状况下可能存在每一个nameserver机器上的数据有短暂的不一致现象,可是经过定时更新,大部分状况下都是一致的)架构

  • broker集群:一个集群有一个统一的名字,即brokerClusterName,默认是DefaultCluster。一个集群下有多个master,每一个master下有多个slave。master和slave算是一组,拥有相同的brokerName,不一样的brokerId,master的brokerId是0,而slave则是大于0的值。master和slave之间能够进行同步复制或者是异步复制。并发

  • consumer集群:拥有相同的consumerGroup。负载均衡

下面来讲说他们之间的通讯关系异步

  • Producer和Name Server:每个Producer会与Name Server集群中的一台机器创建TCP链接,会从这台Name Server上拉取路由信息。分布式

  • Producer和broker:Producer会和它要发送的topic相关的master类型的broker创建TCP链接,用于发送消息以及定时的心跳信息。broker中会记录该Producer的信息,供查询使用.net

  • broker与Name Server:broker(不论是master仍是slave)会和每一台Name Server机器来创建TCP链接。broker在启动的时候会注册本身配置的topic信息到Name Server集群的每一台机器中。即每一台Name Server都有该broker的topic的配置信息。master与master之间无链接,master与slave之间有链接线程

  • Consumer和Name Server:每个Consumer会和Name Server集群中的一台机器创建TCP链接,会从这台Name Server上拉取路由信息,进行负载均衡设计

  • Consumer和broker:Consumer能够与master或者slave的broker创建TCP链接来进行消费消息,Consumer也会向它所消费的broker发送心跳信息,供broker记录。

3 kafka的架构图

来看下kafka的总体架构图

kafka的总体架构图

来看看他们之间的链接关系

  • Producer和broker:Producer会和它所要发送的topic相关的broker创建TCP链接,并经过broker进行其余broker的发现(这个没有依赖ZooKeeper进行服务发现)

  • broker和ZooKeeper:broker会将本身注册在ZooKeeper上,同时依赖ZooKeeper作一些分布式协调

  • Consumer和ZooKeeper:Consumer会将本身注册在ZooKeeper上,同时依赖ZooKeeper进行broker发现以及将消费offset记录在ZooKeeper上

  • Consumer和Broker:Consumer链接topic相关的broker进行消息的消费

4 RocketMQ和kafka的对比

4.1 消息的存储

咱们知道topic是一类消息的统称,为了提升消息的写入和读取并发能力,将一个topic的消息进行拆分,能够分散到多个broker中。kafka上称为分区,而RocketMQ称为队列。

对于kafka:为了防止一个分区的消息文件过大,会拆分红一个个固定大小的文件,因此一个分区就对应了一个目录。分区与分区之间是相互隔离的。

对于RocketMQ:则是全部topic的数据混在一块儿进行存储,默认超过1G的话,则从新建立一个新的文件。消息的写入过程即写入该混杂的文件中,而后又有一个线程服务,在不断的读取分析该混杂文件,将消息进行分拣,而后存储在对应队列目录中(存储的是简要信息,如消息在混杂文件中的offset,消息大小等)

因此RocketMQ须要2次寻找,第一次先找队列中的消息概要信息,拿到概要信息中的offset,根据这个offset再到混杂文件中找到想要的消息。而kafka则只须要直接读取分区中的文件便可获得想要的消息。

看下这里给出的RocketMQ的日志文件图片分布式开放消息系统(RocketMQ)的原理与实践

RocketMQ的消息存储

这里我本身认为RocketMQ的作法仍是值得商榷的,这样的作法在同步刷盘、异步刷盘时效率相对高些(因为量大因此效率相对高些),可是所有的topic往一个文件里面写,每次写入要进行加锁控制,原本不相干的topic却相互影响,就下降的写入的效率。这个锁的粒度有点大了,我本身认为应该一个队列对应一个CommitLog,这样作就是减小锁的粒度问题。

4.1 Prdocuer端的服务发现

就是Producer端如何来发现新的broker地址。

对于kafka来讲:Producer端须要配置broker的列表地址,Producer也从一个broker中来更新broker列表地址(从中发现新加入的broker)。

对于RocketMQ来讲:Producer端须要Name Server的列表地址,同时还能够定时从一个HTTP地址中来获取最新的Name Server的列表地址,而后从其中的一台Name Server来获取所有的路由信息,从中发现新的broker。

4.1 消费offset的存储

对于kafka:Consumer将消费的offset定时存储到ZooKeeper上,利用ZooKeeper保障了offset的高可用问题。

对于RocketMQ:Consumer将消费的offset定时存储到broker所在的机器上,这个broker优先是master,若是master挂了的话,则会选择slave来存储,broker也是将这些offset定时刷新到本地磁盘上,同时slave会定时的访问master来获取这些offset。

4.2 consumer负载均衡

对于负载均衡,在出现分区或者队列增长或者减小的时候、Consumer增长或者减小的时候都会进行reblance操做。

对于RocketMQ:客户端本身会定时对全部的topic的进行reblance操做,对于每一个topic,会从broker获取全部Consumer列表,从broker获取队列列表,按照负载均衡策略,计算各自负责哪些队列。这种就要求进行负载均衡的时候,各个Consumer获取的数据是一致的,否则不一样的Consumer的reblance结果就不一样。

对于kafka:kafka以前也是客户端本身进行reblance,依靠ZooKeeper的监听,来监听上述2种状况的出现,一旦出现则进行reblance。如今的版本则将这个reblance操做转移到了broker端来作,不但解决了RocketMQ上述的问题,同时减轻了客户端的操做,是的客户端更加轻量级,减小了和其余语言集成的工做量。详细见这篇文章Kafka设计解析(四):Kafka Consumer解析

4.3 Name Server和ZooKeeper

Name Server和ZooKeeper的做用大体是相同的,从宏观上来看,Name Server作的东西不多,就是保存一些运行数据,Name Server之间不互连,这就须要broker端链接全部的Name Server,运行数据的改动要发送到每个Name Server来保证运行数据的一致性(这个一致性确实有点弱),这样就变成了Name Server很轻量级,可是broker端就要作更多的东西了。

而ZooKeeper呢,broker只须要链接其中的一台机器,运行数据分发、一致性都交给了ZooKeeper来完成。

目前先就这几个大的组件进行简单的对比,后续会对某些细节进行详细说明。

欢迎关注微信公众号:乒乓狂魔

微信公众号

相关文章
相关标签/搜索