我們知道,在早期的RocketMQ版本中,是有依賴ZK的。而現(xiàn)在的版本中,是去掉了對(duì)ZK的依賴,轉(zhuǎn)而使用自己開發(fā)的NameSrv。
并且這個(gè)NameSrv是無(wú)狀態(tài)的,你可以隨意的部署多臺(tái),其代碼也非常簡(jiǎn)單,非常輕量。
那不禁要問(wèn)了:ZooKeeper是業(yè)界用來(lái)管理集群的一個(gè)非常常用的中間件,比如Kafka就是依賴的ZK。那為什么RocketMQ要自己造輪子,自己做集群的管理呢?純粹就是再做一個(gè)Zookeeper嗎?
本篇試圖通過(guò)一個(gè)架構(gòu)上的巨大差異,來(lái)闡述為什么RocketMQ可以去掉ZK。
我們知道,在Kafka中,是1個(gè)topic有多個(gè)partition,每個(gè)partition有1個(gè)master + 多個(gè)slave。對(duì)應(yīng)如下圖所示:
注意:這里只有3臺(tái)機(jī)器(b0,b1,b2),每臺(tái)機(jī)器既是Master,也是Slave。具體來(lái)說(shuō),比如機(jī)器b0,對(duì)于partition0來(lái)說(shuō),它可能是Master;對(duì)應(yīng)partition1來(lái)說(shuō),它可能又是Slave。
不同于Kafka里面,一臺(tái)機(jī)器同時(shí)是Master和Slave。在RocketMQ里面,1臺(tái)機(jī)器只能要么是Master,要么是Slave。這個(gè)在初始的機(jī)器配置里面,就定死了。其架構(gòu)拓?fù)鋱D如下:
在這里,RocketMQ里面queue這個(gè)概念,就對(duì)應(yīng)Kafka里面partition。
有3個(gè)Master, 6個(gè)Slave,那對(duì)應(yīng)到物理上面,就是3+6,得9臺(tái)機(jī)器?。?!而不是上面像Kafka一樣,3臺(tái)機(jī)器。
通過(guò)上面2張圖,我們已經(jīng)可以直觀看出2者的巨大差異。反映到概念上,雖然2者都有Master/Slave/Broker這3個(gè)概念,但其含義是不一樣的。
Kafka: Master/Slave是個(gè)邏輯概念,1臺(tái)機(jī)器,同時(shí)具有Master角色和Slave角色。
RocketMQ: Master/Slave是個(gè)物理概念,1臺(tái)機(jī)器,只能是Master或者Slave。在集群初始配置的時(shí)候,指定死的。其中Master的broker id = 0,Slave的broker id > 0。
Kafka: Broker是個(gè)物理概念,1個(gè)broker就對(duì)應(yīng)1臺(tái)機(jī)器。
RocketMQ:Broker是個(gè)邏輯概念,1個(gè)broker = 1個(gè)master + 多個(gè)slave。所以才有master broker, slave broker這樣的概念。
那這里,master和slave是如何配對(duì)的呢? 答案是通過(guò)broker name。具有同1個(gè)broker name的master和slave進(jìn)行配對(duì)。
具體到配置里面,如下:
//機(jī)器1的配置brokerClusterName=DefaultClusterbrokerName=broker-abrokerId=0deleteWhen=04fileReservedTime=48brokerRole=ASYNC_MASTERflushDiskType=ASYNC_FLUSH
//機(jī)器2的配置brokerClusterName=DefaultClusterbrokerName=broker-abrokerId=1deleteWhen=04fileReservedTime=48brokerRole=SLAVEflushDiskType=ASYNC_FLUSH
//機(jī)器3的配置brokerClusterName=DefaultClusterbrokerName=broker-abrokerId=2deleteWhen=04fileReservedTime=48brokerRole=SLAVEflushDiskType=ASYNC_FLUSH
這里機(jī)器1和機(jī)器2,機(jī)器3具有相同的brokerName(broker-a),一個(gè)brokerId = 0,另2個(gè)brokerId > 0。所以機(jī)器1是Master,機(jī)器2, 3是Slave。
所以這里可以看出:RokcetMQ和Kafka關(guān)于這2對(duì)概念的定義,剛好是反過(guò)來(lái)的!Kafka是先有Broker,然后產(chǎn)生出Master/Slave;RokcetMQ是先定義Master/Slave,然后組合出Broker。
從上面對(duì)比可以看出,Kafka和RocketMQ在Master/Slave/Broker這個(gè)3個(gè)概念上的差異。
這個(gè)差異,也就影響到topic, partition這種邏輯概念和Master/Slave/Broker這些物理概念上的映射關(guān)系。具體來(lái)講就是:
在Kafka里面,Maser/Slave是選舉出來(lái)的?。?!RocketMQ不需要選舉?。?!
在Kafka里面,Maser/Slave是選舉出來(lái)的?。?!RocketMQ不需要選舉?。?!
在Kafka里面,Maser/Slave是選舉出來(lái)的?。。ocketMQ不需要選舉?。。?/p>
重要的話說(shuō)三篇。具體來(lái)說(shuō),在Kafka里面,Master/Slave的選舉,有2步:第1步,先通過(guò)ZK在所有機(jī)器中,選舉出一個(gè)KafkaController;第2步,再由這個(gè)Controller,決定每個(gè)partition的Master是誰(shuí),Slave是誰(shuí)。
這里的Master/Slave是動(dòng)態(tài)的,也就是說(shuō):當(dāng)Master掛了之后,會(huì)有1個(gè)Slave切換成Master。
而在RocketMQ中,不需要選舉,Master/Slave的角色也是固定的。當(dāng)一個(gè)Master掛了之后,你可以寫到其他Master上,但不會(huì)說(shuō)一個(gè)Slave切換成Master。
這種簡(jiǎn)化,使得RocketMQ可以不依賴ZK就很好的管理Topic/queue和物理機(jī)器的映射關(guān)系了,也實(shí)現(xiàn)了高可用。
這里,也涉及到了我在上1篇里,所說(shuō)的“消息順序”的問(wèn)題:在Kafka里面,一個(gè)partition必須與1個(gè)Master有嚴(yán)格映射關(guān)系,這個(gè)Master掛了,就要從其他Slave里面選舉出一個(gè)Master;而在RocketMQ里面,這個(gè)限制放開了,一個(gè)queue對(duì)應(yīng)的Master掛了,它會(huì)切到其他Master,而不是非要選舉出來(lái)一個(gè)。
說(shuō)到這,答案基本就知道了:RocketMQ不需要像Kafka那樣有很重的選舉邏輯,它把這個(gè)問(wèn)題簡(jiǎn)化了。剩下的就是topic/queue的路由信息,那用個(gè)簡(jiǎn)單的NameServer就搞定了,很輕量,還無(wú)狀態(tài),可靠性也能得到很好保證。
下面從使用的角度,看看Kafka和RocketMQ在創(chuàng)建topic的時(shí)候,分別都需要指定什么參數(shù)?
從這些參數(shù)也可以看出,2者的topic, partition這種邏輯概念和物理機(jī)器之間的映射關(guān)系,有很大不同。
下面代碼來(lái)自UpdateTopicSubCommand這個(gè)類,也就是RocketMq創(chuàng)建topic時(shí),調(diào)用的類。這里有幾個(gè)關(guān)鍵參數(shù),其他參數(shù)我省略了:
b:
c: //b和c2選1,b是指定topic所在的機(jī)器,c是指定topic所在的cluster
topic: //這個(gè)是基本參數(shù),沒(méi)什么好講的
readQueueNums/writeQueueNums: //隊(duì)列個(gè)數(shù)。缺省2者相等,是8。關(guān)于這個(gè)readQueueNums/writeQueueNums,是RocketMQ特有的概念,后面再來(lái)詳細(xì)分析。此處就認(rèn)為他們2者相等,是同1個(gè)。
Option opt = new Option("b", "brokerAddr", true, "create topic to which broker"); opt.setRequired(false); options.addOption(opt); opt = new Option("c", "clusterName", true, "create topic to which cluster"); opt.setRequired(false); options.addOption(opt); opt = new Option("t", "topic", true, "topic name"); opt.setRequired(true); options.addOption(opt); opt = new Option("r", "readQueueNums", true, "set read queue nums"); opt.setRequired(false); options.addOption(opt); opt = new Option("w", "writeQueueNums", true, "set write queue nums"); opt.setRequired(false); options.addOption(opt); 。。。
跟RocketMQ相比,有2個(gè)同樣的參數(shù):1個(gè)是topic,一個(gè)是隊(duì)列數(shù)目,也就是這里的–partitions。
bin/kafka-topics.sh --create --zookeeper localhost:2181 --replication-factor 3 --partitions 1 --topic my-replicated-topic
Kafka有一個(gè)參數(shù)replication-factor,也就是指定給1個(gè)Master配幾個(gè)Slave?
RocketMQ有一個(gè)參數(shù)c,也就是clusterName,來(lái)指定這個(gè)cluster里面,所有的Master和Slave的配對(duì)(多個(gè)master, 多個(gè)slave) 對(duì)應(yīng)同1個(gè)topic!!!
缺省情況下,所有的Master和Slave屬于同1個(gè)集群,也就是上面的3臺(tái)機(jī)器配置中的第1個(gè)參數(shù):brokerClusterName=DefaultCluster。
結(jié)合上面的架構(gòu)拓?fù)鋱D,我們就可以看出:
對(duì)于kafka來(lái)說(shuō),你指定topic,它的partition個(gè)數(shù),它的master/slave配比,然后系統(tǒng)自動(dòng)從所有機(jī)器中,為每個(gè)topic_partition分配1個(gè)master + 多個(gè)slave;
對(duì)于RokcetMQ來(lái)說(shuō),你指定topic,它的queue個(gè)數(shù),它對(duì)應(yīng)的cluster。然后系統(tǒng)自動(dòng)建立這個(gè)cluster(多個(gè)master + 多個(gè)slave) 和你的topic之間的映射關(guān)系。
聯(lián)系客服