概述
zookeeper的內(nèi)存模型:
- zk的數(shù)據(jù)存在內(nèi)存當(dāng)中(高性能),但是同時(shí)記錄操作日志+內(nèi)存快照(二進(jìn)制),持久化。(類(lèi)似于Redis)
- 狀態(tài)機(jī)+命令日志:內(nèi)存中保存數(shù)據(jù)的最終狀態(tài),命令日志中保存所有的操作過(guò)程,內(nèi)存快照中保存某一時(shí)間節(jié)點(diǎn)的狀態(tài)機(jī)中的數(shù)據(jù)。
zookeeper集群的高性能:
- 內(nèi)存讀取數(shù)據(jù)
- 所有Node直接response 讀請(qǐng)求,不需要走M(jìn)aster
- 集群有Obeserver角色,擴(kuò)展了讀的性能,又不影響投票和寫(xiě)的性能(不參與選舉投票和ack proposal)
Zk的寫(xiě)機(jī)制
所有的寫(xiě)的請(qǐng)求,轉(zhuǎn)發(fā)給Leader,Leader采取兩階段提交的方式。
- 本地生成自增的zxid,生成Proposal日志(持久化)
- 廣播所有的Follower,并且有單獨(dú)的線(xiàn)程統(tǒng)計(jì) Ack Proposal的數(shù)量
- Proposal ack過(guò)半之后,廣播Commit,并且把這個(gè)request丟到各自的CommitProcessor里面處理
- Master commit日志,更新lastCommitZxid,apply到內(nèi)存樹(shù)中,Ack client操作成功
這里和Raft系統(tǒng)不同,Raft是master先commit,再ack 客戶(hù),最后在下一個(gè)心跳消息里面通知所有小弟們commit
zk的讀機(jī)制
- Client直接和Zk的節(jié)點(diǎn)直連,如果是讀的請(qǐng)求,那么Node可以直接response,不需要走M(jìn)aster,保障了基于內(nèi)存的快速讀取
- zk集群不能保證讀取到的數(shù)據(jù)是最新的,但是可以保證讀取到的數(shù)據(jù),都是過(guò)半節(jié)點(diǎn)ACK確認(rèn)的數(shù)據(jù)
- zk的讀取本來(lái)就沒(méi)有鎖的概念,一個(gè)消息還在寫(xiě),是讀取不到的,不像Hashtable。即使Master完成了寫(xiě)的操作,如果Follower沒(méi)有Sync數(shù)據(jù)的話(huà),也是讀取不到最新的數(shù)據(jù)的
- Zk直接兩種模式:默認(rèn)模式(CP模式 選舉時(shí)停止讀寫(xiě)請(qǐng)求)、Readonlymode模式(AP模式 選舉時(shí)停止寫(xiě)請(qǐng)求,但是可以讀)
zk的角色
- LOOKING:進(jìn)入leader選舉狀態(tài)
- FOLLOWING:leader選舉結(jié)束,進(jìn)入follower狀態(tài)
- LEADING:leader選舉結(jié)束,進(jìn)入leader狀態(tài)
- OBSERVING:處于觀察者狀態(tài)
Observers和follower非常類(lèi)似,observer的優(yōu)點(diǎn)
- 可以靈活的擴(kuò)展zk集群,新增和減少observer不會(huì)觸發(fā)重新選舉
- 大幅提升讀取的速度的同時(shí),不會(huì)降低寫(xiě)的速度
- 一定程度上提升容災(zāi)率,因?yàn)镺bserver的宕機(jī)不會(huì)影響集群繼續(xù)服務(wù)
選舉過(guò)程
和Raft算法相比,有點(diǎn)過(guò)度設(shè)計(jì)了,解決的是一個(gè)標(biāo)準(zhǔn)的拜占庭問(wèn)題,不僅僅可以處理節(jié)點(diǎn)故障問(wèn)題,還可以防止節(jié)點(diǎn)作弊。代價(jià)是消息交互的次數(shù)大大增加。
每個(gè)Node都在統(tǒng)計(jì)leader獲取的投票數(shù),只有Node統(tǒng)計(jì)有新leader產(chǎn)生時(shí),才會(huì)從Looking狀態(tài),切換成Following狀態(tài),而不是收到Leader的消息,就進(jìn)入Following狀態(tài)。
- Zk所有Node啟動(dòng)時(shí)都有一個(gè)獨(dú)立的線(xiàn)程,不停的check自己當(dāng)前的Role
- 啟動(dòng)剛啟動(dòng)時(shí)、Follower 超時(shí)仍未收到心跳、Leader不能收到過(guò)半心跳恢復(fù)時(shí),節(jié)點(diǎn)都會(huì)進(jìn)入Looking狀態(tài)
- 每個(gè)節(jié)點(diǎn)可以多次投票,每次投票都會(huì)廣播出去,一輪投票必定有一個(gè)leader產(chǎn)生,數(shù)據(jù)最新的節(jié)點(diǎn)肯定會(huì)成為leader,server id 越大,成為leader的概率也越高。
zk 一致性保證
只有超過(guò)半數(shù)節(jié)點(diǎn)Ack了的事務(wù)操作,才會(huì)被commit,才會(huì)最終響應(yīng)到客戶(hù)端。所以響應(yīng)了客戶(hù)端的操作,不管leader是否掛了,新leader中肯定存了這個(gè)日志,否則選舉中不會(huì)獲勝。
未完成半數(shù)Ack的事務(wù)操作,leader掛了,新leader可能保存這個(gè)日志,也可能沒(méi)有保存這個(gè)日志。
- 如果新leader沒(méi)有這個(gè)事務(wù)操作的日志,依賴(lài)客戶(hù)端的超時(shí)重試機(jī)制,來(lái)完成這個(gè)proposal,客戶(hù)端會(huì)發(fā)起重試。
- 如果新leader有這個(gè)uncommitted的事務(wù)操作日志,則會(huì)替代老leader繼續(xù)完成這個(gè)操作
zk 事務(wù)操作有序性
- zk只能保證寫(xiě)操作的有序性,而不能保證讀寫(xiě)的有序性,比如Client先發(fā)起一個(gè)寫(xiě)操作,再迅速發(fā)起一個(gè)讀取操作,并不能保證讀取的最新的數(shù)據(jù)。
- zk通過(guò)自增的zxid的編號(hào),在前期proposal和持久化的時(shí)候,并不需要嚴(yán)格有序,提升寫(xiě)的性能,但是在commit的時(shí)候,通過(guò)鎖和有序FIFO隊(duì)列,保證嚴(yán)格的有序commit,apply到內(nèi)存樹(shù)中。