在hyperledger fabric的orderer中挚躯,目前發(fā)布的版本是使用kafka來做排序片林,并沒有用到所謂的sbft譬涡。kafka作為一個消息中間件,來對orderer發(fā)過來的消息進行排序料皇,這樣所有的orderer可以當做consumer來去kafka上去取消息谓松。kafka具體和fabric怎么合作星压,我們按下不表。這篇文章主要介紹kafka的工作原理鬼譬,以及怎樣和zookeeper合作娜膘。
Zookeeper的原理
1. Zookeeper是什么
ZooKeeper是一種為分布式應(yīng)用所設(shè)計的高可用、高性能且一致的開源協(xié)調(diào)服務(wù)优质,它提供了一項基本服務(wù):分布式鎖服務(wù)竣贪。由于ZooKeeper的開源特性,后來我們的開發(fā)者在分布式鎖的基礎(chǔ)上巩螃,摸索了出了其他的使用方法:配置維護贾富、組服務(wù)、分布式消息隊列牺六、分布式通知/協(xié)調(diào)等。
2. 為什么要用Zookeeper
分布式節(jié)點的各個節(jié)點的協(xié)調(diào)是分布式服務(wù)必須要解決的一個問題汗捡。舉個例子來說明
為什么要使用分布式節(jié)點呢淑际?是為了解決所謂的單點故障。什么是單點故障呢扇住?如下圖所示春缕,一個主節(jié)點Master提供服務(wù)給其他機器,那么如果這個Master節(jié)點掛了呢艘蹋?是不是Slave從節(jié)點就無法享受到該服務(wù)了呢锄贼?
一般對這種單點故障的解決辦法是雙Master或者多集群。如下圖所示女阀,采用兩個Master宅荤,一個為主節(jié)點,一個為備份節(jié)點浸策。一旦發(fā)現(xiàn)主節(jié)點有問題(掛了或者出錯)冯键,則立即切換到備份節(jié)點。
如下圖所示庸汗,所有的slave在收到消息后惫确,直接切換到備用節(jié)點。
然而在有時候主節(jié)點沒有宕機蚯舱,然而Slave節(jié)點或者其他Master節(jié)點認為他宕機了改化,這樣極其容易造成彼此之間的視圖(對整個集群的理解)不一致。如下圖所示:
當集群中的節(jié)點出現(xiàn)對集群的理解不一致時枉昏,會對強一致性的程序產(chǎn)生很壞的影響陈肛,有可能會造成消息的亂序。所以一致性問題的解決有很多辦法凶掰,比如PBFT燥爷,RAFT或者鎖等等蜈亩。每種辦法都有各自的優(yōu)劣。
那么Zookeeper的引入前翎,怎么能解決這個全局視圖保證一致呢稚配?
如下圖所示,主節(jié)點A和主節(jié)點B在啟動的時候港华,都首先向Zookeeper節(jié)點注冊道川,Zookeeper會將這兩個節(jié)點寫入到自己的文件系統(tǒng)內(nèi),并分配給每個節(jié)點一個id號立宜。與此同時冒萄,Zookeeper節(jié)點會保持與兩個Master節(jié)點的心跳,每隔幾個tick(自己定義在配置文件里)與節(jié)點溝通一次橙数,以此驗證節(jié)點的狀態(tài)尊流。這樣哪個節(jié)點宕機,哪個節(jié)點新加入等等都可以實時的反應(yīng)在zookeeper上灯帮。Slave節(jié)點想知道連哪個主節(jié)點崖技,根據(jù)自己的算法去選擇。比如kafka就會根據(jù)topic隨機選擇leader钟哥。所有人都可以在zookeeper上設(shè)置監(jiān)聽迎献,一旦某個主節(jié)點有變動,大家都會收到zookeeper的推送消息腻贰。
寫到這里估計有人得問吁恍,你這不也會有單點故障的風險嗎?比如這個zookeeper掛了怎么辦播演?這個問題是個好問題冀瓦。zookeeper可以設(shè)置集群,也就是幾個zookeeper可以同時對外服務(wù)宾巍。那么zookeeper集群如何保證一致性的咕幻?怎樣保證所有的zookeeper對外部世界的理解一致的?總不能這個zookeeper知道MasterA是正常的顶霞,那個zookeeper以為MasterA是不正常吧肄程!
還是一致性的問題,這個zookeeper用了ZAB共識算法來保證各個zookeeper節(jié)點的一致性选浑。
3. 怎樣使用Zookeeper
zookeeper的啟動需要配置如下的信息(本文以docker啟動)蓝厌,太坑了,這里竟然不能用代碼古徒。
從上圖可以看出ZOO_MY_ID為每個zookeeper的唯一id號拓提,ZOO_SERVERS為集群的ip及端口。當zookeeper起來后隧膘,可以直接進入zookeeper所在的bin目錄代态,查找zkCli.sh寺惫。通過該可執(zhí)行腳本可以找到注冊在zookeeper上的服務(wù)。zkCli.sh所在目錄如下圖所示:
執(zhí)行該腳本后蹦疑,進入zkCli的控制臺西雀,在該控制臺可以查看注冊到zookeeper的服務(wù)。本例以kafka來舉例:
可以到brokers目錄下查看注冊的kafka節(jié)點數(shù)目歉摧。
從上圖中艇肴,可以看到注冊到zookeeper的kafka有四個,id分別為0,1,2,3叁温。其中0的注冊信息可以通過 get /brokers/ids/0來獲得再悼。
各個字段的含義如下:
czxid.節(jié)點創(chuàng)建時的zxid.mzxid.節(jié)點最新一次更新發(fā)生時的
zxid.ctime.節(jié)點創(chuàng)建時的時間戳.
mtime.節(jié)點最新一次更新發(fā)生時的時間戳.
dataVersion.節(jié)點數(shù)據(jù)的更新次數(shù).
cversion.其子節(jié)點的更新次數(shù).
aclVersion.節(jié)點ACL(授權(quán)信息)的更新次數(shù).
ephemeralOwner.如果該節(jié)點為ephemeral節(jié)點,ephemeralOwner值表示與該節(jié)點綁定的sessionid.如果該節(jié)點不是ephemeral節(jié)點,ephemeralOwner值為0.
dataLength.節(jié)點數(shù)據(jù)的字節(jié)數(shù).
numChildren.子節(jié)點個數(shù).
關(guān)于zxid的定義:ZooKeeper狀態(tài)的每一次改變, 都對應(yīng)著一個遞增的Transaction id, 該id稱為zxid. 由于zxid的遞增性質(zhì), 如果zxid1小于zxid2, 那么zxid1肯定先于zxid2發(fā)生. 創(chuàng)建任意節(jié)點, 或者更新任意節(jié)點的數(shù)據(jù), 或者刪除任意節(jié)點, 都會導(dǎo)致Zookeeper狀態(tài)發(fā)生改變, 從而導(dǎo)致zxid的值增加.
再舉個例子,下圖是kafka節(jié)點創(chuàng)建的mytopic膝但,可以看到在0號分區(qū)的kafka主節(jié)點是0號冲九,isr分別同步到0,1跟束,2節(jié)點娘侍。而且通過dataVersion可以看到改變了11次,說明發(fā)了11條消息泳炉。
Kafka的原理
1. Kafka是什么
Kafka是一種分布式的,基于發(fā)布/訂閱的消息系統(tǒng)嚎杨。為什么要用的消息系統(tǒng)呢花鹅?因為利用消息系統(tǒng)有如下的好處:
a)? ? 系統(tǒng)解耦。系統(tǒng)解耦帶來的好處就是擴展性增強枫浙。
b)? ? 事件分發(fā)刨肃。這樣做的好處就是帶來了異步通信,不用某個模塊等待另外一個模塊箩帚,而是將消息發(fā)送過去就不用管了真友,或者消費者只管去拉消息。
c)? ? 消息回溯紧帕。舉個簡單的例子盔然,在玩游戲的過程中,想要做視頻回放是嗜,那么消息系統(tǒng)里做一次記錄即可愈案。開個不是玩笑的玩笑,現(xiàn)在很多人拿kafka當數(shù)據(jù)庫來用鹅搪。簡單方便站绪。
d) ????......
2. 為什么要用到Kafka
a)????快速持久化,可以在O(1)的系統(tǒng)開銷下進行消息持久化丽柿。這個經(jīng)過本人的驗證恢准,的確太不可思議了魂挂,非常快馁筐,源于kafka良好的順序?qū)懩J健?/p>
b)????高吞吐涂召,我自己測的tps可以達到幾十萬;
c)? ? 同時支持單播與廣播眯漩。同一個topic的數(shù)據(jù)芹扭,會廣播給不同的group;同一個group中的worker赦抖,只有一個worker能拿到這個數(shù)據(jù)
d)????支持存儲舱卡。很多人把kafka當數(shù)據(jù)庫來存儲東西。
e)? ? 支持分布式存儲队萤。kafka可以和其他的kafka節(jié)點形成kafka集群轮锥,通過kafka的isr模式,topic的分區(qū)可以分布于不同的節(jié)點要尔。
f)? ? ......
3. 怎樣使用Kafka
先介紹一下kafka的相關(guān)概念舍杜。
????Broker:指服務(wù)于Kafka的一個節(jié)點。
????topic是一個邏輯概念赵辕,用于保證Producer以及Consumer能夠通過該標示進行對接既绩。
????partition是消息的真實存放者。partition會實際存儲在系統(tǒng)的某個目錄还惠。它Topic的一個子概念饲握,
????一個topic可具有多個partition,但Partition一定屬于一個topic蚕键。
下列是一個kafka集群救欧,從下圖可以看出一共有四個節(jié)點,分別為Broker1, Broker2, Broker3, Broker4. 該集群一共有一個topic锣光,該topic供有三個partition笆怠,分別為part0, part1, part2。其中part0分別存儲在Broker1, Broker2, Broker3上誊爹。而part1分別存儲在Broker2, Broker3, Broker4蹬刷。part2分半存儲在Broker1, Broker2, Broker4中。part0的三個Broker中频丘,Broker1為主節(jié)點箍铭。part1的主節(jié)點為Broker2, part2的主節(jié)點為Broker4。三個partition均勻分布椎镣。
需要的環(huán)境:
docker--為啥需要這個呢诈火,因為可以很容易的模擬多機部署,當然如果你是土豪,可以忽略這個冷守,安裝步驟在這里刀崖,當然你也可以參考別的文檔來安裝docker及docker-compose
1. 啟動kafka和zookeeper節(jié)點
利用下面的docker-compose.yml來啟動kafka與zookeeper,下面配置文件里啟動了三個zookeeper和4個kafka節(jié)點拍摇,三個zookeeper組成了一個zookeeper集群亮钦,管理kafka節(jié)點。
三個zookeeper節(jié)點分別為zookeeper0充活,zookeeper1蜂莉,zookeeper2
四個kafka節(jié)點分別為kafka0,kafka1混卵,kafka2映穗,kafka3
我的zookeeper節(jié)點是基于hyperledger/fabric-zookeeper的docker鏡像來啟動的,可以到zookeeper鏡像地址下載幕随。而kafka節(jié)點是基于hyperledger/fabric-kafka的docker鏡像來啟動的蚁滋,可以到kafka鏡像地址下載。
拷貝下面配置文件赘淮,并保存到docker-compose.yml文件中辕录。
在docker-compose.yml所在的目錄中,運行命令docker-compose up -d 命令來啟動容器梢卸。
創(chuàng)建完成后走诞,可以進入zookeeper容器檢查kafka節(jié)點是否都已經(jīng)注冊成功。
運行docker ps命令蛤高,列舉出所有的容器速梗,如下:
進入其中的一個zookeeper容器,通過如下命令
運行zkCli.sh命令襟齿,來檢查kafka節(jié)點有沒有注冊到zookeeper上。
檢查其中的一個broker id 如下:
從中可以知道brokerid 0,1,2,3都已經(jīng)注冊到zookeeper集群上了枕赵,而詳細brokerid 0的信息中可以得到其ip猜欺,端口等等。
具體kafka在zookeeper上的注冊消息圖如下拷窜,詳細我找到了一個網(wǎng)頁 开皿,可以參考
2. 創(chuàng)建topic
進入kafka節(jié)點,利用下述命令
運行下述命令篮昧,創(chuàng)建mytopic赋荆,該topic有一個分區(qū),部署有三個副本懊昨。
可以進入zookeeper節(jié)點窄潭,用zkCli.sh查看topic下的信息如下。
從中可以看出broker3為主節(jié)點酵颁,總共有3個副本嫉你,分別是broker0,broker1,broker3
3. 發(fā)送消息
進入kafka容器月帝,利用該kafka自帶腳本可以發(fā)送消息,如下即向本kafka節(jié)點的mytopic發(fā)送消息
4. 消費消息
進入kafka容器幽污,利用kafka自帶腳本嚷辅,可以對消息進行消費,如下即向kafka節(jié)點消費消息
到zookeeper中距误,啟動zkCli.sh可以看到簸搞,消費者是在zookeeper中注冊了消費者id,這樣可以保障group單播准潭。
本文參考:
https://www.cnblogs.com/wuxl360/p/5817471.html
http://blog.csdn.net/lizhitao/article/details/51718185
http://blog.csdn.net/lizhitao/article/details/23744675
http://blog.csdn.net/eric_sunah/article/details/46891901