zookeeper

1.研究下數(shù)據(jù)持久化機制
2.研究下dubbo中如何封裝并使用zk的
3.腦裂問題
4.多中心部署數(shù)據(jù)同步問題

https://luyiisme.github.io/2017/04/22/spring-cloud-service-discovery-products/?utm_source=tuicool&utm_medium=referral

1.zk概述

1.1zk是什么

Zookeeper是一個分布式協(xié)調(diào)服務(wù),可用于服務(wù)發(fā)現(xiàn)逝嚎,分布式鎖兼蕊,分布式領(lǐng)導(dǎo)選舉聋涨,配置管理等檐春。

這一切的基礎(chǔ)罐监,都是Zookeeper提供了一個類似于Linux文件系統(tǒng)的樹形結(jié)構(gòu),
可認為是輕量級的內(nèi)存文件系統(tǒng)梳庆,但只適合存少量信息唐责,
完全不適合存儲大量文件或者大文件, 同時提供了對于每個節(jié)點的監(jiān)控與通知機制鳞溉。

Zookeeper 和Redis一樣全量數(shù)據(jù)存儲在內(nèi)存中,以此來提高服務(wù)器吞吐鼠哥、減少延遲的目的熟菲。
100%讀請求壓測QPS 12-13W看政。

// 三大特性
>> Znode數(shù)據(jù)節(jié)點
>> Watcher機制
>> ACL權(quán)限控制

1.2相關(guān)概念

#1.zk集群 (實則是主從復(fù)制模式)
Zookeeper 是一個由多個 server 組成的集群,一個 leader,多個 follower抄罕。
這個不同于我們常見的Master/Slave模式, leader 為客戶端服務(wù)器提供讀寫服務(wù)允蚣,除了leader外其他的機器只能提供讀服務(wù)。
每個 server 保存一份數(shù)據(jù)副本全數(shù)據(jù)一致呆贿,分布式讀 follower嚷兔,
寫由 leader 實施更新請求轉(zhuǎn)發(fā),由 leader 實施更新請求順序進行做入,
來自同一個 client 的更新請求按其發(fā)送順序依次執(zhí)行數(shù)據(jù)更新原子性冒晰,
一次數(shù)據(jù)更新要么成功,要么失敗竟块。
全局唯一數(shù)據(jù)視圖壶运,client 無論連接到哪個 server,數(shù)據(jù)視圖都是一致的實時性浪秘,
在一定事件范圍內(nèi)蒋情,client 能讀到最新數(shù)據(jù)。

#2.zk集群中的角色
Zookeeper集群是一個基于主從復(fù)制的高可用集群耸携,每個服務(wù)器承擔(dān)如下三種角色中的一種:
1) Leader (有投票權(quán), 可處理讀 & 寫請求)
一個Zookeeper集群同一時間只會有一個實際工作的Leader棵癣,它會發(fā)起并維護與各Follwer及Observer間的心跳。
是整個 Zookeeper 集群工作機制中的核心 夺衍。負責(zé)響應(yīng)所有對 ZooKeeper 狀態(tài)變更的請求狈谊。
所有的寫操作必須要通過Leader完成再由Leader將寫操作廣播給其它服務(wù)器。
>> 主要工作:
事務(wù)請求的唯一調(diào)度和處理刷后,保障集群處理事務(wù)的順序性的畴。
集群內(nèi)各服務(wù)器的調(diào)度者渊抄。

2) Follower (有投票權(quán), 可處理讀請求) 
一個Zookeeper集群可能同時存在多個Follower,它會響應(yīng)Leader的心跳护桦。
Follower可直接處理并返回客戶端的讀請求含衔,除了響應(yīng)本服務(wù)器上的讀請求外,
follower 還要處理leader 的提議二庵,并在 leader 提交該提議時在本地也進行提交贪染。
另外需要注意的是,leader 和 follower 構(gòu)成ZooKeeper 集群的法定人數(shù)催享,
也就是說杭隙,只有他們才參與新 leader的選舉、響應(yīng) leader 的提議因妙。

3) Observer (無投票權(quán), 可處理讀請求)
服務(wù)器充當(dāng)一個觀察者的角色痰憎。如果 ZooKeeper 集群的讀取負載很高票髓,
或者客戶端多到跨機房,可以設(shè)置一些 observer 服務(wù)器铣耘,以提高讀取的吞吐量洽沟。
Observer 和 Follower 比較相似,只有一些小區(qū)別:
首先 observer 不屬于法定人數(shù)蜗细,即不參加選舉也不響應(yīng)提議裆操,也不參與寫操作的“過半寫成功”策略;
其次是 observer 不需要將事務(wù)持久化到磁盤炉媒,一旦 observer 被重啟踪区,需要從 leader 重新同步整個namespace。


#3.會話(Session)
Session 指的是 ZooKeeper  服務(wù)器與客戶端會話吊骤。
在 ZooKeeper 中朽缴,一個客戶端連接是指客戶端和服務(wù)器之間的一個 TCP 長連接。
客戶端啟動的時候水援,首先會與服務(wù)器建立一個 TCP 連接密强,
從第一次連接建立開始,客戶端會話的生命周期也開始了蜗元。
通過這個連接或渤,客戶端能夠通過心跳檢測與服務(wù)器保持有效的會話,
也能夠向Zookeeper 服務(wù)器發(fā)送請求并接受響應(yīng)奕扣,同時還能夠通過該連接接收來自服務(wù)器的Watch事件通知薪鹦。 
Session 的 sessionTimeout 值用來設(shè)置一個客戶端會話的超時時間。
當(dāng)由于服務(wù)器壓力太大惯豆、網(wǎng)絡(luò)故障或是客戶端主動斷開連接等各種原因?qū)е驴蛻舳诉B接斷開時池磁,
只要在sessionTimeout規(guī)定的時間內(nèi)能夠重新連接上集群中任意一臺服務(wù)器,那么之前創(chuàng)建的會話仍然有效楷兽。
在為客戶端創(chuàng)建會話之前地熄,服務(wù)端首先會為每個客戶端都分配一個sessionID。
由于 sessionID 是 Zookeeper 會話的一個重要標識芯杀,許多與會話相關(guān)的運行機制都是基于這個 sessionID 的端考,
因此,無論是哪臺服務(wù)器為客戶端分配的 sessionID揭厚,都務(wù)必保證全局唯一却特。
##3.1會話狀態(tài)
在Zookeeper客戶端與服務(wù)端成功完成連接創(chuàng)建后,就創(chuàng)建了一個會話筛圆,
Zookeeper會話在整個運行期間的生命周期中裂明,會在不同的會話狀態(tài)中之間進行切換,
這些狀態(tài)可以分為:
>> CONNECTING
>> CONNECTED
>> RECONNECTING
>> RECONNECTED
>> CLOSE
一旦客戶端開始創(chuàng)建Zookeeper對象太援,那么客戶端狀態(tài)就會變成CONNECTING狀態(tài)闽晦,
同時客戶端開始嘗試連接服務(wù)端轰绵,連接成功后,客戶端狀態(tài)變?yōu)镃ONNECTED尼荆,
通常情況下左腔,由于斷網(wǎng)或其他原因,客戶端與服務(wù)端之間會出現(xiàn)斷開情況捅儒,
一旦碰到這種情況液样,Zookeeper客戶端會自動進行重連服務(wù),同時客戶端狀態(tài)再次變成CONNCTING巧还,
直到重新連上服務(wù)端后鞭莽,狀態(tài)又變?yōu)镃ONNECTED,
在通常情況下麸祷,客戶端的狀態(tài)總是介于CONNECTING 和CONNECTED 之間澎怒。
但是,如果出現(xiàn)諸如會話超時阶牍、權(quán)限檢查或是客戶端主動退出程序等情況喷面,
客戶端的狀態(tài)就會直接變更為CLOSE狀態(tài)。
##3.2會話創(chuàng)建
Session是Zookeeper中的會話實體走孽,代表了一個客戶端會話惧辈,其包含了如下四個屬性:
1) sessionID
會話ID,唯一標識一個會話磕瓷,每次客戶端創(chuàng)建新的會話時盒齿,
Zookeeper都會為其分配一個全局唯一的sessionID。
2) TimeOut
會話超時時間困食,客戶端在構(gòu)造Zookeeper實例時边翁,會配置sessionTimeout參數(shù)用于指定會話的超時時間,
Zookeeper客戶端向服務(wù)端發(fā)送這個超時時間后硕盹,服務(wù)端會根據(jù)自己的超時時間限制最終確定會話的超時時間符匾。
3) TickTime
下次會話超時時間點,為了便于Zookeeper對會話實行”分桶策略”管理莱睁,
同時為了高效低耗地實現(xiàn)會話的超時檢查與清理待讳,
Zookeeper會為每個會話標記一個下次會話超時時間點,其值大致等于當(dāng)前時間加上TimeOut仰剿。
4) isClosing
標記一個會話是否已經(jīng)被關(guān)閉,當(dāng)服務(wù)端檢測到會話已經(jīng)超時失效時痴晦,
會將該會話的isClosing標記為”已關(guān)閉”南吮,這樣就能確保不再處理來自該會話的新請求了。
Zookeeper為了保證請求會話的全局唯一性誊酌,在SessionTracker初始化時部凑,
調(diào)用initializeNextSession方法生成一個sessionID露乏,之后在Zookeeper運行過程中,
會在該sessionID的基礎(chǔ)上為每個會話進行分配涂邀,初始化算法如下:

public static long initializeNextSession(long id) {
  long nextSid = 0;
  // 無符號右移8位使為了避免左移24后瘟仿,再右移8位出現(xiàn)負數(shù)而無法通過高8位確定sid值
  nextSid = (System.currentTimeMillis() << 24) >>> 8;
  nextSid = nextSid | (id << 56);
  return nextSid;
}

##3.3會話管理
Zookeeper的會話管理主要是通過SessionTracker來負責(zé),
其采用了分桶策略(將類似的會話放在同一區(qū)塊中進行管理)進行管理比勉,
以便Zookeeper對會話進行不同區(qū)塊的隔離處理以及同一區(qū)塊的統(tǒng)一處理劳较。

##3.4數(shù)據(jù)節(jié)點 Znode
在Zookeeper中,“節(jié)點"分為兩類:
第一類同樣是指構(gòu)成集群的機器浩聋,我們稱之為機器節(jié)點观蜗;
第二類則是指數(shù)據(jù)模型中的數(shù)據(jù)單元,我們稱之為數(shù)據(jù)節(jié)點一一ZNode衣洁。
Zookeeper將所有數(shù)據(jù)存儲在內(nèi)存中墓捻,數(shù)據(jù)模型是一棵樹(Znode Tree), 
由斜杠(/)的進行分割的路徑,就是一個Znode坊夫,例如/foo/path1砖第。
每個ZNode上都會保存自己的數(shù)據(jù)內(nèi)容,同時還會保存一系列屬性信息环凿。
>>>>>>> 節(jié)點類型 <<<<<<<
在Zookeeper中厂画,node可以分為持久節(jié)點和臨時節(jié)點和順序節(jié)點三大類。
可以通過組合生成如下四種類型節(jié)點:
1) PERSISTENT
持久節(jié)點,節(jié)點創(chuàng)建后便一直存在于Zookeeper服務(wù)器上拷邢,直到有刪除操作來主動清除該節(jié)點袱院。
2) PERSISTENT_SEQUENTIAL
持久順序節(jié)點,相比持久節(jié)點,其新增了順序特性瞭稼,
每個父節(jié)點都會為它的第一級子節(jié)點維護一份順序忽洛,用于記錄每個子節(jié)點創(chuàng)建的先后順序。
在創(chuàng)建節(jié)點時环肘,會自動添加一個數(shù)字后綴欲虚,作為新的節(jié)點名,該數(shù)字后綴的上限是整形的最大值悔雹。
3) EPEMERAL
臨時節(jié)點复哆,臨時節(jié)點的生命周期與客戶端會話綁定,客戶端失效腌零,節(jié)點會被自動清理梯找。
同時,Zookeeper規(guī)定不能基于臨時節(jié)點來創(chuàng)建子節(jié)點益涧,即臨時節(jié)點只能作為葉子節(jié)點锈锤。
4) EPEMERAL_SEQUENTIAL
臨時順序節(jié)點,在臨時節(jié)點的基礎(chǔ)添加了順序特性。

##3.5版本——保證分布式數(shù)據(jù)原子性操作
每個數(shù)據(jù)節(jié)點都具有三種類型的版本信息,對數(shù)據(jù)節(jié)點的任何更新操作都會引起版本號的變化久免。
>> version– 當(dāng)前數(shù)據(jù)節(jié)點數(shù)據(jù)內(nèi)容的版本號
>> cversion– 當(dāng)前數(shù)據(jù)子節(jié)點的版本號
>> aversion– 當(dāng)前數(shù)據(jù)節(jié)點ACL變更版本號
上述各版本號都是表示修改次數(shù)浅辙,如version為1表示對數(shù)據(jù)節(jié)點的內(nèi)容變更了一次。
即使前后兩次變更并沒有改變數(shù)據(jù)內(nèi)容阎姥,version的值仍然會改變记舆。version可以用于寫入驗證,類似于CAS呼巴。

##3.6watcher事件監(jiān)聽器
ZooKeeper允許用戶在指定節(jié)點上注冊一些Watcher泽腮,當(dāng)數(shù)據(jù)節(jié)點發(fā)生變化的時候,
ZooKeeper服務(wù)器會把這個變化的通知發(fā)送給感興趣的客戶端伊磺。

##3.7ACL 權(quán)限控制——保障數(shù)據(jù)的安全
ACL是Access Control Lists 的簡寫, ZooKeeper采用ACL策略來進行權(quán)限控制盛正,有以下權(quán)限:
CREATE:創(chuàng)建子節(jié)點的權(quán)限
READ:獲取節(jié)點數(shù)據(jù)和子節(jié)點列表的權(quán)限
WRITE:更新節(jié)點數(shù)據(jù)的權(quán)限
DELETE:刪除子節(jié)點的權(quán)限
ADMIN:設(shè)置節(jié)點ACL的權(quán)限

##3.8Ensemble
ZooKeeper服務(wù)器組。形成ensemble所需的最小節(jié)點數(shù)為3屑埋。

##3.9層次命名空間(namespace)
下圖描述了用于內(nèi)存表示的ZooKeeper文件系統(tǒng)的樹結(jié)構(gòu)豪筝。ZooKeeper節(jié)點稱為 znode 。
每個znode有一個名稱標識摘能,并用路徑(/)序列分隔续崖。
在圖中,首先有一個由“/”分隔的znode团搞。在根目錄下严望,你有兩個邏輯命名空間 config 和 workers 。
>> config 命名空間用于集中式配置管理逻恐,workers 命名空間用于命名像吻。
>> 在 config 命名空間下,每個znode最多可存儲1MB的數(shù)據(jù)复隆。
這與UNIX文件系統(tǒng)相類似拨匆,除了父znode也可以存儲數(shù)據(jù)。
這種結(jié)構(gòu)的主要目的是存儲同步數(shù)據(jù)并描述znode的元數(shù)據(jù)挽拂。
此結(jié)構(gòu)稱為 ZooKeeper數(shù)據(jù)模型惭每。

##3.10zk的數(shù)據(jù)模型
ZooKeeper數(shù)據(jù)模型中的每個znode都維護著一個 stat 結(jié)構(gòu)。
一個stat僅提供一個znode的元數(shù)據(jù)亏栈。它由版本號台腥,操作控制列表(ACL),時間戳和數(shù)據(jù)長度組成绒北。
1) 版本號
每個znode都有版本號黎侈,這意味著每當(dāng)與znode相關(guān)聯(lián)的數(shù)據(jù)發(fā)生變化時,其對應(yīng)的版本號也會增加镇饮。
當(dāng)多個zookeeper客戶端嘗試在同一znode上執(zhí)行操作時蜓竹,版本號的使用就很重要箕母。
2) 操作控制列表(ACL) 
ACL基本上是訪問znode的認證機制储藐。它管理所有znode讀取和寫入操作俱济。
3) 時間戳
時間戳表示創(chuàng)建和修改znode所經(jīng)過的時間。它通常以毫秒為單位钙勃。
ZooKeeper從“事務(wù)ID"(zxid)標識znode的每個更改蛛碌。
Zxid 是唯一的,并且為每個事務(wù)保留時間辖源,以便你可以輕松地確定從一個請求到另一個請求所經(jīng)過的時間蔚携。
4) 數(shù)據(jù)長度
存儲在znode中的數(shù)據(jù)總量是數(shù)據(jù)長度。最多可以存儲1MB的數(shù)據(jù)克饶。
zk-寫Leader.png
zk-寫Follower-Observer.png
zk-Leader-Follower-Observer讀操作.png
namespace.png

1.3 ZAB(ZooKeeper Atomic Broadcast)

ZAB協(xié)議規(guī)定了兩種模式:崩潰恢復(fù)和消息廣播酝蜒。
基于該協(xié)議,Zookeeper實現(xiàn)了一種主從模式的系統(tǒng)架構(gòu)來保持集群中各個副本之間的數(shù)據(jù)一致性矾湃。

1) 恢復(fù)模式
下述情況ZAB都會進入恢復(fù)模式
>> 當(dāng)整個服務(wù)框架在啟動過程中亡脑。
>> 當(dāng)Leader服務(wù)器出現(xiàn)網(wǎng)絡(luò)中斷崩潰退出與重啟等異常情況。
>> 當(dāng)有新的服務(wù)器加入到集群中且集群處于正常狀態(tài)(廣播模式),新服會與leader進行數(shù)據(jù)同步邀跃,然后進入消息廣播模式霉咨。
主要功能:
選舉產(chǎn)生新的Leader服務(wù)器,同時集群中已有的過半的機器會與該Leader完成狀態(tài)同步拍屑,
這些工作完成后途戒,ZAB協(xié)議就會退出崩潰恢復(fù)模式。

2) 廣播模式
集群狀態(tài)穩(wěn)定僵驰,有了leader且過半機器狀態(tài)同步完成 or 退出崩潰恢復(fù)模式后進入消息廣播模式
主要功能:
正常的消息同步喷斋,把日常產(chǎn)生數(shù)據(jù)從leader同步到learner的過程
ZAB協(xié)議的兩種模式.png
1.崩潰恢復(fù)狀態(tài) – 即選主過程
進入崩潰恢復(fù)模式說明集群目前是存在問題的了,那么此時就需要開始一個選主的過程蒜茴。
zookeeper使用的默認選主算法是FastLeaderElection星爪,它是標準的Fast Paxos算法實現(xiàn),
可解決LeaderElection選舉算法收斂速度慢的問題矮男。

// 特點:
>> Commit過的數(shù)據(jù)不丟失
commit過的數(shù)據(jù)半數(shù)以上參加選舉的follwer都有移必,
而且成為leader的條件是要有最高事務(wù)id即數(shù)據(jù)是最新的。
>> 未commit過的數(shù)據(jù)丟棄
未commit過的數(shù)據(jù)只存在于leader毡鉴,但是leader宕機無法參加首輪選舉崔泵,
epoch會小一輪,最終數(shù)據(jù)會丟棄猪瞬。

// 可通過electionAlg配置項設(shè)置Zookeeper用于領(lǐng)導(dǎo)選舉的算法憎瘸。
到3.4.10版本為止,可選項有
0 基于UDP的LeaderElection
1 基于UDP的FastLeaderElection
2 基于UDP和認證的FastLeaderElection
3 基于TCP的FastLeaderElection
在3.4.10版本中陈瘦,默認值為3幌甘,也即基于TCP的FastLeaderElection。
另外三種算法已經(jīng)被棄用,并且有計劃在之后的版本中將它們徹底刪除而不再支持锅风。

// 服務(wù)器狀態(tài)
>> LOOKING 不確定Leader狀態(tài)酥诽。
該狀態(tài)下的服務(wù)器認為當(dāng)前集群中沒有Leader,會發(fā)起Leader選舉皱埠。
>> FOLLOWING 跟隨者狀態(tài)肮帐。
表明當(dāng)前服務(wù)器角色是Follower,并且它知道Leader是誰边器。
>> LEADING 領(lǐng)導(dǎo)者狀態(tài)训枢。
表明當(dāng)前服務(wù)器角色是Leader,它會維護與Follower間的心跳忘巧。
>> OBSERVING 觀察者狀態(tài)恒界。
表明當(dāng)前服務(wù)器角色是Observer,與Folower唯一的不同在于不參與選舉砚嘴,也不參與集群寫操作時的投票十酣。

// 選票數(shù)據(jù)結(jié)構(gòu)
每個服務(wù)器在進行領(lǐng)導(dǎo)選舉時,會發(fā)送如下關(guān)鍵信息
>> logicClock 每個服務(wù)器會維護一個自增的整數(shù)枣宫,名為logicClock婆誓,它表示這是該服務(wù)器發(fā)起的第多少輪投票
>> state 當(dāng)前服務(wù)器的狀態(tài)
>> self_id 當(dāng)前服務(wù)器的myid
>> self_zxid 當(dāng)前服務(wù)器上所保存的數(shù)據(jù)的最大zxid
>> vote_id 被推舉的服務(wù)器的myid
>> vote_zxid 被推舉的服務(wù)器上所保存的數(shù)據(jù)的最大zxid

// myid
每個Zookeeper服務(wù)器,都需要在數(shù)據(jù)文件夾下創(chuàng)建一個名為myid的文件也颤,
該文件包含整個Zookeeper集群唯一的ID(整數(shù))洋幻。
例如某Zookeeper集群包含三臺服務(wù)器党饮,hostname分別為zoo1雷酪、zoo2和zoo3伪阶,其myid分別為1截亦、2和3,
則在配置文件中其ID與hostname必須一一對應(yīng)伙判,如下所示迈嘹。在該配置文件中鸟蟹,server.后面的數(shù)據(jù)即為myid:
server.1=zoo1:2888:3888
server.2=zoo2:2888:3888
server.3=zoo3:2888:3888

// zxid
類似于RDBMS中的事務(wù)ID蜕提,用于標識一次更新操作的Proposal ID森书。
為了保證順序性,該zkid必須單調(diào)遞增谎势。
因此Zookeeper使用一個64位的數(shù)來表示:
高32位是Leader的epoch凛膏,從1開始,每次選出新的Leader脏榆,epoch加一猖毫。
低32位為該epoch內(nèi)的序號,每次epoch變化须喂,都將低32位的序號重置吁断。
這樣保證了zkid的全局遞增性趁蕊。

////////////////////////// 投票流程開始 //////////////////////////
1) 自增選舉輪次
Zookeeper規(guī)定所有有效的投票都必須在同一輪次中。
每個服務(wù)器在開始新一輪投票時仔役,會先對自己維護的logicClock進行自增操作掷伙。

2) 初始化選票
每個服務(wù)器在廣播自己的選票前,會將自己的投票箱清空骂因。該投票箱記錄了所收到的選票炎咖。
例:服務(wù)器2投票給服務(wù)器3赃泡,服務(wù)器3投票給服務(wù)器1寒波,則服務(wù)器1的投票箱為(2, 3), (3, 1), (1, 1)。
票箱中只會記錄每一投票者的最后一票升熊,如投票者更新自己的選票俄烁,
則其它服務(wù)器收到該新選票后會在自己票箱中更新該服務(wù)器的選票。

3) 發(fā)送初始化選票
每個服務(wù)器最開始都是通過廣播把票投給自己级野。

4) 接收外部投票
服務(wù)器會嘗試從其它服務(wù)器獲取投票页屠,并記入自己的投票箱內(nèi)。
如果無法獲取任何外部投票蓖柔,則會確認自己是否與集群中其它服務(wù)器保持著有效連接辰企。
如果是,則再次發(fā)送自己的投票况鸣;如果否牢贸,則馬上與之建立連接。

5) 判斷選舉輪次
收到外部投票后镐捧,首先會根據(jù)投票信息中所包含的logicClock來進行不同處理:
>> 外部投票的logicClock大于自己的logicClock潜索。
說明該服務(wù)器的選舉輪次落后于其它服務(wù)器的選舉輪次,
立即清空自己的投票箱并將自己的logicClock更新為收到的logicClock懂酱,
然后再對比自己之前的投票與收到的投票以確定是否需要變更自己的投票竹习,
最終再次將自己的投票廣播出去。
>> 外部投票的logicClock小于自己的logicClock列牺。
當(dāng)前服務(wù)器直接忽略該投票整陌,繼續(xù)處理下一個投票。
>> 外部投票的logickClock與自己的相等瞎领。
立即進行選票PK泌辫。

6) 選票PK
選票PK是基于(self_id, self_zxid)與(vote_id, vote_zxid)的對比:
>> 外部投票的logicClock大于自己的logicClock,
則將自己的logicClock及自己的選票的logicClock變更為收到的logicClock
>> 若logicClock一致默刚,
則對比二者的vote_zxid甥郑,若外部投票的vote_zxid比較大,
則將自己的票中的vote_zxid與vote_myid更新為收到的票中的vote_zxid與vote_myid并廣播出去荤西,
另外將收到的票及自己更新后的票放入自己的票箱澜搅。
如果票箱內(nèi)已存在(self_myid, self_zxid)相同的選票伍俘,則直接覆蓋。
>> 若二者vote_zxid一致勉躺,
則比較二者的vote_myid癌瘾,若外部投票的vote_myid比較大,
則將自己的票中的vote_myid更新為收到的票中的vote_myid并廣播出去饵溅,
另外將收到的票及自己更新后的票放入自己的票箱

7) 統(tǒng)計選票
如果已經(jīng)確定有過半服務(wù)器認可了自己的投票(可能是更新后的投票), 
則終止投票妨退。否則繼續(xù)接收其它服務(wù)器的投票。

8) 更新服務(wù)器狀態(tài)
投票終止后蜕企,服務(wù)器開始更新自身狀態(tài)咬荷。
若過半的票投給了自己,則將自己的服務(wù)器狀態(tài)更新為LEADING轻掩,否則將自己的狀態(tài)更新為FOLLOWING幸乒。
////////////////////////// 投票流程結(jié)束 //////////////////////////

/////////// 下圖引自: ///////////
http://www.jasongj.com/zookeeper/fastleaderelection/
zk-集群啟動領(lǐng)導(dǎo)選舉.png
zk-follower重啟領(lǐng)導(dǎo)選舉.png
zk-leader重啟領(lǐng)導(dǎo)選舉.png
2.消息廣播狀態(tài) – 即數(shù)據(jù)同步
client端發(fā)起請求唇牧,讀請求由leader/follower/observer直接返回罕扎,寫請求由它們轉(zhuǎn)發(fā)給leader:
1) Leader 首先為這個事務(wù)分配一個全局單調(diào)遞增的唯一事務(wù)ID (即 ZXID )。
2) 然后發(fā)起proposal給follower丐重,Leader 會為每一個 Follower 都各自分配一個單獨的隊列腔召,
然后將需要廣播的事務(wù) Proposal 依次放入這些隊列中去,并且根據(jù) FIFO策略進行消息發(fā)送扮惦。
3) 每一個 Follower 在接收到這個事務(wù) Proposal 之后臀蛛,都會首先將其以事務(wù)日志的形式寫入到本地磁盤中去,
并且在成功寫入后反饋給 Leader 服務(wù)器一個 Ack 響應(yīng)径缅。
4) 當(dāng) Leader 服務(wù)器接收到超過半數(shù) Follower 的 Ack 響應(yīng)后掺栅,
就會廣播一個Commit 消息給所有的 Follower 服務(wù)器以通知其進行事務(wù)提交,
同時Leader 自身也會完成對事務(wù)的提交纳猪。

1.4 zookeeper數(shù)據(jù)結(jié)構(gòu)圖---->znode

zookeeper的數(shù)據(jù)模型,在結(jié)構(gòu)上和標準文件系統(tǒng)非常相似;擁有一個層次的命名空間, zookeeper樹中的每個節(jié)點都被稱為一個Znode;
和文件系統(tǒng)的目錄樹一樣,zookeeper樹中的每個節(jié)點可以擁有子節(jié)點,但也有不同之處;如下:
// 1.Znode兼具文件和目錄兩種特點
1.即像文件一樣維護著數(shù)據(jù),元信息 ACL 時間戳等數(shù)據(jù)結(jié)構(gòu),
2.又像目錄一樣可以作為路徑標示的一部分,并可以具有子Znode, 
3.用戶可以對Znode具有增 刪 改 查等操作(權(quán)限允許的情況下)

// 2.Znode具有原子性操作
1.讀操作將獲取與節(jié)點相關(guān)的所有的數(shù)據(jù)
2.寫操作也將替換點節(jié)點的所有數(shù)據(jù)
3.另外,每一個節(jié)點都擁有自己的ACL(訪問控制列表),這個列表規(guī)定了用戶的權(quán)限,
即限定了特定用戶對目標節(jié)點可以執(zhí)行的操作

// 3.Znode存儲數(shù)據(jù)大小有限制
1.zookeeper雖然可以關(guān)聯(lián)一些數(shù)據(jù),但是并沒有被設(shè)計為常規(guī)的數(shù)據(jù)庫或者大數(shù)據(jù)存儲,
相反的是,它用來管理調(diào)度數(shù)據(jù),比如分布式應(yīng)用中的配置文件信息,狀態(tài)信息,匯集位置等等;
2.上面的這些數(shù)據(jù)的共同特性就是他們都是很小的數(shù)據(jù),通常以KB為大小單位,
Zookeeper的服務(wù)器和客戶端都設(shè)計為嚴格檢查并限制為每個Znode的數(shù)據(jù)大小最大1M,當(dāng)然常規(guī)遠小于這個值;

// 4.Znode 通過路徑引用
1.如同linxu系統(tǒng)文件路徑一樣,路徑必須是絕對的,因此他們必須是由斜杠字符開頭
2.路徑必須是唯一的
3.路徑由Unicode字符串組成,并且有一些限制,字符串"zookeeper"用來保存管理信息,比如關(guān)鍵配置額信息

// 5.節(jié)點類型
在Zookeeper中氧卧,node可以分為持久節(jié)點和臨時節(jié)點和順序節(jié)點三大類。
可以通過組合生成如下四種類型節(jié)點:
1) PERSISTENT
持久節(jié)點,節(jié)點創(chuàng)建后便一直存在于Zookeeper服務(wù)器上氏堤,直到有刪除操作來主動清除該節(jié)點沙绝。
2) PERSISTENT_SEQUENTIAL
持久順序節(jié)點,相比持久節(jié)點,其新增了順序特性鼠锈,
每個父節(jié)點都會為它的第一級子節(jié)點維護一份順序闪檬,用于記錄每個子節(jié)點創(chuàng)建的先后順序。
在創(chuàng)建節(jié)點時购笆,會自動添加一個數(shù)字后綴粗悯,作為新的節(jié)點名,該數(shù)字后綴的上限是整形的最大值同欠。
3) EPEMERAL
臨時節(jié)點样傍,臨時節(jié)點的生命周期與客戶端會話綁定横缔,客戶端失效,節(jié)點會被自動清理衫哥。
同時茎刚,Zookeeper規(guī)定不能基于臨時節(jié)點來創(chuàng)建子節(jié)點,即臨時節(jié)點只能作為葉子節(jié)點撤逢。
4) EPEMERAL_SEQUENTIAL
臨時順序節(jié)點,在臨時節(jié)點的基礎(chǔ)添加了順序特性膛锭。

// 6.節(jié)點屬性
1.dataVersion 數(shù)據(jù)版本號
每次對節(jié)點進行set操作,dataVersion的值都會增加1(即使設(shè)置的是相同的數(shù)據(jù));
可以避免數(shù)據(jù)更新時出現(xiàn)的先后順序問題;
2.cversion(children version) 子節(jié)點的版本號
當(dāng)znode的子節(jié)點有變化時,cversion的值會增加1
3.aclversion
ACL的版本號
4.cZxid (create Znode zxid)
znode節(jié)點創(chuàng)建的事務(wù)id;在創(chuàng)建新的節(jié)點的時候的事務(wù)id;
5.mZxid (modified Znode zxid)
Znode被修改的事務(wù)id;即每次對znode的修改都會更新mZxid
6.ctime
節(jié)點創(chuàng)建時的時間戳
7.mtime
節(jié)點最新一次更新發(fā)生時的時間戳
8.ephemeralOwner
1) 如果該節(jié)點為臨時節(jié)點,ephemeralOwner 值表示與該節(jié)點綁定的session id,
如果不是,ephemeralOwner 值為0;
2) 在client和server通信之前,首先需要建立連接,該連接稱為session,
連接建立后,如果發(fā)生連接超時,授權(quán)失敗或者顯示關(guān)閉連接,連接便處于closed狀態(tài), 此時session結(jié)束;
znode的樹形結(jié)構(gòu)1.png

1.5 zk的特性

>> 順序一致性
從同一個客戶端發(fā)起的事務(wù)請求,最終將會嚴格地按照其發(fā)起順序被應(yīng)用到Zookeeper中去蚊荣。

>> 原子性
所有事務(wù)請求的處理結(jié)果在整個集群中所有機器上的應(yīng)用情況是一致的初狰,
即整個集群要么都成功應(yīng)用了某個事務(wù),要么都沒有應(yīng)用妇押。

>> 單一視圖
無論客戶端連接的是哪個 Zookeeper 服務(wù)器跷究,其看到的服務(wù)端數(shù)據(jù)模型都是一致的。

>> 可靠性
一旦服務(wù)端成功地應(yīng)用了一個事務(wù)敲霍,并完成對客戶端的響應(yīng),
那么該事務(wù)所引起的服務(wù)端狀態(tài)變更將會一直被保留丁存,除非有另一個事務(wù)對其進行了變更肩杈。

>> 實時性
Zookeeper 保證在一定的時間段內(nèi),客戶端最終一定能夠從服務(wù)端上讀取到最新的數(shù)據(jù)狀態(tài)解寝。

>> 最終一致性:為客戶端展示同一視圖扩然,這是zookeeper最重要的功能。 

1.6 zk的應(yīng)用場景

1.分布式服務(wù)注冊與訂閱

2.分布式配置中心
發(fā)布與訂閱模型聋伦,即所謂的配置中心夫偶,顧名思義就是發(fā)布者將數(shù)據(jù)發(fā)布到ZK節(jié)點上,
供訂閱者獲取數(shù)據(jù)觉增,實現(xiàn)配置信息的集中式管理和動態(tài)更新兵拢。

3.命名服務(wù)
在分布式系統(tǒng)中,通過使用命名服務(wù)逾礁,客戶端應(yīng)用能夠根據(jù)指定名字來獲取資源或服務(wù)的地址说铃,提供者等信息。
被命名的實體通赤诼模可以是集群中的機器腻扇,提供的服務(wù)地址,進程對象等等——這些我們都可以統(tǒng)稱他們?yōu)槊郑∟ame)砾嫉。
其中較為常見的就是一些分布式服務(wù)框架中的服務(wù)地址列表幼苛。
通過調(diào)用ZK提供的創(chuàng)建節(jié)點的API,能夠很容易創(chuàng)建一個全局唯一的path焕刮,這個path就可以作為一個名稱舶沿。

4.分布式鎖
分布式鎖舌剂,這個主要得益于ZooKeeper為我們保證了數(shù)據(jù)的強一致性。
鎖服務(wù)可以分為兩類暑椰,一個是保持獨占霍转,另一個是控制時序。
1) 保持獨占
就是所有試圖來獲取這個鎖的客戶端一汽,最終只有一個可以成功獲得這把鎖避消。
通常的做法是把zk上的一個znode看作是一把鎖,通過create znode的方式來實現(xiàn)召夹。
所有客戶端都去創(chuàng)建 /distribute_lock 節(jié)點岩喷,最終成功創(chuàng)建的那個客戶端也即擁有了這把鎖。
2)控制時序
就是所有視圖來獲取這個鎖的客戶端监憎,最終都是會被安排執(zhí)行纱意,只是有個全局時序了。
做法和上面基本類似鲸阔,只是這里 /distribute_lock 已絆預(yù)先存在偷霉,
客戶端在它下面創(chuàng)建臨時有序節(jié)點(CreateMode.EPHEMERAL_SEQUENTIAL). 
Zk的父節(jié)點(/distribute_lock)維持一份sequence, 保證子節(jié)點創(chuàng)建的時序性,從而也形成了每個客戶端的全局時序.

5.Master選舉

6.負載均衡

1.7 Zab與Paxos

1) Paxos算法的確是不關(guān)心請求之間的邏輯順序褐筛,而只考慮數(shù)據(jù)之間的全序类少,
但很少有人直接使用paxos算法,都會經(jīng)過一定的簡化渔扎、優(yōu)化硫狞。
2) Paxos算法在出現(xiàn)競爭的情況下,其收斂速度很慢晃痴,甚至可能出現(xiàn)活鎖的情況残吩,
例如當(dāng)有三個及三個以上的proposer在發(fā)送prepare請求后,
很難有一個proposer收到半數(shù)以上的回復(fù)而不斷地執(zhí)行第一階段的協(xié)議倘核。
因此泣侮,為了避免競爭,加快收斂的速度笤虫,在算法中引入了一個Leader這個角色旁瘫,
在正常情況下同時應(yīng)該最多只能有一個參與者扮演Leader角色,而其它的參與者則扮演Acceptor的角色琼蚯。
在這種優(yōu)化算法中酬凳,只有l(wèi)eader可以提出議案,從而避免了競爭使得算法能夠快速地收斂而趨于一致遭庶;
而為了保證leader的健壯性宁仔,又引入了leader選舉,再考慮到同步的階段峦睡,
漸漸的你會發(fā)現(xiàn)對Paxos算法的簡化和優(yōu)化已經(jīng)和上面介紹的ZAB協(xié)議很相似了翎苫。

1.8 zk 的 Watcher 機制

1.8.1 概述

// 概述
Zookeeper采用了Watcher機制實現(xiàn)數(shù)據(jù)的發(fā)布/訂閱功能权埠。
該機制在被訂閱對象發(fā)生變化時會異步通知客戶端,
因此客戶端不必在Watcher注冊后輪詢阻塞煎谍,從而減輕了客戶端壓力攘蔽。

Watcher機制實際上與觀察者模式類似,也可看作是一種觀察者模式在分布式場景下的實現(xiàn)方式呐粘。

// Watcher架構(gòu)
Watcher實現(xiàn)由三個部分組成:
>> Zookeeper服務(wù)端满俗;
>> Zookeeper客戶端;
>> 客戶端的ZKWatchManager對象作岖;
客戶端首先將Watcher注冊到服務(wù)端唆垃,同時將Watcher對象保存到客戶端的Watch管理器中。
當(dāng)ZooKeeper服務(wù)端監(jiān)聽的數(shù)據(jù)狀態(tài)發(fā)生變化時痘儡,服務(wù)端會主動通知客戶端辕万,
接著客戶端的Watch管理器會觸發(fā)相關(guān)Watcher來回調(diào)相應(yīng)處理邏輯,從而完成整體的數(shù)據(jù)發(fā)布/訂閱流程沉删。

// Watcher特性
>> 一次性  
Watcher是一次性的渐尿,一旦被觸發(fā)就會移除,再次使用時需要重新注冊丑念。
>> 客戶端順序回調(diào)  
Watcher回調(diào)是順序串行化執(zhí)行的涡戳,只有回調(diào)后客戶端才能看到最新的數(shù)據(jù)狀態(tài)。
一個Watcher回調(diào)邏輯不應(yīng)該太多脯倚,以免影響別的watcher執(zhí)行。
>> 輕量級  
WatchEvent是最小的通信單元嵌屎,結(jié)構(gòu)上只包含通知狀態(tài)推正、
事件類型和節(jié)點路徑,并不會告訴數(shù)據(jù)節(jié)點變化前后的具體內(nèi)容宝惰。
>> 時效性  
Watcher只有在當(dāng)前session徹底失效時才會無效植榕,
若在session有效期內(nèi)快速重連成功,則watcher依然存在尼夺,仍可接收到通知尊残。

// Watcher接口
任何實現(xiàn)了Watcher接口的類就是一個新的Watcher。
Watcher內(nèi)部包含了兩個枚舉類:KeeperState淤堵、EventType寝衫。
// KeeperState (Watcher通知狀態(tài))
KeeperState是客戶端與服務(wù)端連接狀態(tài)發(fā)生變化時對應(yīng)的通知類型。枚舉屬性:
>> Unknown(-1)              屬性過期
>> Disconnected(0)          客戶端與服務(wù)器斷開連接時
>> NoSyncConnected(1)       屬性過期
>> SyncConnected(3)         客戶端與服務(wù)器正常連接時
>> AuthFailed(4)            身份認證失敗時
>> ConnectedReadOnly(5)     
3.3.0版本后支持只讀模式拐邪,一般情況下ZK集群中半數(shù)以上服務(wù)器正常慰毅,zk集群才能正常對外提供服務(wù)。
該屬性的意義在于:
若客戶端設(shè)置了允許只讀模式扎阶,則當(dāng)zk集群中只有少于半數(shù)的服務(wù)器正常時汹胃,
會返回這個狀態(tài)給客戶端婶芭,此時客戶端只能處理讀請求
>> SaslAuthenticated(6)     服務(wù)器采用SASL做校驗時
>> Expired(-112)            會話session失效時

// EventType (Watcher事件類型)
EventType是數(shù)據(jù)節(jié)點(znode)發(fā)生變化時對應(yīng)的通知類型。
EventType變化時KeeperState永遠處于SyncConnected通知狀態(tài)下着饥;
當(dāng)KeeperState發(fā)生變化時犀农,EventType永遠為None。枚舉屬性如下:
>> None (-1)                    無
>> NodeCreated (1)          Watcher監(jiān)聽的數(shù)據(jù)節(jié)點被創(chuàng)建時
>> NodeDeleted (2)          Watcher監(jiān)聽的數(shù)據(jù)節(jié)點被刪除時
>> NodeDataChanged (3)      Watcher監(jiān)聽的數(shù)據(jù)節(jié)點內(nèi)容發(fā)生變更時(無論內(nèi)容數(shù)據(jù)是否變化)
>> NodeChildrenChanged (4)  Watcher監(jiān)聽的數(shù)據(jù)節(jié)點的子節(jié)點列表發(fā)生變更時
注:客戶端接收到的相關(guān)事件通知中只包含狀態(tài)及類型等信息宰掉,不包括節(jié)點變化前后的具體內(nèi)容呵哨,
變化前的數(shù)據(jù)需業(yè)務(wù)自身存儲,變化后的數(shù)據(jù)需調(diào)用get等方法重新獲取贵扰。
Watcher架構(gòu).png
Watcher類圖.png

客戶端Watcher管理器:ZKWatchManager數(shù)據(jù)結(jié)構(gòu)

//ZKWatchManager維護了三個map仇穗,key代表數(shù)據(jù)節(jié)點的絕對路徑,value代表注冊在當(dāng)前節(jié)點上的watcher集合

// 代表節(jié)點上內(nèi)容數(shù)據(jù)戚绕、狀態(tài)信息變更相關(guān)監(jiān)聽
private final Map<String, Set<Watcher>> dataWatches = new HashMap<String, Set<Watcher>>();

// 代表節(jié)點變更相關(guān)監(jiān)聽
private final Map<String, Set<Watcher>> existWatches = new HashMap<String, Set<Watcher>>();

// 代表節(jié)點子列表變更相關(guān)監(jiān)聽
private final Map<String, Set<Watcher>> childWatches = new HashMap<String, Set<Watcher>>();

服務(wù)端Watcher管理器:WatchManager數(shù)據(jù)結(jié)構(gòu)

// WatchManager維護了兩個map
// 說明:WatchManager中的Watcher對象不是客戶端用戶定義的Watcher纹坐,
//       而是服務(wù)端中實現(xiàn)了Watcher接口的ServerCnxn抽象類,
//       該抽象類代表了一個客戶端與服務(wù)端的連接

// key代表數(shù)據(jù)節(jié)點路徑舞丛,value代表客戶端連接的集合耘子,該map作用為:
// 通過一個指定znode路徑可找到其映射的所有客戶端,當(dāng)znode發(fā)生變更時
// 可快速通知所有注冊了當(dāng)前Watcher的客戶端
private final HashMap<String, HashSet<Watcher>> watchTable = new HashMap<String, HashSet<Watcher>>();

// key代表一個客戶端與服務(wù)端的連接球切,value代表當(dāng)前客戶端監(jiān)聽的所有數(shù)據(jù)節(jié)點路徑
// 該map作用為:當(dāng)一個連接徹底斷開時谷誓,可快速找到當(dāng)前連接對應(yīng)的所有
// 注冊了監(jiān)聽的節(jié)點,以便移除當(dāng)前客戶端對節(jié)點的Watcher
private final HashMap<Watcher, HashSet<String>> watch2Paths = new HashMap<Watcher, HashSet<String>>();
Watcher注冊流程.png
Watcher通知流程.png
org.apache.zookeeper.ZooKeeper.png

http://www.reibang.com/p/c68b6b241943 (zk 的 Watcher 機制)

2.zk安裝與使用

zk的端口說明

一吨凑、zookeeper有三個端口(可以修改)
1捍歪、2181:對clinet端提供服務(wù)
2、3888:選舉leader使用
3鸵钝、2888:集群內(nèi)機器通訊使用(Leader監(jiān)聽此端口)

二糙臼、部署時注意
1、單機單實例恩商,只要端口不被占用即可
2变逃、單機偽集群(單機,部署多個實例)怠堪,三個端口必須修改為組組不一樣, 如:
myid1 : 2181,3888,2888
myid2 : 2182,3788,2788
myid3 : 2183,3688,2688
3揽乱、集群(一臺機器部署一個實例)

三、集群為大于等于3個基數(shù)
如 3粟矿、5凰棉、7....,不宜太多,集群機器多了選舉和數(shù)據(jù)同步耗時時長長嚷炉,不穩(wěn)定渊啰。
目前覺得,三臺選舉+N臺observer很不錯。

2.1 docker-compose安裝zk集群(偽集群)

docker-compose.yml

version: '3.4'

services:
  zoo1:
    image: zookeeper:3.4
    restart: always
    hostname: zoo1
    ports:
      - 2181:2181
    environment:
      ZOO_MY_ID: 1
      ZOO_SERVERS: server.1=0.0.0.0:2888:3888 server.2=zoo2:2888:3888 server.3=zoo3:2888:3888

  zoo2:
    image: zookeeper:3.4
    restart: always
    hostname: zoo2
    ports:
      - 2182:2181
    environment:
      ZOO_MY_ID: 2
      ZOO_SERVERS: server.1=zoo1:2888:3888 server.2=0.0.0.0:2888:3888 server.3=zoo3:2888:3888

  zoo3:
    image: zookeeper:3.4
    restart: always
    hostname: zoo3
    ports:
      - 2183:2181
    environment:
      ZOO_MY_ID: 3
      ZOO_SERVERS: server.1=zoo1:2888:3888 server.2=zoo2:2888:3888 server.3=0.0.0.0:2888:3888
      
# notice: execute command 'docker-compose up -d' to run zookeeper clusters

2.2 CentOS7 下安裝zk (單機版)

#1.下載zk
wget https://mirrors.tuna.tsinghua.edu.cn/apache/zookeeper/zookeeper-3.4.14/zookeeper-3.4.14.tar.gz

#2.解壓重命名
tar -zxf zookeeper-3.4.14.tar.gz
mv zookeeper-3.4.14 zookeeper

#3.將zookeeper-3.4.3/conf目錄下的zoo_sample.cfg文件拷貝一份绘证,命名為為“zoo.cfg”
cd /opt/software/zookeeper/conf
cp zoo_sample.cfg zoo.cfg

#4.修改zoo.cfg內(nèi)容為:
見下文

#5.創(chuàng)建dataDir參數(shù)指定的目錄
這里指的是“/opt/software/zk_runtime/data”)隧膏,并在目錄下創(chuàng)建文件,命名為“myid”嚷那。

#6.編輯“myid”文件胞枕,并在對應(yīng)的IP的機器上輸入對應(yīng)的編號。
如在zk1上魏宽,“myid”文件內(nèi)容就是1腐泻。由于本次只在單點上進行安裝配置,所以只有一個server.1队询。
若還有其他服務(wù)器派桩,比如地址為192.168.1.102,
則在zoo.cfg文件中還需加入server.2=192.168.0.105:2888:3888蚌斩。
那么myid文件在192.168.0.105服務(wù)器上的內(nèi)容就是2铆惑。

#7.在/etc/profile文件中設(shè)置PATH
export ZOOKEEPER_HOME=/opt/software/zookeeper 
PATH=$ZOOKEEPER_HOME/bin:$PATH

#8.啟動zk
zkServer.sh start

#9.查看是否啟動成功
lsof -i:2181

zoo.cfg

tickTime=2000

#配置 Zookeeper 接受客戶端初始化連接時最長能忍受多少個心跳時間間隔數(shù)。
#這里所說的客戶端不是用戶連接 Zookeeper服務(wù)器的客戶端送膳,而是 Zookeeper 服務(wù)器集群中連接到 Leader 的 Follower 服務(wù)器
#當(dāng)已經(jīng)超過 10 個心跳的時間(也就是 tickTime)長度后,
#Zookeeper 服務(wù)器還沒有收到客戶端的返回信息员魏,那么表明這個客戶端連接失敗。
#總的時間長度就是 10*2000=20 秒叠聋。
initLimit=10

#這個配置項標識 Leader 與 Follower 之間發(fā)送消息撕阎,請求和應(yīng)答時間長度,
#最長不能超過多少個 tickTime 的時間長度碌补,總的時間長度就是 5*2000=10 秒虏束。
syncLimit=5

dataDir=/opt/software/zk_runtime/data
dataLogDir=/opt/software/zk_runtime/logs

clientPort=2181

#server.A=B:C:D
#其中 A 是一個數(shù)字,表示這個是第幾號服務(wù)器厦章;B 是這個服務(wù)器的 ip 地址魄眉;
#C 表示的是這個服務(wù)器與集群中的 Leader 服務(wù)器交換信息的端口;
#D 表示的是萬一集群中的 Leader 服務(wù)器掛了闷袒,需要一個端口來重新進行選舉,選出一個新的 Leader岩梳,
#而這個端口就是用來執(zhí)行選舉時服務(wù)器相互通信的端口囊骤。
#如果是偽集群的配置方式,由于 B 都是一樣冀值,
#所以不同的 Zookeeper 實例通信端口號不能一樣也物,所以要給它們分配不同的端口號。
#2888端口號是zookeeper服務(wù)之間通信的端口列疗,而3888是zookeeper與其他應(yīng)用程序通信的端口滑蚯。
server.1=192.168.0.104:2888:3888

2.3 CentOS7 下安裝zk (集群版)

2.x Zookeeper數(shù)據(jù)查看工具ZooInspector

#1.下載
https://issues.apache.org/jira/secure/attachment/12436620/ZooInspector.zip

#2.解壓即可

#3.運行jar包
// 進入目錄ZooInspector\build,運行zookeeper-dev-ZooInspector.jar
java -jar zookeeper-dev-ZooInspector.jar //執(zhí)行成功后,會彈出java ui client

#4.添加監(jiān)控主機, 查看相關(guān)機器上的數(shù)據(jù)
點擊左上角綠色連接按鈕告材,輸入zk服務(wù)地址:ip或者主機名:2181

2.x zk監(jiān)控工具PrettyZoo

https://github.com/vran-dev/PrettyZoo/releases

PrettyZoo.png

https://www.cnblogs.com/linbingdong/p/6253479.html (paxos算法)
http://www.reibang.com/p/82d0eb9da176 (curator系列)
http://www.reibang.com/p/70151fc0ef5d (curator-->核心參考)
https://blog.csdn.net/HappyHeng/article/details/89303197 (權(quán)限)

4.代碼實現(xiàn)

4.1工具類封裝(參考apache dubbo)

https://github.com/zhangxin1932/java-tools.git

4.2分布式鎖實現(xiàn)

http://www.reibang.com/p/e4eb43573f84

5. 常見問題集錦

5.1 zookeeper寫入數(shù)據(jù)超過1M大小

https://zookeeper.apache.org/doc/r3.3.3/zookeeperAdmin.html
#需要通過Java的環(huán)境變量來設(shè)置
jute.maxbuffer:(Java system property: jute.maxbuffer) 
#方案
首先這個參數(shù)的修改坤次,有兩種方式:
方式一:在zk的部署機器上,進入zk的conf目錄下斥赋,新建一個java.env文件缰猴,然后寫入如下內(nèi)容:
export JVMFLAGS="-Xms512m -Xmx2048m -Djute.maxbuffer=10485760 " (10MB)
方式二:
修改bin目錄下的zkServer.sh文件,在vi中搜索start單詞疤剑,然后修改如下參數(shù):
nohup "$JAVA" "-Djute.maxbuffer=10485760  -Dzookeeper.log.dir=${ZOO_LOG_DIR}" "-Dzookeeper.root.logger=${ZOO_LOG4J_PROP}"

#重啟服務(wù)
這里要說明的是滑绒,為了避免造成大范圍影響,我們操作的方式是先滾動重啟服務(wù)端zk集群隘膘,
即單臺修改完成之后疑故,即可重啟,然后使用jps -lvm命令弯菊,可以在進程列表中找到我們啟動的進程纵势,
如果觀察環(huán)境參數(shù)中附帶了我們設(shè)置的值,即代表修改生效误续。
然后依次再滾動重啟其他的zk機器吨悍。啟動的順序一定是按照myid的值,從小到大依次啟動蹋嵌,否則有可能導(dǎo)致啟動失敗育瓜。
在所有服務(wù)端啟動成功后,可以根據(jù)需要決定是否需要啟動客戶端栽烂,
如果你真的決定客戶端會寫入大于1MB的數(shù)據(jù)包躏仇,那么就要在客戶端任務(wù)啟動的時候,同樣加上x相同的環(huán)境變量:
java -Djute.maxbuffer=10485760 -jar  com.xxxx.Main

https://cloud.tencent.com/developer/article/1516691 (zk單節(jié)點存儲限制)
https://blog.csdn.net/lbh199466/article/details/100077248 (zk之坑)

參考資源
https://blog.csdn.net/qq_25537177/article/details/84235890 (zk安裝)
https://zookeeper.apache.org/doc/r3.4.14/zookeeperObservers.html (zk安裝配置observer)
http://www.reibang.com/p/f45af8027d7f (zooinspector數(shù)據(jù)監(jiān)控工具)
http://www.imooc.com/article/251135 (zk概念)
http://www.jasongj.com/zookeeper/fastleaderelection/ (ZAB協(xié)議)
https://www.cnblogs.com/frankltf/p/10392151.html (ZAB協(xié)議)
http://ddrv.cn/a/174259 (ZAB協(xié)議)
https://blog.csdn.net/wangshouhan/article/details/89919404 (選舉源碼)
https://blog.csdn.net/u014636209/article/details/85411512 (znode)

踩坑指南
https://yq.aliyun.com/articles/227260 (EPHEMERAL實現(xiàn)集群的陷阱)
http://jm.taobao.org/2018/06/13/%E5%81%9A%E6%9C%8D%E5%8A%A1%E5%8F%91%E7%8E%B0%EF%BC%9F/ (阿里對zk的評與用)

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末腺办,一起剝皮案震驚了整個濱河市焰手,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌怀喉,老刑警劉巖书妻,帶你破解...
    沈念sama閱讀 219,110評論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異躬拢,居然都是意外死亡躲履,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,443評論 3 395
  • 文/潘曉璐 我一進店門聊闯,熙熙樓的掌柜王于貴愁眉苦臉地迎上來工猜,“玉大人,你說我怎么就攤上這事菱蔬∨袼В” “怎么了史侣?”我有些...
    開封第一講書人閱讀 165,474評論 0 356
  • 文/不壞的土叔 我叫張陵,是天一觀的道長魏身。 經(jīng)常有香客問我惊橱,道長,這世上最難降的妖魔是什么叠骑? 我笑而不...
    開封第一講書人閱讀 58,881評論 1 295
  • 正文 為了忘掉前任李皇,我火速辦了婚禮,結(jié)果婚禮上宙枷,老公的妹妹穿的比我還像新娘掉房。我一直安慰自己,他們只是感情好慰丛,可當(dāng)我...
    茶點故事閱讀 67,902評論 6 392
  • 文/花漫 我一把揭開白布卓囚。 她就那樣靜靜地躺著,像睡著了一般诅病。 火紅的嫁衣襯著肌膚如雪哪亿。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,698評論 1 305
  • 那天贤笆,我揣著相機與錄音蝇棉,去河邊找鬼。 笑死芥永,一個胖子當(dāng)著我的面吹牛篡殷,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播埋涧,決...
    沈念sama閱讀 40,418評論 3 419
  • 文/蒼蘭香墨 我猛地睜開眼板辽,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了棘催?” 一聲冷哼從身側(cè)響起劲弦,我...
    開封第一講書人閱讀 39,332評論 0 276
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎醇坝,沒想到半個月后邑跪,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,796評論 1 316
  • 正文 獨居荒郊野嶺守林人離奇死亡呼猪,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,968評論 3 337
  • 正文 我和宋清朗相戀三年呀袱,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片郑叠。...
    茶點故事閱讀 40,110評論 1 351
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖明棍,靈堂內(nèi)的尸體忽然破棺而出乡革,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 35,792評論 5 346
  • 正文 年R本政府宣布沸版,位于F島的核電站嘁傀,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏视粮。R本人自食惡果不足惜细办,卻給世界環(huán)境...
    茶點故事閱讀 41,455評論 3 331
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望蕾殴。 院中可真熱鬧笑撞,春花似錦、人聲如沸钓觉。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,003評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽荡灾。三九已至瓤狐,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間批幌,已是汗流浹背础锐。 一陣腳步聲響...
    開封第一講書人閱讀 33,130評論 1 272
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留荧缘,地道東北人皆警。 一個月前我還...
    沈念sama閱讀 48,348評論 3 373
  • 正文 我出身青樓,卻偏偏與公主長得像胜宇,于是被迫代替她去往敵國和親耀怜。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 45,047評論 2 355

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

  • 序言 ??Apache ZooKeeper是由集群(節(jié)點組)使用的一種服務(wù)桐愉,用于在自身之間協(xié)調(diào)财破,并通過穩(wěn)健的同步技...
    抄無止境閱讀 1,036評論 0 1
  • zookeeper為分布式應(yīng)用提供了高效且可靠的分布式協(xié)調(diào)服務(wù)左痢,提供了如統(tǒng)一命名服務(wù)、配置管理和分布式鎖等分布式的...
    小manong閱讀 1,262評論 0 0
  • https://blog.csdn.net/gs80140/article/details/51496925 ht...
    小陳阿飛閱讀 190評論 0 0
  • 之前我在去小學(xué)看望老師時系洛,正好是剛放學(xué)俊性,我在學(xué)校門口見到了一群人聚在一起拿著手機。走近一看發(fā)現(xiàn)他們都在玩王者榮...
    偽文藝的俏小生閱讀 151評論 1 1
  • 想吃烤鴨豬蹄牛肉紅燒肉糖醋里脊小龍蝦咖喱雞蝦仁天吶描扯,什么都想吃
    不吃零食閱讀 164評論 0 1