Zookeeper分布式過(guò)程協(xié)同技術(shù)詳解筆記(二)

下載Zookeeper

筆者這里不對(duì)下載部分做過(guò)多贅述评凝,從官網(wǎng)下載何時(shí)版本的包解壓即可。其中bin目錄中含有zk的啟動(dòng)腳本腺律,conf中則是啟動(dòng)所需的配置文件奕短,lib目錄則是java的jar文件。

第一個(gè)zookeeper會(huì)話

初學(xué)zookeeper匀钧,我們使用bin目錄下的zkServer和zkClient工具進(jìn)行簡(jiǎn)單的調(diào)試和管理翎碑。
筆者使用的版本是3.4.10,conf目錄下的zoo.cfg是zk默認(rèn)的配置文件之斯,zoo_sample則是包含了更多的配置及其含義的注釋日杈,為了簡(jiǎn)便,我們直接使用zoo.cfg來(lái)啟動(dòng)zk服務(wù)佑刷。

localhost:bin wz$ sudo ./zkServer.sh start
ZooKeeper JMX enabled by default
Using config: /Users/wz/Developement/zookeeper-3.4.10/bin/../conf/zoo.cfg
Starting zookeeper ... STARTED

這個(gè)指令可以讓zk服務(wù)在后臺(tái)運(yùn)行莉擒,如果需要在前臺(tái)運(yùn)行以便查看服務(wù)器輸出,可以通過(guò)以下命令瘫絮。

sudo ./zkServer.sh start-foreground

好了涨冀,啟動(dòng)好了服務(wù)端,接著我們啟動(dòng)一個(gè)客戶端麦萤。

./zkCli.sh

......

2018-06-05 21:11:46,487 [myid:] - INFO  [main:ZooKeeper@438] - Initiating client connection, connectString=localhost:2181 sessionTimeout=30000 watcher=org.apache.zookeeper.ZooKeeperMain$MyWatcher@67424e82 ①
Welcome to ZooKeeper!
2018-06-05 21:11:46,511 [myid:] - INFO  [main-SendThread(localhost:2181):ClientCnxn$SendThread@1032] - Opening socket connection to server localhost/127.0.0.1:2181. Will not attempt to authenticate using SASL (unknown error)
JLine support is enabled ②
2018-06-05 21:11:46,566 [myid:] - INFO  [main-SendThread(localhost:2181):ClientCnxn$SendThread@876] - Socket connection established to localhost/127.0.0.1:2181, initiating session ③
2018-06-05 21:11:46,595 [myid:] - INFO  [main-SendThread(localhost:2181):ClientCnxn$SendThread@1299] - Session establishment complete on server  localhost/127.0.0.1:2181, sessionid = 0x163d00dddef0000, negotiated timeout = 30000 ④

WATCHER::

WatchedEvent state:SyncConnected type:None path:null ⑤

下面我們逐個(gè)分析這幾行日志鹿鳖,其實(shí)就是會(huì)話建立的過(guò)程信息。

① 客戶端啟動(dòng)壮莹,開始建立會(huì)話
② 客戶端嘗試連接到localhost/127.0.0.1:2181
③ 連接成功建立翅帜,開始初始化會(huì)話
④ 會(huì)話初始化完成
⑤ 服務(wù)端向客戶端發(fā)送一個(gè)state:SyncConnected事件,會(huì)話建立完成命满,id為 0x163d00dddef0000
客戶端需要實(shí)現(xiàn)Watcher對(duì)象來(lái)處理這個(gè)事件涝滴。

接下來(lái)我們劣列出根節(jié)點(diǎn)下的所有znode,然后嘗試創(chuàng)建一個(gè)znode胶台。

[zk: localhost:2181(CONNECTED) 3] ls /
[zookeeper]

只有zookeeper節(jié)點(diǎn)狭莱,其中包含了zk服務(wù)所需要的元數(shù)據(jù)樹,這里不多贅述概作,下面我們新建一個(gè)workers znode腋妙。

[zk: localhost:2181(CONNECTED) 3] ls /
[zookeeper]
[zk: localhost:2181(CONNECTED) 4] create /workers ""
Created /workers
[zk: localhost:2181(CONNECTED) 5] ls /
[zookeeper, workers]

這里創(chuàng)建時(shí)我們指定了一個(gè)空串,代表此時(shí)這個(gè)znode中不保存數(shù)據(jù)讯榕,當(dāng)然你也可以把""替換為"workers"或是任意內(nèi)容骤素。

然后我們刪除znode匙睹,停止這個(gè)會(huì)話,這樣就完成了這第一個(gè)小實(shí)驗(yàn)济竹。

[zk: localhost:2181(CONNECTED) 6] delete /workers
[zk: localhost:2181(CONNECTED) 7] ls /
[zookeeper]
[zk: localhost:2181(CONNECTED) 8] quit
Quitting...
2018-06-05 21:45:24,904 [myid:] - INFO  [main:ZooKeeper@684] - Session: 0x163d00dddef0000 closed
2018-06-05 21:45:24,906 [myid:] - INFO  [main-EventThread:ClientCnxn$EventThread@519] - EventThread shut down for session: 0x163d00dddef0000

會(huì)話的狀態(tài)和生命周期

一個(gè)zookeeper會(huì)話的狀態(tài)轉(zhuǎn)換大致如下圖所示


zookeeper會(huì)話狀態(tài)轉(zhuǎn)換圖

一個(gè)會(huì)話從NOT_CONNECTED開始痕檬,當(dāng)客戶端初始化連接完成時(shí)轉(zhuǎn)到CONNECTING狀態(tài),連接成功建立后會(huì)轉(zhuǎn)到CONNECTED狀態(tài)送浊。倘若此時(shí)服務(wù)器斷開連接或者無(wú)法收到服務(wù)器的響應(yīng)時(shí)梦谜,就會(huì)轉(zhuǎn)會(huì)CONNECTING狀態(tài)(箭頭3),并嘗試重新連接或發(fā)現(xiàn)其他zk服務(wù)器袭景,如果發(fā)現(xiàn)一個(gè)服務(wù)器或重連成功唁桩,狀態(tài)就會(huì)重新回到CONNECTED,否則耸棒,會(huì)話過(guò)期荒澡,轉(zhuǎn)到CLOSED狀態(tài)(箭頭4)。當(dāng)然与殃,應(yīng)用也可以顯示關(guān)閉會(huì)話(箭頭5)单山。

注意:
如果一個(gè)客戶端因超時(shí)與服務(wù)端斷開連接,客戶端仍然保持CONNECTING狀態(tài)幅疼,此時(shí)倘若因?yàn)榫W(wǎng)絡(luò)分區(qū)錯(cuò)誤導(dǎo)致客戶端與服務(wù)端之間連接不可達(dá)米奸,那么其狀態(tài)會(huì)一直保持,直到顯示的關(guān)閉這個(gè)會(huì)話或者問(wèn)題修復(fù)后客戶端悉知會(huì)話已過(guò)期爽篷。這是因?yàn)闀?huì)話的超時(shí)由服務(wù)集群來(lái)控制悴晰,客戶端無(wú)法控制。直到客戶端獲悉會(huì)話超時(shí)狼忱,否則不能聲明自己的回話過(guò)期膨疏,但是客戶端可以顯示關(guān)閉會(huì)話一睁。

因此钻弄,我們需要設(shè)置會(huì)話過(guò)期時(shí)間這個(gè)參數(shù),如果經(jīng)過(guò)t時(shí)間服務(wù)接收不到會(huì)話的消息者吁,就會(huì)聲明這個(gè)會(huì)話過(guò)期窘俺。在客戶端側(cè),如果經(jīng)過(guò)t/3時(shí)間后沒(méi)有收到消息复凳,就會(huì)向服務(wù)器發(fā)送心跳消息瘤泪。經(jīng)過(guò)2t/3時(shí)間后會(huì)開始尋找其他服務(wù)器,如果在剩下t/3時(shí)間內(nèi)無(wú)法找到育八,就會(huì)被聲明會(huì)話過(guò)期对途。

當(dāng)客戶端嘗試連接到一個(gè)不同的服務(wù)器時(shí),需要保證這個(gè)服務(wù)的狀態(tài)要與最后連接的服務(wù)器狀態(tài)一致髓棋,如果某個(gè)服務(wù)獲悉狀態(tài)變更的時(shí)間點(diǎn)延遲于客戶端实檀,那就要保證這個(gè)服務(wù)不會(huì)被鏈接惶洲。zk通過(guò)在服務(wù)中排序更新操作發(fā)發(fā)生的事件來(lái)確保這種情況,如果客戶端再位置i觀察到一個(gè)更新膳犹,那他就不能連接到只觀察到i之前狀態(tài)的服務(wù)恬吕。這個(gè)過(guò)程如下圖所示。


客戶端重連

zookeeper與仲裁模式

上面我們都是基于獨(dú)立模式進(jìn)行的實(shí)驗(yàn)须床,這在實(shí)際環(huán)境中肯定是非常不靠譜的铐料,如果服務(wù)器故障那整個(gè)zk服務(wù)都將關(guān)閉。下面我們通過(guò)在一臺(tái)機(jī)器上運(yùn)行多個(gè)zk服務(wù)器來(lái)演示仲裁模式豺旬。
首先將配置文件修改如下:

   tickTime=2000
   initLimit=10
   syncLimit=5
   dataDir=./data
   clientPort=2181
   server.1=127.0.0.1:2222:2223
   server.2=127.0.0.1:3333:3334
   server.3=127.0.0.1:4444:4445

其中server.n指定了編號(hào)為n的服務(wù)器所使用的地址和端口钠惩,每個(gè)server.n通過(guò)冒號(hào)分隔為三部分,第一部分為服務(wù)器主機(jī)名哈垢,第二部分和第三部分為TCP端口號(hào)妻柒,分別用于仲裁和群首選舉。

接著我們還需要為每個(gè)服務(wù)分別設(shè)置data目錄

localhost:bin wz$ mkdir z1
localhost:bin wz$ mkdir z2
localhost:bin wz$ mkdir z3
localhost:bin wz$ mkdir z1/data
localhost:bin wz$ mkdir z2/data
localhost:bin wz$ mkdir z3/data

當(dāng)一個(gè)服務(wù)器啟動(dòng)時(shí)耘分,需要知道啟動(dòng)的是哪個(gè)服務(wù)器举塔,通過(guò)讀取data目錄下一個(gè)名為myid的文件來(lái)獲取服務(wù)器ID信息,我們可以通過(guò)以下命令創(chuàng)建這些文件:

localhost:bin wz$ echo 1 > z1/data/myid
localhost:bin wz$ echo 2 > z2/data/myid
localhost:bin wz$ echo 3 > z3/data/myid

接著我們分別創(chuàng)建每臺(tái)服務(wù)器的配置文件求泰,根據(jù)上面的配置新建z1.cfg央渣,然后修改端口為2181和2183創(chuàng)建z2/z3.cfg。

現(xiàn)在我們可以啟動(dòng)服務(wù)器渴频,先從z1開始

sudo ./zkServer.sh start-foreground ./z1/z1.cfg

此時(shí)服務(wù)器瘋狂嘗試連接到其他服務(wù)器芽丹,報(bào)錯(cuò)如下:

018-06-07 22:51:26,169 [myid:1] - WARN  [WorkerSender[myid=1]:QuorumCnxManager@588] - Cannot open channel to 2 at election address /127.0.0.1:3334
java.net.ConnectException: Connection refused (Connection refused)
    at java.net.PlainSocketImpl.socketConnect(Native Method)
    at java.net.AbstractPlainSocketImpl.doConnect(AbstractPlainSocketImpl.java:350)
    at java.net.AbstractPlainSocketImpl.connectToAddress(AbstractPlainSocketImpl.java:206)
    at java.net.AbstractPlainSocketImpl.connect(AbstractPlainSocketImpl.java:188)
    at java.net.SocksSocketImpl.connect(SocksSocketImpl.java:392)
    at java.net.Socket.connect(Socket.java:589)
    at org.apache.zookeeper.server.quorum.QuorumCnxManager.connectOne(QuorumCnxManager.java:562)
    at org.apache.zookeeper.server.quorum.QuorumCnxManager.toSend(QuorumCnxManager.java:538)
    at org.apache.zookeeper.server.quorum.FastLeaderElection$Messenger$WorkerSender.process(FastLeaderElection.java:452)

接著我們啟動(dòng)第二臺(tái)服務(wù)器,我們會(huì)看到以下日志

2018-06-07 22:51:42,699 [myid:2] - INFO  [QuorumPeer[myid=2]/0:0:0:0:0:0:0:0:2182:Leader@371] - LEADING - LEADER ELECTION TOOK - 250

該日志指出服務(wù)器2已被選舉為群首卜朗,再看服務(wù)器1的日志

2018-06-07 22:51:42,683 [myid:1] - INFO  [QuorumPeer[myid=1]/0:0:0:0:0:0:0:0:2181:Follower@64] - FOLLOWING - LEADER ELECTION TOOK - 16517

該服務(wù)器作為服務(wù)器2的追隨者被激活拔第,現(xiàn)在我們并沒(méi)有啟動(dòng)服務(wù)器3,也就是說(shuō)此時(shí)構(gòu)成了允許執(zhí)行的最小數(shù)目(參見一篇博客)场钉。

此刻服務(wù)已經(jīng)可用蚊俺,現(xiàn)在我們啟動(dòng)一個(gè)客戶端來(lái)連接到服務(wù)上,連接字符串需要列出所有組成服務(wù)的服務(wù)器host:port對(duì)逛万。這個(gè)例子中泳猬,這個(gè)連接串為
"127.0.0.1:2181,127.0.0.1:2182,127.0.0.1:2183"(這里我們包含了第三臺(tái)服務(wù)器的信息,但我們并沒(méi)有啟動(dòng)它宇植,放在這里僅為了說(shuō)明zk的一些屬性)
接下來(lái)使用zkCli來(lái)訪問(wèn)這個(gè)集群:

./zkCli.sh -server 127.0.0.1:2181,127.0.0.2:2182,127.0.0.1:2183

連接成功后得封,你會(huì)看到如下日志

2018-06-07 23:09:16,507 [myid:] - INFO  [main-SendThread(127.0.0.1:2181):ClientCnxn$SendThread@1299] - Session establishment complete on server 127.0.0.1/127.0.0.1:2181, sessionid = 0x163dabb62e60001, negotiated timeout = 30000

如果你通過(guò)多次ctrl+c停止并重連,就會(huì)發(fā)現(xiàn)端口號(hào)在2181和2182之間變化指郁,也會(huì)看到因?yàn)閲L試連接2183而報(bào)錯(cuò)的日志忙上,之后又成功連接到某一個(gè)服務(wù)。

一個(gè)主從模式例子的實(shí)現(xiàn)

主從模式的模型包括三個(gè)角色:

  1. 主節(jié)點(diǎn)闲坎,主要負(fù)責(zé)監(jiān)視新的從節(jié)點(diǎn)和任務(wù)疫粥,進(jìn)行任務(wù)的分配洋腮。
  2. 從節(jié)點(diǎn), 通過(guò)系統(tǒng)注冊(cè)自己以便可以被主節(jié)點(diǎn)所監(jiān)控手形,然后開始監(jiān)視新的任務(wù)啥供。
  3. 客戶端,創(chuàng)建新任務(wù)并等待服務(wù)端響應(yīng)库糠。

因?yàn)橹挥幸粋€(gè)進(jìn)程會(huì)成為主節(jié)點(diǎn)伙狐,所以一旦有一個(gè)進(jìn)程成為主節(jié)點(diǎn)后就必須鎖定管理權(quán),為此瞬欧,我們先創(chuàng)建一個(gè)臨時(shí)節(jié)點(diǎn)/master贷屎。

[zk: localhost:2181(CONNECTED) 0] create -e /master "master1.example.com:2223"
Created /master
[zk: localhost:2181(CONNECTED) 1] ls /
[zookeeper, master]
[zk: localhost:2181(CONNECTED) 2] get /master
master1.example.com:2223
cZxid = 0xf0a
ctime = Tue Jun 12 22:35:20 CST 2018
mZxid = 0xf0a
mtime = Tue Jun 12 22:35:20 CST 2018
pZxid = 0xf0a
cversion = 0
dataVersion = 0
aclVersion = 0
ephemeralOwner = 0x163f1627cc3000e
dataLength = 24
numChildren = 0

以上我們創(chuàng)建主節(jié)點(diǎn)znode,使用 -e標(biāo)注創(chuàng)建的znode為臨時(shí)性的艘虎。之后列出了zookeeper樹的根唉侄。最后獲取了/master這個(gè)znode的數(shù)據(jù)和元數(shù)據(jù)。
主節(jié)點(diǎn)建立后野建,倘若其他進(jìn)程不知道一個(gè)主節(jié)點(diǎn)已被選舉出來(lái)属划,嘗試重復(fù)創(chuàng)建/master,zk會(huì)告訴我們一個(gè)/master節(jié)點(diǎn)已經(jīng)存在候生。但是主節(jié)點(diǎn)隨時(shí)可能崩潰同眯,為了讓其他節(jié)點(diǎn)能夠接替主節(jié)點(diǎn)的角色,需要在/master上設(shè)置一個(gè)監(jiān)視點(diǎn)唯鸭。

[zk: localhost:2181(CONNECTED) 4] stat /master true
cZxid = 0xf0a
ctime = Tue Jun 12 22:35:20 CST 2018
mZxid = 0xf0a
mtime = Tue Jun 12 22:35:20 CST 2018
pZxid = 0xf0a
cversion = 0
dataVersion = 0
aclVersion = 0
ephemeralOwner = 0x163f1627cc3000e
dataLength = 24
numChildren = 0

stat命令可以得到一個(gè)znode的屬性须蜗,并允許我們?cè)O(shè)置一個(gè)監(jiān)視點(diǎn)。通過(guò)路徑后添加true來(lái)添加監(jiān)視點(diǎn)目溉,這樣以來(lái)明肮,當(dāng)主節(jié)點(diǎn)會(huì)話結(jié)束過(guò)崩潰時(shí),我們就可以收到一個(gè)NodeDeleted事件缭付。此時(shí)備份節(jié)點(diǎn)就可以創(chuàng)建/master成為新的活動(dòng)主節(jié)點(diǎn)柿估。

從節(jié)點(diǎn)的任務(wù)和分配

開始之前,我們先創(chuàng)建3個(gè)持久性父znode, /workers, /tasks以及/assign蛉腌。他們不包含任何數(shù)據(jù)官份,用來(lái)告訴主節(jié)點(diǎn)有哪些節(jié)點(diǎn)可以接受任務(wù)只厘,哪些任務(wù)要分配烙丛,并向從節(jié)點(diǎn)分配任務(wù)。

[zk: localhost:2181(CONNECTED) 5] create /workers ""
Created /workers
[zk: localhost:2181(CONNECTED) 6] create /tasks ""
Created /tasks
[zk: localhost:2181(CONNECTED) 7] create /assign ""
Created /assign
[zk: localhost:2181(CONNECTED) 8] ls /workers true
[]
[zk: localhost:2181(CONNECTED) 9] ls /tasks true
[]

通過(guò)ls的可選參數(shù)true羔味,來(lái)設(shè)置對(duì)這個(gè)znode子節(jié)點(diǎn)變化的監(jiān)視點(diǎn)河咽。

好了,從節(jié)點(diǎn)現(xiàn)在首先要通知主節(jié)點(diǎn)赋元,自己可以執(zhí)行任務(wù)忘蟹。通過(guò)在/workers子節(jié)點(diǎn)下創(chuàng)建臨時(shí)性的znode來(lái)進(jìn)行通知飒房,并用主機(jī)名表示自己。

create -e /workers/worker1.example.com "worker1.example.com:2224"

WATCHER::

WatchedEvent state:SyncConnected type:NodeChildrenChanged path:/workers
Created /workers/worker1.example.com

一單創(chuàng)建成功媚值,主節(jié)點(diǎn)就會(huì)收到type:NodeChildrenChanged的通知狠毯。
下一步,從節(jié)點(diǎn)需要?jiǎng)?chuàng)建一個(gè)znode /assign/worker1.example.com來(lái)接受任務(wù)分配褥芒,
并監(jiān)視這個(gè)節(jié)點(diǎn)的變化:

[zk: localhost:2181(CONNECTED) 11] create -e /assign/worker1.example.com ""
Created /assign/worker1.example.com
[zk: localhost:2181(CONNECTED) 12] ls /assign/worker1.example.com true
[]

這樣從節(jié)點(diǎn)就已經(jīng)準(zhǔn)備就緒嚼松,可以接受任務(wù)分配。接下來(lái)我們通過(guò)討論客戶端角色來(lái)看一下任務(wù)分配的問(wèn)題锰扶。
假設(shè)客戶端提交了一個(gè)請(qǐng)求主從系統(tǒng)來(lái)運(yùn)行cmd的任務(wù)献酗,客戶端執(zhí)行一下操作

create -s /tasks/task- "cmd"

因?yàn)樾枰WC任務(wù)執(zhí)行順序,所以這里是一個(gè)有序隊(duì)列坷牛,使用-s創(chuàng)建順序節(jié)點(diǎn)罕偎。負(fù)責(zé)執(zhí)行該任務(wù)的節(jié)點(diǎn)執(zhí)行完成后會(huì)在此節(jié)點(diǎn)下創(chuàng)建一個(gè)新的節(jié)點(diǎn)表示任務(wù)的狀態(tài),因此客戶端需要監(jiān)視這個(gè)節(jié)點(diǎn)京闰,同樣的颜及,使用ls的參數(shù)true來(lái)設(shè)置監(jiān)視點(diǎn)

ls /tasks/task-0000000000 true

之前我們已經(jīng)設(shè)置了主節(jié)點(diǎn)對(duì)于/task節(jié)點(diǎn)的監(jiān)視,所以這里一單創(chuàng)建成功蹂楣,我們就會(huì)監(jiān)視到以下事件:

[zk: localhost:2181(CONNECTED) 6]
 WATCHER::
 WatchedEvent state:SyncConnected type:NodeChildrenChanged path:/tasks

主節(jié)點(diǎn)接著會(huì)檢查這個(gè)新任務(wù)器予,獲取可處理任務(wù)的節(jié)點(diǎn)列表,之后分配給work1.example.com

[zk: 6] ls /tasks
[task-0000000000]
[zk: 7] ls /workers
[worker1.example.com]
[zk: 8] create /assign/worker1.example.com/task-0000000000 ""
Created /assign/worker1.example.com/task-0000000000
[zk: 9]

接下來(lái)從節(jié)點(diǎn)會(huì)獲取到新增任務(wù)的通知:

  [zk: localhost:2181(CONNECTED) 3]
   WATCHER::
   WatchedEvent state:SyncConnected type:NodeChildrenChanged
   path:/assign/worker1.example.com

之后從節(jié)點(diǎn)會(huì)再次檢查任務(wù)是否分配給自己

   WATCHER::
   WatchedEvent state:SyncConnected type:NodeChildrenChanged
   path:/assign/worker1.example.com
   [zk: localhost:2181(CONNECTED) 3] ls /assign/worker1.example.com
   [task-0000000000]
   [zk: localhost:2181(CONNECTED) 4]

一旦從節(jié)點(diǎn)完成任務(wù)捐迫,就會(huì)向/task/task-0000000000中添加一個(gè)狀態(tài)節(jié)點(diǎn)status

   [zk: localhost:2181(CONNECTED) 4] create /tasks/task-0000000000/status "done"
   Created /tasks/task-0000000000/status
   [zk: localhost:2181(CONNECTED) 5]

之后客戶端收到通知乾翔,檢查結(jié)果:

   WATCHER::
   WatchedEvent state:SyncConnected type:NodeChildrenChanged
   path:/tasks/task-0000000000
   [zk: localhost:2181(CONNECTED) 2] get /tasks/task-0000000000
   "cmd"
   cZxid = 0x7c
   ctime = Tue Dec 11 10:30:18 CET 2012
   mZxid = 0x7c
   mtime = Tue Dec 11 10:30:18 CET 2012
   pZxid = 0x7e
   cversion = 1
   dataVersion = 0
   aclVersion = 0
   ephemeralOwner = 0x0
   dataLength = 5
   numChildren = 1
   [zk: localhost:2181(CONNECTED) 3] get /tasks/task-0000000000/status
   "done"
   cZxid = 0x7e
   ctime = Tue Dec 11 10:42:41 CET 2012
   mZxid = 0x7e
   mtime = Tue Dec 11 10:42:41 CET 2012
   pZxid = 0x7e
   cversion = 0
   dataVersion = 0
   aclVersion = 0
   ephemeralOwner = 0x0
   dataLength = 8
   numChildren = 0
   [zk: localhost:2181(CONNECTED) 4]

小結(jié)

這次我們通過(guò)例子了解了很多zk的基礎(chǔ)以及api的使用,盡管實(shí)際在分布式系統(tǒng)中可能復(fù)雜數(shù)倍施戴,但本質(zhì)上是相似的反浓。通過(guò)對(duì)仲裁模式中主從節(jié)點(diǎn)通訊過(guò)程的演示,相信你對(duì)zk的基本原理已經(jīng)有一些理解赞哗,本文中的演示主要使用的都是zkcli這個(gè)命令行工具雷则,它更多的是為了學(xué)習(xí)和演示,下一章我們將直接使用JAVA來(lái)實(shí)現(xiàn)一些例子肪笋。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末月劈,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子藤乙,更是在濱河造成了極大的恐慌猜揪,老刑警劉巖,帶你破解...
    沈念sama閱讀 222,590評(píng)論 6 517
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件坛梁,死亡現(xiàn)場(chǎng)離奇詭異而姐,居然都是意外死亡,警方通過(guò)查閱死者的電腦和手機(jī)划咐,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 95,157評(píng)論 3 399
  • 文/潘曉璐 我一進(jìn)店門拴念,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)钧萍,“玉大人,你說(shuō)我怎么就攤上這事政鼠》缡荩” “怎么了?”我有些...
    開封第一講書人閱讀 169,301評(píng)論 0 362
  • 文/不壞的土叔 我叫張陵公般,是天一觀的道長(zhǎng)弛秋。 經(jīng)常有香客問(wèn)我,道長(zhǎng)俐载,這世上最難降的妖魔是什么蟹略? 我笑而不...
    開封第一講書人閱讀 60,078評(píng)論 1 300
  • 正文 為了忘掉前任,我火速辦了婚禮遏佣,結(jié)果婚禮上挖炬,老公的妹妹穿的比我還像新娘。我一直安慰自己状婶,他們只是感情好意敛,可當(dāng)我...
    茶點(diǎn)故事閱讀 69,082評(píng)論 6 398
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著膛虫,像睡著了一般草姻。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上稍刀,一...
    開封第一講書人閱讀 52,682評(píng)論 1 312
  • 那天撩独,我揣著相機(jī)與錄音,去河邊找鬼账月。 笑死综膀,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的局齿。 我是一名探鬼主播剧劝,決...
    沈念sama閱讀 41,155評(píng)論 3 422
  • 文/蒼蘭香墨 我猛地睜開眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼抓歼!你這毒婦竟也來(lái)了讥此?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 40,098評(píng)論 0 277
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤谣妻,失蹤者是張志新(化名)和其女友劉穎萄喳,沒(méi)想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體拌禾,經(jīng)...
    沈念sama閱讀 46,638評(píng)論 1 319
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡取胎,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,701評(píng)論 3 342
  • 正文 我和宋清朗相戀三年展哭,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了湃窍。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片闻蛀。...
    茶點(diǎn)故事閱讀 40,852評(píng)論 1 353
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖您市,靈堂內(nèi)的尸體忽然破棺而出觉痛,到底是詐尸還是另有隱情,我是刑警寧澤茵休,帶...
    沈念sama閱讀 36,520評(píng)論 5 351
  • 正文 年R本政府宣布薪棒,位于F島的核電站,受9級(jí)特大地震影響榕莺,放射性物質(zhì)發(fā)生泄漏俐芯。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 42,181評(píng)論 3 335
  • 文/蒙蒙 一钉鸯、第九天 我趴在偏房一處隱蔽的房頂上張望吧史。 院中可真熱鬧,春花似錦唠雕、人聲如沸贸营。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,674評(píng)論 0 25
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)钞脂。三九已至,卻和暖如春捕儒,著一層夾襖步出監(jiān)牢的瞬間冰啃,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,788評(píng)論 1 274
  • 我被黑心中介騙來(lái)泰國(guó)打工刘莹, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留亿笤,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 49,279評(píng)論 3 379
  • 正文 我出身青樓栋猖,卻偏偏與公主長(zhǎng)得像最冰,于是被迫代替她去往敵國(guó)和親旺上。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,851評(píng)論 2 361

推薦閱讀更多精彩內(nèi)容