先来看下官方给出的总体架构图c#
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记录。
来看下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进行消息的消费
咱们知道topic是一类消息的统称,为了提升消息的写入和读取并发能力,将一个topic的消息进行拆分,能够分散到多个broker中。kafka上称为分区,而RocketMQ称为队列。
对于kafka:为了防止一个分区的消息文件过大,会拆分红一个个固定大小的文件,因此一个分区就对应了一个目录。分区与分区之间是相互隔离的。
对于RocketMQ:则是全部topic的数据混在一块儿进行存储,默认超过1G的话,则从新建立一个新的文件。消息的写入过程即写入该混杂的文件中,而后又有一个线程服务,在不断的读取分析该混杂文件,将消息进行分拣,而后存储在对应队列目录中(存储的是简要信息,如消息在混杂文件中的offset,消息大小等)
因此RocketMQ须要2次寻找,第一次先找队列中的消息概要信息,拿到概要信息中的offset,根据这个offset再到混杂文件中找到想要的消息。而kafka则只须要直接读取分区中的文件便可获得想要的消息。
看下这里给出的RocketMQ的日志文件图片分布式开放消息系统(RocketMQ)的原理与实践
这里我本身认为RocketMQ的作法仍是值得商榷的,这样的作法在同步刷盘、异步刷盘时效率相对高些(因为量大因此效率相对高些),可是所有的topic往一个文件里面写,每次写入要进行加锁控制,原本不相干的topic却相互影响,就下降的写入的效率。这个锁的粒度有点大了,我本身认为应该一个队列对应一个CommitLog,这样作就是减小锁的粒度问题。
就是Producer端如何来发现新的broker地址。
对于kafka来讲:Producer端须要配置broker的列表地址,Producer也从一个broker中来更新broker列表地址(从中发现新加入的broker)。
对于RocketMQ来讲:Producer端须要Name Server的列表地址,同时还能够定时从一个HTTP地址中来获取最新的Name Server的列表地址,而后从其中的一台Name Server来获取所有的路由信息,从中发现新的broker。
对于kafka:Consumer将消费的offset定时存储到ZooKeeper上,利用ZooKeeper保障了offset的高可用问题。
对于RocketMQ:Consumer将消费的offset定时存储到broker所在的机器上,这个broker优先是master,若是master挂了的话,则会选择slave来存储,broker也是将这些offset定时刷新到本地磁盘上,同时slave会定时的访问master来获取这些offset。
对于负载均衡,在出现分区或者队列增长或者减小的时候、Consumer增长或者减小的时候都会进行reblance操做。
对于RocketMQ:客户端本身会定时对全部的topic的进行reblance操做,对于每一个topic,会从broker获取全部Consumer列表,从broker获取队列列表,按照负载均衡策略,计算各自负责哪些队列。这种就要求进行负载均衡的时候,各个Consumer获取的数据是一致的,否则不一样的Consumer的reblance结果就不一样。
对于kafka:kafka以前也是客户端本身进行reblance,依靠ZooKeeper的监听,来监听上述2种状况的出现,一旦出现则进行reblance。如今的版本则将这个reblance操做转移到了broker端来作,不但解决了RocketMQ上述的问题,同时减轻了客户端的操做,是的客户端更加轻量级,减小了和其余语言集成的工做量。详细见这篇文章Kafka设计解析(四):Kafka Consumer解析
Name Server和ZooKeeper的做用大体是相同的,从宏观上来看,Name Server作的东西不多,就是保存一些运行数据,Name Server之间不互连,这就须要broker端链接全部的Name Server,运行数据的改动要发送到每个Name Server来保证运行数据的一致性(这个一致性确实有点弱),这样就变成了Name Server很轻量级,可是broker端就要作更多的东西了。
而ZooKeeper呢,broker只须要链接其中的一台机器,运行数据分发、一致性都交给了ZooKeeper来完成。
目前先就这几个大的组件进行简单的对比,后续会对某些细节进行详细说明。
欢迎关注微信公众号:乒乓狂魔