一、Zookeeper簡介
zookeeper起源于雅虎研究院,主要用于解決服務間協(xié)同以及單節(jié)點問題,所以雅虎研究院就研發(fā)了無單節(jié)點問題的分布式協(xié)同系統(tǒng)-Zookeeper逐样。
1泳桦、 在開源項目的使用:
? ? Hadoop:使用zookeeper做NameNode的高可用
? ? HBase:保證集群中只有一個master
? ? kafka:集群成員管理汤徽、controller選舉
2、 典型的應用場景:
? ? 配置管理
? ? 分布式鎖
? ? 組成員管理
3灸撰、數據模型:
? ? Zookeeper的數據模型是層次模型(比如文件系統(tǒng))谒府,zk采用層次模型主要考慮以下幾點優(yōu)勢:
? ? ? ? (1)、便于表達數據間的層次關系
? ? ? ? ( 2)浮毯、便于為不同的應用分配不同的命名空間(namespace)
? ? zk的每個節(jié)點稱為znode完疫,不同于文件系統(tǒng)每個節(jié)點都可以保存數據,每個節(jié)點都有一個版本(version)债蓝,版本從0開始計數
4趋惨、 znode分類:
? ? 持久性znode(PERSISTENT):即使發(fā)生zk集群宕機或者client宕機也不會丟失
? ? 臨時行znode(EPHEMERMAL):client宕機或者client超過timeout沒有給zk集群發(fā)送消息,這樣的節(jié)點就會消失
? ? znode的節(jié)點也可以是順序性的惦蚊,每個順序性的znode節(jié)點是關聯(lián)一個單調遞增的整數器虾,這個單調遞增的整數是znode的節(jié)點的后綴
? ? 持久順序性的znode節(jié)點(PERSISTENT_SEQUENTIAL):除了具備持久性znode節(jié)點的特性外,znode的名字具備順序性
? ? 臨時順序性的znode節(jié)點(EPHEMERMAL_SEQUENTIAL):除了具備臨時性znode節(jié)點的特性外蹦锋,znode的名字具備順序性
二兆沙、 Leader選舉
1、Zookeeper節(jié)點有4種狀態(tài)
LOOKING:尋找Leader狀態(tài)莉掂,處于該狀態(tài)需要進入選舉流程
LEADING:領導者狀態(tài)葛圃,處于該狀態(tài)的節(jié)點說明是角色已經是Leader
FOLLOWING:跟隨者狀態(tài),表示Leader已經選舉出來憎妙,當前節(jié)點角色是follower
OBSERVER:觀察者狀態(tài)库正,表明當前節(jié)點角色是observer
2、事務ID
ZooKeeper狀態(tài)的每次變化都接收一個ZXID(ZooKeeper事務id)形式的標記厘唾。ZXID是一個64位的數字褥符,由Leader統(tǒng)一分配,全局唯一抚垃,不斷遞增喷楣。
ZXID展示了所有的ZooKeeper的變更順序。每次變更會有一個唯一的zxid鹤树,如果zxid1小于zxid2說明zxid1在zxid2之前發(fā)生铣焊。
3、Zookeeper集群初始化啟動時Leader選舉(以三臺實例為例)
在集群初始化階段罕伯,當有一臺服務器ZK1啟動時曲伊,其單獨無法進行和完成Leader選舉,當第二臺服務器ZK2啟動時追他,此時兩臺機器可以相互通信坟募,每臺機器都試圖找到Leader绽榛,于是進入Leader選舉過程。選舉過程開始婿屹,過程如下:
(1) 每個Server發(fā)出一個投票。由于是初始情況推溃,ZK1和ZK2都會將自己作為Leader服務器來進行投票昂利,每次投票會包含所推舉的服務器的myid和ZXID,使用(myid, ZXID)來表示铁坎,此時ZK1的投票為(1, 0)蜂奸,ZK2的投票為(2, 0),然后各自將這個投票發(fā)給集群中其他機器硬萍。
(2) 接受來自各個服務器的投票扩所。集群的每個服務器收到投票后,首先判斷該投票的有效性朴乖,如檢查是否是本輪投票祖屏、是否來自LOOKING狀態(tài)的服務器。
(3) 處理投票买羞。針對每一個投票袁勺,服務器都需要將別人的投票和自己的投票進行比較,規(guī)則如下
· 優(yōu)先檢查ZXID畜普。ZXID比較大的服務器優(yōu)先作為Leader期丰。
· 如果ZXID相同,那么就比較myid吃挑。myid較大的服務器作為Leader服務器钝荡。
對于ZK1而言,它的投票是(1, 0)舶衬,接收ZK2的投票為(2, 0)埠通,首先會比較兩者的ZXID,均為0逛犹,再比較myid植阴,此時ZK2的myid最大,于是ZK2勝圾浅。ZK1更新自己的投票為(2, 0)掠手,并將投票重新發(fā)送給ZK2。
(4) 統(tǒng)計投票狸捕。每次投票后喷鸽,服務器都會統(tǒng)計投票信息,判斷是否已經有過半機器接受到相同的投票信息灸拍,對于ZK1做祝、ZK2而言砾省,都統(tǒng)計出集群中已經有兩臺機器接受了(2, 0)的投票信息,此時便認為已經選出ZK2作為Leader混槐。
(5) 改變服務器狀態(tài)编兄。一旦確定了Leader,每個服務器就會更新自己的狀態(tài)声登,如果是Follower狠鸳,那么就變更為FOLLOWING,如果是Leader悯嗓,就變更為Leader)
三件舵、 zk的ACL權限控制
1、ACL 權限控制
使用:scheme:id:perm 來標識脯厨,主要涵蓋 3 個方面:
權限模式(Scheme):授權的策略
授權對象(ID):授權的對象 【比如ip/auth/world】
權限(Permission):授予的權限 [比如cdrwa]
??【重要】其特性如下:
ZooKeeper的權限控制是基于每個znode節(jié)點的铅祸,需要對每個節(jié)點設置權限
每個znode支持設置多種權限控制方案和多個權限
子節(jié)點不會繼承父節(jié)點的權限,客戶端無權訪問某節(jié)點合武,但可能可以訪問它的子節(jié)點
2临梗、scheme? 采用何種方式授權
world:默認方式,相當于全部都能訪問
auth:代表已經認證通過的用戶(cli中可以通過addauth digest user:pwd 來添加當前上下文中的授權用戶)
digest:即用戶名:密碼這種方式認證稼跳,這也是業(yè)務系統(tǒng)中最常用的夜焦。用 username:password 字符串來產生一個MD5串,然后該串被用來作為ACL ID岂贩。認證是通過明文發(fā)送username:password 來進行的茫经,當用在ACL時,表達式為username:base64 萎津,base64是password的SHA1摘要的編碼卸伞。
ip:使用客戶端的主機IP作為ACL ID 。這個ACL表達式的格式為addr/bits 锉屈,此時addr中的有效位與客戶端addr中的有效位進行比對荤傲。
比如在根目錄“/”,針對用戶mxy授予所有的權限: setAcl / auth:mxy:cdrwa
比如在根目錄“/”颈渊,針對IP“127.0.0.1”授予所有的權限:setAcl / ip:127.0.0.1:cdrwa
比如在根目錄“/”遂黍,針對所有的用戶授予所有的權限:setAcl / world:cdrwa
3、permission? 授予什么權限
CREATE俊嗽、READ雾家、WRITE、DELETE绍豁、ADMIN 也就是 增芯咧、刪、改、查敬飒、管理權限邪铲,這5種權限簡寫為crwda
詳細的如下:
CREATE? c 可以創(chuàng)建子節(jié)點
DELETE? d 可以刪除子節(jié)點(僅下一級節(jié)點)
READ? ? ? r 可以讀取節(jié)點數據及顯示子節(jié)點列表
WRITE? ? w 可以設置節(jié)點數據
ADMIN? ? a 可以設置節(jié)點訪問控制列表權限
??【注意】:這5種權限中,delete是指對子節(jié)點的刪除權限无拗,其它4種權限指對自身節(jié)點的操作權限
4带到、ACL 相關命令
getAcl? ? ? ? getAcl <path>? ? 讀取ACL權限
setAcl? ? ? ? setAcl <path> <acl>? ? 設置ACL權限
addauth? ? ? addauth <scheme> <auth>? ? 添加認證用戶
四、 zk實現master-worker協(xié)同
? 1英染、 什么是master-worker架構:
? ? master-worker架構揽惹,其中有一個master和多個worker,master負責監(jiān)聽woker狀態(tài)税迷,并為worker分配任務。
? ? 1锹漱、任何時刻系統(tǒng)中只能有一個master箭养,多個master會導致腦裂現象
? ? 2、系統(tǒng)中除了處于active狀態(tài)的mater還有一個backup master哥牍,如果active master宕機毕泌,backup master 很快進入active狀態(tài)
? ? 3、master實時監(jiān)聽worker狀態(tài)嗅辣,能夠實時收到worker成員的變化通知撼泛。master在收到worker成員有變化的時候,通常進行任務重新分配
? ? 2澡谭、zk在其他分布式服務中的應用
? ? 1愿题、Hbase:其采用的是master-worker架構。HMBase是系統(tǒng)中的master蛙奖,HRegiionServer是系統(tǒng)中的worker潘酗。HMBase監(jiān)控HBase cluser中的worker變化,把region分配給HregionServer雁仲。系統(tǒng)中只有一個HMaster處于active狀態(tài)仔夺,其他處于備用狀態(tài)
? ? 2:kafka:一個kafka集群有多個broker,這些broker是系統(tǒng)的worker攒砖。其broker會競選一個controller缸兔,這個controller就是系統(tǒng)中的master,負責把topic partition分配給其他broker吹艇。
五惰蜜、 zk架構解析
? ? zk可以分為單機模式和集群模式(一般是3臺集群,保證高可用受神,如果是2臺雖然可以搭建master-worker但是不能保證高可用蝎抽,因為當master掛掉,選舉的數是1小于2的大多數)。集群模式下樟结,一個leader節(jié)點养交,多個follower節(jié)點。leader節(jié)點可以處理讀寫請求瓢宦,follower在接到寫請求時會把請求轉發(fā)給leader來處理碎连。
? ? session機制:zk客戶端和zk集群中的某個節(jié)點創(chuàng)建一個session⊥月模客戶端可以主動關閉session鱼辙,如果超zk節(jié)點超過timeout沒有收到客戶端的心跳消息的話,zk節(jié)點會關閉session玫镐。另外zk客戶端如果發(fā)現連接的zk出錯倒戏,會主動和其他zk節(jié)點建立連接。
? ? zk集群時恐似,配置文件的server列表 例如:server.1=127.0.0.1:3333:3334 ,其中3333用于集群通信杜跷,3334用于leader選舉。
? ? 【重點】:zk為了保證數據一直性采用的是線性化寫入的方式矫夷,這點類似于mysql的serialize隔離級別葛闷,并發(fā)非常低。
【注意】zk的API是wait-free機制(一個操作是否執(zhí)行完不影響另外操作的執(zhí)行)双藕,這個跟傳統(tǒng)的鎖不一致淑趾,zk不直接提供鎖機制,但是借助API可以實現加鎖的功能(比如創(chuàng)建節(jié)點)
【注意】Zookeeper不適合存儲大量的數據:
? ? 1. 設計方面:ZooKeeper需要把所有的數據(它的data tree)加載到內存中忧陪。這就決定了ZooKeeper存儲的數據量受內存的限制扣泊。這一點和基于內存KV存儲Redis比較像。
? ? 2. 工程方面:ZooKeeper的設計目標是為協(xié)同服務提供數據存儲嘶摊,數據的高可用性和性能是最重要的系統(tǒng)指標旷赖,處理大數量不是ZooKeeper的首要目標
六、zookeeper 開發(fā)
Apache Curator是Apache Zookeeper的Java客戶端更卒。其簡化Zookeeper客戶端的使用等孵,并為分布式協(xié)同服務提供高質量的實現,Curator最初是Netflix研發(fā)蹂空,后來捐獻給Apache俯萌。
Curator 技術棧:
Client:封裝來zookeeper類,管理和ZK集群的連接上枕,并提供類重建連接機制咐熙。
Framework:為所有的zookeeper操作提供類重試機制,對外提供一個Fluent風格的API
Recipes:使用Framework實現類大量的Zookeeper協(xié)同服務辨萍。
Extensions:擴展模塊棋恼。
一返弹、zk在服務發(fā)現方面的應用:主要應用于微服務架構/分布式架構/面向服務架構的場景。在這些場景下爪飘,一個服務通常需要松耦合的多個協(xié)同的協(xié)同才能完成义起。服務發(fā)現就是讓服務發(fā)現相關的服務。服務發(fā)現需要提供一下功能:
1师崎、服務注冊
2默终、服務實例的獲取
3、服務變化的通知機制
curator有一個擴展叫做curator-x-discovery犁罩。其基于zk實現服務發(fā)現功能齐蔽。curator-x-discovery設計如下:
使用一個base path作為整個服務發(fā)現的根目錄。在這個根目錄下是各個服務的目錄床估,服務目錄下是服務實例含滴,實例的數據是JSON虛擬化的內容。服務實例對應的節(jié)點可以像普通的zk節(jié)點一樣設置持久性丐巫、臨時性谈况、順序性。
4鞋吉、zk-curator-x-discory設計:
5鸦做、curator-x-discovery API設計如下(主要就是3個Java類)
zk-curator-x-discovery-接口設計:
ServiceDiscovery: 提供服務注冊是對zk節(jié)點的更新操作励烦,服務發(fā)現是對zk節(jié)點的讀取操作谓着,最核心的類,包含ServiceProvider和ServiceCache實例的構建坛掠。
ServiceProvider: 其封裝ProviderStraegy和InstanceProvider赊锚,InstanceProvider的數據來自zk在本地的一個緩存。ProviderStraegy提供服務三種發(fā)現策略屉栓,比如輪訓舷蒲、隨機、粘性友多。
ServiceCache: 將在zk中的服務數據緩存至本地牲平,并監(jiān)聽服務變化,實時更新緩存域滥。
??【注意】這三個類在使用時都需要先調用start(),在使用完之后調用close纵柿,釋放自己創(chuàng)建的資源,其不會釋放上游資源启绰,比如ServiceDiscory的close不會調用CuratorFramework的close方法昂儒。
七、Paxos算法
ZK采用Zab算法保證保證分布式服務的CP委可,Zab算法是Paxos算法的變體渊跋,Paxos算法解決的是一個分布式系統(tǒng)如何就某個值(決議)達成一致。一個典型的場景是,在一個分布式數據庫系統(tǒng)中拾酝,如果各個節(jié)點的初始狀態(tài)一致燕少,每個節(jié)點執(zhí)行相同的操作序列,那么他們最后能夠得到一個一致的狀態(tài)微宝。為了保證每個節(jié)點執(zhí)行相同的命令序列棺亭,需要在每一條指令上執(zhí)行一個“一致性算法”以保證每個節(jié)點看到的指令一致。zookeeper使用的zab算法是該算法的一個實現蟋软。在Paxos算法中镶摘,有三種角色:Proposer (提議者),Acceptor(接受者),Learners(記錄員)
Proposer提議者:(發(fā)送prepare和accept請求)只要Proposer發(fā)的提案Propose被半數以上的Acceptor接受岳守,Proposer就認為該提案例的value被選定了凄敢。
Acceptor接受者:(處理prepare和accept請求)只要Acceptor接受了某個提案,Acceptor就認為該提案例的value被選定了
Learner記錄員:(獲取Paxos算法決定的結果)Acceptor告訴Learner哪個value就是提議者的提案被選定湿痢,Learner就認為哪個value被選定涝缝。
Paxos算法分為兩個階段,具體如下:
階段一 (準leader 確定 ):
(a) Proposer 選擇一個提案編號 N譬重,然后向半數以上的Acceptor 發(fā)送編號為 N 的 Prepare 請求拒逮。
(b) 如果一個 Acceptor 收到一個編號為 N 的 Prepare 請求,且 N 大于該 Acceptor 已經響應過的所有 Prepare 請求的編號臀规,那么它就會將它已經接受過的編號最大的提案(如果有的話)作為響 應反饋給 Proposer滩援,同時該Acceptor 承諾不再接受任何編號小于 N 的提案。
階段二 (leader 確認):
(a) 如果 Proposer 收到半數以上 Acceptor 對其發(fā)出的編號為 N 的 Prepare 請求的響應塔嬉,那么它就會發(fā)送一個針對[N,V]提案的 Accept 請求給半數以上的 Acceptor玩徊。注意:V 就是收到的響應中編號最大的提案的 value ,如果響應中不包含任何提案谨究,那么V 就由 Proposer 自己決定恩袱。
(b) 如果 Acceptor 收到一個針對編號為 N 的提案的 Accept 請求,只要該 Acceptor 沒有對編號
大于 N 的 Prepare 請求做出過響應胶哲,它就接受該提案畔塔。
Paxos算法偽代碼
Paxos算法偽代碼描述
使用paxos算法實現一致性的有redis嘵兵選舉master算法(采用的是paxos算法的變體),google的分布式鎖Chubby系統(tǒng)鸯屿,zk選leader機制(Zab算法也是Paxos算法的變體)等
八澈吨、協(xié)同服務領域,對比Google分布式鎖Chubby系統(tǒng)
Chubby架構:
一個Chubby集群叫做一個cell碾盟,由多個replica實例組成棚辽,其中一個replica是整個cell的master。所有的讀寫請求只能通過master來處理冰肴∏辏客戶端和Chubby服務端建立連接后榔组,客戶端會維持一個保證數據一致性的cache。Chubby系統(tǒng)采用的是和zk一樣的層次數據模型(文件系統(tǒng)模型)
Chubby API:
Open(): 使用唯一路徑明訪問文件的API联逻,其他API都使用一個文件句柄搓扯。
Close():關閉文件句柄。
Poison():取消文件句柄正在進程的操作包归,主要用于多線程場景锨推。
文件操作API:getContentsAndStat()、SetContent()公壤、Delete()
鎖API:Acquire()换可、TryAcquire()、Release()厦幅、GetSequencer()沾鳄、SetSequencer()、CheckSequencer()
Chubby 和 Zookeeper對比:
相同之處:
1确憨、Chubby的文件相當于Zookeeper的znode译荞,都是用來存儲少量的數據,不適合存儲較大的數據量休弃。
2吞歼、都只提供文件的全部讀取或者寫入。
3塔猾、都提供類似Linux文件系統(tǒng)的API篙骡。
4、都提供數據更新的通知機制桥帆,Chubby的Event機制医增,ZK的watcher機制慎皱。
5老虫、寫操作都是通過Leader/master來進行。
6茫多、都支持永久性和臨時性數據祈匙。
7、都使用副本機制(復制狀態(tài))來做容錯天揖。
不同之處:
1夺欲、Chubby內置分布式鎖的支持(Chubby主要就是做這件事的),zk本身不提供鎖今膊,但是可以基于znode實現鎖機制些阅。
2、Chubby讀寫操作都必須通過master來執(zhí)行(優(yōu)點是數據一致性高斑唬,缺點是并發(fā)下降市埋,沒有利用多實例的優(yōu)點)黎泣,ZK讀操作可以通過任意的節(jié)點來執(zhí)行(數據一致性弱一些,可能讀到久數據)缤谎。
3抒倚、Chubby使用Paxos數據一致性協(xié)議,ZK采用的是Zab數據一致性協(xié)議(Paxos的變體)坷澡。
4托呕、Chubby提供保證數據一致性的cache(比如更新操作,Chubby先通知所有客戶端更新cache后频敛,才進行更新操作项郊,然后返回操作結果),而ZK不執(zhí)行cache斟赚,但是可以通過watcher機制實現Cache(zk是先更新呆抑,再通知client的watcher)。
九汁展、系統(tǒng)服務領域對比Etcd
1鹊碍、Etcd采用的是Raft算法?
Raft 是一個共識算法(consensus algorithm),所謂共識食绿,就是多個節(jié)點對某個事情達成一致的看法侈咕,即使是在部分節(jié)點故障、網絡延時器紧、網絡分割的情況下耀销。在分布式系統(tǒng)中,共識算法更多用于提高系統(tǒng)的容錯性铲汪,比如分布式存儲中的復制集(replication)熊尉。
Raft協(xié)議中,一個節(jié)點任一時刻處于以下三個狀態(tài)之一:leader掌腰、follower狰住、candidate;所有節(jié)點啟動時都是follower狀態(tài)齿梁;在一段時間內如果沒有收到來自leader的心跳催植,從follower切換到candidate,發(fā)起選舉勺择;如果收到majority的造成票(含自己的一票)則切換到leader狀態(tài)创南;如果發(fā)現其他節(jié)點的狀態(tài)比自己更新,則主動切換到follower省核。
系統(tǒng)中最多只有一個leader稿辙,如果在一段時間里發(fā)現沒有l(wèi)eader,則大家通過選舉-投票選出leader气忠。leader會不停的給follower發(fā)心跳消息邻储,表明自己的存活狀態(tài)未桥。如果leader故障,那么follower會轉換成candidate芥备,重新選出leader冬耿。
raft將共識問題分解成兩個相對獨立的問題,leader election萌壳,log replication亦镶。流程是先選舉出leader,然后leader負責復制袱瓮、提交log(log中包含command)缤骨;為了在任何異常情況下系統(tǒng)不出錯,即滿足safety屬性尺借,對leader election绊起,log replication兩個子問題有諸多約束
? ? (1)、leader election約束:
? ? 獲得多數贊成票
? ? 同一任期內最多只能投一票燎斩,先來先得
? ? 選舉人必須比自己知道的更多(比較term虱歪,log index,比如Mongo/Redis故障轉移時master選舉機制)
? ? (2)栅表、log replication約束:
? ? 一個log被復制到大多數節(jié)點笋鄙,就是committed,保證不會回滾【這點分布式事物不同的是怪瓶,分布式事物是原子性的萧落,全部成功或者全部失敗,如果提交后部分成功洗贰,會通過coorinator進行回滾】
? ? leader一定包含最新的committed log找岖,因此leader只會追加日志,不會刪除覆蓋日志
? ? 不同節(jié)點敛滋,某個位置上日志相同许布,那么這個位置之前的所有日志一定是相同的
2、Etcd服務介紹
etcd是一個高可用的分布式KV系統(tǒng)矛缨,可以用來實現各種分布式協(xié)同服務爹脾。etcd采用一致性算法Raft帖旨,基于Go語言實現箕昭。目前火熱的K8s的服務發(fā)現和配置信息管理采用的是Etcd中間件做協(xié)同服務。tcd使用的是bbolt存儲引擎解阅,會將數據持久化磁盤落竹,而Zookeeper需要將所有的數據都要加載至內存中,所以內存是ZK的瓶頸
etcd的數據模型是KV模型货抄,所有的key構成了一個扁平的命名空間述召,所有的key通過字典排序朱转。整個etcd的KV存儲維護一個遞增的64位整數。etcd使用這個整數位為每一次KV更新分配一個revision积暖。每一個key可以有多個revision藤为。每一次更新操作都會生成一個新的revision。刪除操作會生成一個tombstone的新的revision夺刑。如果進行了compaction缅疟,etcd會對compaction revision之前的key-value進行清理。整個KV上最新的一次更新操作的revision叫做整個KV的revision遍愿。其中createVersion是創(chuàng)建key的version存淫,modRevision是更新key的revision,version是key的版本號沼填。比如獲取key值數據:(kvs:[{
? ? ? ? ? ? "key": "Zm9v",
? ? ? ? ? ? "create_revision": "9030",
? ? ? ? ? ? "mod_revision": "9070",
? ? ? ? ? ? "version": "41",
? ? ? ? ? ? "value": "YmFy"
? ? ? ? }])桅咆。
可以把etcd看作一個狀態(tài)機。etcd的狀態(tài)是所有的key-value坞笙,revision是狀態(tài)編號岩饼,每一個狀態(tài)轉換是若干個key的更新操作。
etcd使用bbolt進行KV的存儲薛夜。bbolt使用持久化的B+tree保存key-value忌愚。三元組(major工三、sub转培、type)是B+tree的key,major是revision蕊唐,sub用來區(qū)別一次更新中的key腊徙,type保存可選的特殊值(例如type為t代表這個三元組對應一個tombstone)简十,這樣做的目的是為了加速某一個revision上的范圍查找。另外etcd還維護一個in-memory的B-tree的索引撬腾,這個索引中的key是key-value中的key螟蝙。
reference:
【Raft算法,很棒的動畫展示】:http://thesecretlivesofdata.com/raft/