我們知道,在早期的RocketMQ版本中,是有依賴ZK的。而現在的版本中,是去掉了對ZK的依賴,轉而使用自己開發的NameSrv。
並且這個NameSrv是無狀態的,你可以隨意的部署多臺,其代碼也非常簡單,非常輕量。
那不禁要問了:ZooKeeper是業界用來管理集羣的一個非常常用的中間件,比如Kafka就是依賴的ZK。那爲什麼RocketMQ要自己造輪子,自己做集羣的管理呢?純粹就是再做一個Zookeeper嗎?
本篇試圖通過一個架構上的巨大差異,來闡述爲什麼RocketMQ可以去掉ZK。
Kafka的架構拓撲圖
我們知道,在Kafka中,是1個topic有多個partition,每個partition有1個master + 多個slave。對應如下圖所示:
注意:這裏只有3臺機器(b0,b1,b2),每臺機器既是Master,也是Slave。具體來說,比如機器b0,對於partition0來說,它可能是Master;對應partition1來說,它可能又是Slave。
RocketMQ的架構拓撲圖
不同於Kafka裏面,一臺機器同時是Master和Slave。在RocketMQ裏面,1臺機器只能要麼是Master,要麼是Slave。這個在初始的機器配置裏面,就定死了。其架構拓撲圖如下:
在這裏,RocketMQ裏面queue這個概念,就對應Kafka裏面partition。
有3個Master, 6個Slave,那對應到物理上面,就是3+6,得9臺機器!!!而不是上面像Kafka一樣,3臺機器。
Master/Slave/Broker概念上的差異
通過上面2張圖,我們已經可以直觀看出2者的巨大差異。反映到概念上,雖然2者都有Master/Slave/Broker這3個概念,但其含義是不一樣的。
Master/Slave概念差異
Kafka: Master/Slave是個邏輯概念,1臺機器,同時具有Master角色和Slave角色。
RocketMQ: Master/Slave是個物理概念,1臺機器,只能是Master或者Slave。在集羣初始配置的時候,指定死的。其中Master的broker id = 0,Slave的broker id > 0。
Broker概念差異
Kafka: Broker是個物理概念,1個broker就對應1臺機器。
RocketMQ:Broker是個邏輯概念,1個broker = 1個master + 多個slave。所以纔有master broker, slave broker這樣的概念。
那這裏,master和slave是如何配對的呢? 答案是通過broker name。具有同1個broker name的master和slave進行配對。
具體到配置裏面,如下:
//機器1的配置
brokerClusterName=DefaultCluster
brokerName=broker-a
brokerId=0
deleteWhen=04
fileReservedTime=48
brokerRole=ASYNC_MASTER
flushDiskType=ASYNC_FLUSH
//機器2的配置
brokerClusterName=DefaultCluster
brokerName=broker-a
brokerId=1
deleteWhen=04
fileReservedTime=48
brokerRole=SLAVE
flushDiskType=ASYNC_FLUSH
//機器3的配置
brokerClusterName=DefaultCluster
brokerName=broker-a
brokerId=2
deleteWhen=04
fileReservedTime=48
brokerRole=SLAVE
flushDiskType=ASYNC_FLUSH
- >
這裏機器1和機器2,機器3具有相同的brokerName(broker-a),一個brokerId = 0,另2個brokerId > 0。所以機器1是Master,機器2, 3是Slave。
所以這裏可以看出:RokcetMQ和Kafka關於這2對概念的定義,剛好是反過來的!Kafka是先有Broker,然後產生出Master/Slave;RokcetMQ是先定義Master/Slave,然後組合出Broker。
答案:爲什麼可以去ZK?
從上面對比可以看出,Kafka和RocketMQ在Master/Slave/Broker這個3個概念上的差異。
這個差異,也就影響到topic, partition這種邏輯概念和Master/Slave/Broker這些物理概念上的映射關係。具體來講就是:
在Kafka裏面,Maser/Slave是選舉出來的!!!RocketMQ不需要選舉!!!
在Kafka裏面,Maser/Slave是選舉出來的!!!RocketMQ不需要選舉!!!
在Kafka裏面,Maser/Slave是選舉出來的!!!RocketMQ不需要選舉!!!
重要的話說三篇。具體來說,在Kafka裏面,Master/Slave的選舉,有2步:第1步,先通過ZK在所有機器中,選舉出一個KafkaController;第2步,再由這個Controller,決定每個partition的Master是誰,Slave是誰。
這裏的Master/Slave是動態的,也就是說:當Master掛了之後,會有1個Slave切換成Master。
而在RocketMQ中,不需要選舉,Master/Slave的角色也是固定的。當一個Master掛了之後,你可以寫到其他Master上,但不會說一個Slave切換成Master。
這種簡化,使得RocketMQ可以不依賴ZK就很好的管理Topic/queue和物理機器的映射關係了,也實現了高可用。
這裏,也涉及到了我在上1篇裏,所說的“消息順序”的問題:在Kafka裏面,一個partition必須與1個Master有嚴格映射關係,這個Master掛了,就要從其他Slave裏面選舉出一個Master;而在RocketMQ裏面,這個限制放開了,一個queue對應的Master掛了,它會切到其他Master,而不是非要選舉出來一個。
說到這,答案基本就知道了:RocketMQ不需要像Kafka那樣有很重的選舉邏輯,它把這個問題簡化了。剩下的就是topic/queue的路由信息,那用個簡單的NameServer就搞定了,很輕量,還無狀態,可靠性也能得到很好保證。
Topic的創建過程
下面從使用的角度,看看Kafka和RocketMQ在創建topic的時候,分別都需要指定什麼參數?
從這些參數也可以看出,2者的topic, partition這種邏輯概念和物理機器之間的映射關係,有很大不同。
RocketMQ 創建topic的命令
下面代碼來自UpdateTopicSubCommand這個類,也就是RocketMq創建topic時,調用的類。這裏有幾個關鍵參數,其他參數我省略了:
b:
c: //b和c2選1,b是指定topic所在的機器,c是指定topic所在的cluster
topic: //這個是基本參數,沒什麼好講的
readQueueNums/writeQueueNums: //隊列個數。缺省2者相等,是8。關於這個readQueueNums/writeQueueNums,是RocketMQ特有的概念,後面再來詳細分析。此處就認爲他們2者相等,是同1個。
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);
Kafka創建topic的命令
跟RocketMQ相比,有2個同樣的參數:1個是topic,一個是隊列數目,也就是這裏的–partitions。
bin/kafka-topics.sh --create --zookeeper localhost:2181 --replication-factor 3 --partitions 1 --topic my-replicated-topic
2者在創建topic時一個顯著的不同
Kafka有一個參數replication-factor,也就是指定給1個Master配幾個Slave?
RocketMQ有一個參數c,也就是clusterName,來指定這個cluster裏面,所有的Master和Slave的配對(多個master, 多個slave) 對應同1個topic!!!
缺省情況下,所有的Master和Slave屬於同1個集羣,也就是上面的3臺機器配置中的第1個參數:brokerClusterName=DefaultCluster。
結合上面的架構拓撲圖,我們就可以看出:
對於kafka來說,你指定topic,它的partition個數,它的master/slave配比,然後系統自動從所有機器中,爲每個topic_partition分配1個master + 多個slave;
對於RokcetMQ來說,你指定topic,它的queue個數,它對應的cluster。然後系統自動建立這個cluster(多個master + 多個slave) 和你的topic之間的映射關係。