Zookeeper是什么框架
分布式的、開源的分布式應用程序協調服務,原本是Hadoop、HBase的一個重要組件。它為分布式應用提供一致性服務的軟件,包括:配置維護、域名服務、分布式同步、組服務等。
應用場景
Zookeeper的功能很強大,應用場景很多,結合我實際工作中使用Dubbo框架的情況,Zookeeper主要是做注冊中心用。基於Dubbo框架開發的提供者、消費者都向Zookeeper注冊自己的URL,消費者還能拿到並訂閱提供者的注冊URL,以便在后續程序的執行中去調用提供者。而提供者發生了變動,也會通過Zookeeper向訂閱的消費者發送通知。
Paxos算法& Zookeeper使用協議
Paxos算法是分布式選舉算法,Zookeeper使用的 ZAB協議(Zookeeper原子廣播),二者有相同的地方,比如都有一個Leader,用來協調N個Follower的運行;Leader要等待超半數的Follower做出正確反饋之后才進行提案;二者都有一個值來代表Leader的周期。
不同的地方在於:
ZAB用來構建高可用的分布式數據主備系統(Zookeeper),Paxos是用來構建分布式一致性狀態機系統。
Paxos算法、ZAB協議要想講清楚可不是一時半會的事兒,自1990年萊斯利·蘭伯特提出Paxos算法以來,因為晦澀難懂並沒有受到重視。后續幾年,蘭伯特通過好幾篇論文對其進行更進一步g地解釋,也直到06年谷歌發表了三篇論文,選擇Paxos作為chubby cell的一致性算法,Paxos才真正流行起來。
對於普通開發者來說,尤其是學習使用Zookeeper的開發者明確一點就好:分布式Zookeeper選舉Leader服務器的算法與Paxos有很深的關系。
選舉算法和流程
詳情可參看我之前的文章《ZooKeeper集群安裝配置使用》第6節“ZooKeeper選舉機制”,有個簡單的描述。
Zookeeper有哪幾種節點類型
持久:創建之后一直存在,除非有刪除操作,創建節點的客戶端會話失效也不影響此節點。
持久順序:跟持久一樣,就是父節點在創建下一級子節點的時候,記錄每個子節點創建的先后順序,會給每個子節點名加上一個數字后綴。
臨時:創建客戶端會話失效(注意是會話失效,不是連接斷了),節點也就沒了。不能建子節點。
臨時順序:不用解釋了吧。
Zookeeper對節點的watch監聽通知是永久的嗎?
不是。官方聲明:一個Watch事件是一個一次性的觸發器,當被設置了Watch的數據發生了改變的時候,則服務器將這個改變發送給設置了Watch的客戶端,以便通知它們。
為什么不是永久的,舉個例子,如果服務端變動頻繁,而監聽的客戶端很多情況下,每次變動都要通知到所有的客戶端,這太消耗性能了。
一般是客戶端執行getData(“/節點A”,true),如果節點A發生了變更或刪除,客戶端會得到它的watch事件,但是在之后節點A又發生了變更,而客戶端又沒有設置watch事件,就不再給客戶端發送。
在實際應用中,很多情況下,我們的客戶端不需要知道服務端的每一次變動,我只要最新的數據即可。
部署方式?集群中的機器角色都有哪些?集群最少要幾台機器
單機,集群。Leader、Follower。集群最低3(2N+1)台,保證奇數,主要是為了選舉算法。
集群如果有3台機器,掛掉一台集群還能工作嗎?掛掉兩台呢?
記住一個原則:過半存活即可用。
集群支持動態添加機器嗎?
其實就是水平擴容了,Zookeeper在這方面不太好。兩種方式:
全部重啟:關閉所有Zookeeper服務,修改配置之后啟動。不影響之前客戶端的會話。
逐個重啟:顧名思義。這是比較常用的方式。
1. Zookeeper是什么框架
分布式的、開源的分布式應用程序協調服務,原本是Hadoop、HBase的一個重要組件。它為分布式應用提供一致性服務的軟件,包括:配置維護、域名服務、分布式同步、組服務等。
2. 應用場景
Zookeeper的功能很強大,應用場景很多,結合我實際工作中使用Dubbo框架的情況,Zookeeper主要是做注冊中心用。基於Dubbo框架開發的提供者、消費者都向Zookeeper注冊自己的URL,消費者還能拿到並訂閱提供者的注冊URL,以便在后續程序的執行中去調用提供者。而提供者發生了變動,也會通過Zookeeper向訂閱的消費者發送通知。
。
8. zookeeper是如何保證事務的順序一致性的
zookeeper采用了遞增的事務Id來標識,所有的proposal都在被提出的時候加上了zxid,zxid實際上是一個64位的數字,高32位是epoch用來標識leader是否發生改變,如果有新的leader產生出來,epoch會自增,低32位用來遞增計數。當新產生proposal的時候,會依據數據庫的兩階段過程,首先會向其他的server發出事務執行請求,如果超過半數的機器都能執行並且能夠成功,那么就會開始執行
9. zookeeper是如何選取主leader的?
當leader崩潰或者leader失去大多數的follower,這時zk進入恢復模式,
zk中znode類型有四種,持久化目錄節點 持久化順序編號目錄節點(有順序 能夠在注冊機器等許多場景用到) 臨時目錄節點 臨時順序編號節點
zk的通知機制
client端會對某個znode建立一個watcher事件,當該znode發生變化時,這些client會收到zk的通知,然后client可以根據znode變化來做出業務上的改變等。
zk的配置管理
程序分布式的部署在不同的機器上,將程序的配置信息放在zk的znode下,當有配置發生改變時,也就是znode發生變化時,可以通過改變zk中某個目錄節點的內容,利用water通知給各個客戶端 從而更改配置。
zk的命名服務
命名服務是指通過指定的名字來獲取資源或者服務的地址,利用zk創建一個全局的路徑,這個路徑就可以作為一個名字,指向集群中的集群,提供的服務的地址,或者一個遠程的對象等等。
分布式通知和協調
對於系統調度來說:操作人員發送通知實際是通過控制台改變某個節點的狀態,然后zk將這些變化發送給注冊了這個節點的watcher的所有客戶端。
對於執行情況匯報:每個工作進程都在某個目錄下創建一個臨時節點。並攜帶工作的進度數據,這樣匯總的進程可以監控目錄子節點的變化獲得工作進度的實時的全局情況。
10. 機器中為什么會有master;
在分布式環境中,有些業務邏輯只需要集群中的某一台機器進行執行,其他的機器可以共享這個結果,這樣可以大大減少重復計算,提高性能,於是就需要進行master選舉。
11. ZooKeeper集群中服務器之間是怎樣通信的?
Leader服務器會和每一個Follower/Observer服務器都建立TCP連接,同時為每個F/O都創建一個叫做LearnerHandler的實體。LearnerHandler主要負責Leader和F/O之間的網絡通訊,包括數據同步,請求轉發和Proposal提議的投票等。Leader服務器保存了所有F/O的LearnerHandler。
12. zookeeper是否會自動進行日志清理?如何進行日志清理?
zk自己不會進行日志清理,需要運維人員進行日志清理
13. ZK選舉過程
當leader崩潰或者leader失去大多數的follower,這時候zk進入恢復模式,恢復模式需要重新選舉出一個新的leader,讓所有的Server都恢復到一個正確的狀態。Zk的選舉算法使用ZAB協議:
① 選舉線程由當前Server發起選舉的線程擔任,其主要功能是對投票結果進行統計,並選出推薦的Server;
② 選舉線程首先向所有Server發起一次詢問(包括自己);
③ 選舉線程收到回復后,驗證是否是自己發起的詢問(驗證zxid是否一致),然后獲取對方的id(myid),並存儲到當前詢問對象列表中,最后獲取對方提議的leader相關信息(id,zxid),並將這些信息存儲到當次選舉的投票記錄表中;
④ 收到所有Server回復以后,就計算出zxid最大的那個Server,並將這個Server相關信息設置成下一次要投票的Server;
⑤ 線程將當前zxid最大的Server設置為當前Server要推薦的Leader,如果此時獲勝的Server獲得n/2 + 1的Server票數, 設置當前推薦的leader為獲勝的Server,將根據獲勝的Server相關信息設置自己的狀態,否則,繼續這個過程,直到leader被選舉出來。
通過流程分析我們可以得出:要使Leader獲得多數Server的支持,則Server總數最好是奇數2n+1,且存活的Server的數目不得少於n+1
14. master/slave之間通信
Storm:定期掃描
PtBalancer:節點監聽
15. 節點變多時,PtBalancer速度變慢
類似問題:根據Netflix的Curator作者所說,ZooKeeper真心不適合做Queue,或者說ZK沒有實現一個好的Queue,詳細內容可以看https://cwiki.apache.org/confluence/display/CURATOR/TN4,
原因有五:
① ZK有1MB 的傳輸限制。 實踐中ZNode必須相對較小,而隊列包含成千上萬的消息,非常的大。
② 如果有很多節點,ZK啟動時相當的慢。 而使用queue會導致好多ZNode. 你需要顯著增大 initLimit 和 syncLimit.
③ ZNode很大的時候很難清理。Netflix不得不創建了一個專門的程序做這事。
④ 當很大量的包含成千上萬的子節點的ZNode時, ZK的性能變得不好
⑤ ZK的數據庫完全放在內存中。 大量的Queue意味着會占用很多的內存空間。
盡管如此, Curator還是創建了各種Queue的實現。 如果Queue的數據量不太多,數據量不太大的情況下,酌情考慮,還是可以使用的。
16. 客戶端對ServerList的輪詢機制是什么
隨機,客戶端在初始化( new ZooKeeper(String connectString, int sessionTimeout, Watcher watcher) )的過程中,將所有Server保存在一個List中,然后隨機打散,形成一個環。之后從0號位開始一個一個使用。
兩個注意點:
① Server地址能夠重復配置,這樣能夠彌補客戶端無法設置Server權重的缺陷,但是也會加大風險。(比如: 192.168.1.1:2181,192.168.1.1:2181,192.168.1.2:2181).
② 如果客戶端在進行Server切換過程中耗時過長,那么將會收到SESSION_EXPIRED. 這也是上面第1點中的加大風險之處。
17. 客戶端如何正確處理CONNECTIONLOSS(連接斷開) 和 SESSIONEXPIRED(Session 過期)兩類連接異常
在ZooKeeper中,服務器和客戶端之間維持的是一個長連接,在 SESSION_TIMEOUT 時間內,服務器會確定客戶端是否正常連接(客戶端會定時向服務器發送heart_beat),服務器重置下次SESSION_TIMEOUT時間。因此,在正常情況下,Session一直有效,並且zk集群所有機器上都保存這個Session信息。在出現問題情況下,客戶端與服務器之間連接斷了(客戶端所連接的那台zk機器掛了,或是其它原因的網絡閃斷),這個時候客戶端會主動在地址列表(初始化的時候傳入構造方法的那個參數connectString)中選擇新的地址進行連接。
好了,上面基本就是服務器與客戶端之間維持長連接的過程了。在這個過程中,用戶可能會看到兩類異常CONNECTIONLOSS(連接斷開) 和SESSIONEXPIRED(Session 過期)。
CONNECTIONLOSS發生在上面紅色文字部分,應用在進行操作A時,發生了CONNECTIONLOSS,此時用戶不需要關心我的會話是否可用,應用所要做的就是等待客戶端幫我們自動連接上新的zk機器,一旦成功連接上新的zk機器后,確認剛剛的操作A是否執行成功了。
18. 一個客戶端修改了某個節點的數據,其它客戶端能夠馬上獲取到這個最新數據嗎
ZooKeeper不能確保任何客戶端能夠獲取(即Read Request)到一樣的數據,除非客戶端自己要求:方法是客戶端在獲取數據之前調用org.apache.zookeeper.AsyncCallback.VoidCallback, java.lang.Object) sync.
通常情況下(這里所說的通常情況滿足:1. 對獲取的數據是否是最新版本不敏感,2. 一個客戶端修改了數據,其它客戶端是否需要立即能夠獲取最新),可以不關心這點。
在其它情況下,最清晰的場景是這樣:ZK客戶端A對 /my_test 的內容從 v1->v2, 但是ZK客戶端B對 /my_test 的內容獲取,依然得到的是 v1. 請注意,這個是實際存在的現象,當然延時很短。解決的方法是客戶端B先調用 sync(), 再調用 getData().
19. ZK為什么不提供一個永久性的Watcher注冊機制
不支持用持久Watcher的原因很簡單,ZK無法保證性能。
使用watch需要注意的幾點
① Watches通知是一次性的,必須重復注冊.
② 發生CONNECTIONLOSS之后,只要在session_timeout之內再次連接上(即不發生SESSIONEXPIRED),那么這個連接注冊的watches依然在。
③ 節點數據的版本變化會觸發NodeDataChanged,注意,這里特意說明了是版本變化。存在這樣的情況,只要成功執行了setData()方法,無論內容是否和之前一致,都會觸發NodeDataChanged。
④ 對某個節點注冊了watch,但是節點被刪除了,那么注冊在這個節點上的watches都會被移除。
⑤ 同一個zk客戶端對某一個節點注冊相同的watch,只會收到一次通知。
⑥ Watcher對象只會保存在客戶端,不會傳遞到服務端。
20. 我能否收到每次節點變化的通知
如果節點數據的更新頻率很高的話,不能。
原因在於:當一次數據修改,通知客戶端,客戶端再次注冊watch,在這個過程中,可能數據已經發生了許多次數據修改,因此,千萬不要做這樣的測試:”數據被修改了n次,一定會收到n次通知”來測試server是否正常工作。(我曾經就做過這樣的傻事,發現Server一直工作不正常?其實不是)。即使你使用了GitHub上這個客戶端也一樣。
21. 能為臨時節點創建子節點嗎
不能。
22. 是否可以拒絕單個IP對ZK的訪問,操作
ZK本身不提供這樣的功能,它僅僅提供了對單個IP的連接數的限制。你可以通過修改iptables來實現對單個ip的限制,當然,你也可以通過這樣的方式來解決。https://issues.apache.org/jira/browse/ZOOKEEPER-1320
23. 在getChildren(String path, boolean watch)是注冊了對節點子節點的變化,那么子節點的子節點變化能通知嗎
不能
24. 創建的臨時節點什么時候會被刪除,是連接一斷就刪除嗎?延時是多少?
連接斷了之后,ZK不會馬上移除臨時數據,只有當SESSIONEXPIRED之后,才會把這個會話建立的臨時數據移除。因此,用戶需要謹慎設置Session_TimeOut