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服務,修改配置以後啓動。不影響以前客戶端的會話。
逐個重啓:顧名思義。這是比較經常使用的方式。java
分佈式的、開源的分佈式應用程序協調服務,本來是Hadoop、HBase的一個重要組件。它爲分佈式應用提供一致性服務的軟件,包括:配置維護、域名服務、分佈式同步、組服務等。node
Zookeeper的功能很強大,應用場景不少,結合我實際工做中使用Dubbo框架的狀況,Zookeeper主要是作註冊中心用。基於Dubbo框架開發的提供者、消費者都向Zookeeper註冊本身的URL,消費者還能拿到並訂閱提供者的註冊URL,以便在後續程序的執行中去調用提供者。而提供者發生了變更,也會經過Zookeeper向訂閱的消費者發送通知。算法
zookeeper採用了遞增的事務Id來標識,全部的proposal都在被提出的時候加上了zxid,zxid其實是一個64位的數字,高32位是epoch用來標識leader是否發生改變,若是有新的leader產生出來,epoch會自增,低32位用來遞增計數。當新產生proposal的時候,會依據數據庫的兩階段過程,首先會向其餘的server發出事務執行請求,若是超過半數的機器都能執行而且可以成功,那麼就會開始執行數據庫
當leader崩潰或者leader失去大多數的follower,這時zk進入恢復模式,apache
zk中znode類型有四種,持久化目錄節點 持久化順序編號目錄節點(有順序 可以在註冊機器等許多場景用到) 臨時目錄節點 臨時順序編號節點服務器
zk的通知機制網絡
client端會對某個znode創建一個watcher事件,當該znode發生變化時,這些client會收到zk的通知,而後client能夠根據znode變化來作出業務上的改變等。session
zk的配置管理框架
程序分佈式的部署在不一樣的機器上,將程序的配置信息放在zk的znode下,當有配置發生改變時,也就是znode發生變化時,能夠經過改變zk中某個目錄節點的內容,利用water通知給各個客戶端 從而更改配置。運維
zk的命名服務
命名服務是指經過指定的名字來獲取資源或者服務的地址,利用zk建立一個全局的路徑,這個路徑就能夠做爲一個名字,指向集羣中的集羣,提供的服務的地址,或者一個遠程的對象等等。
分佈式通知和協調
對於系統調度來講:操做人員發送通知實際是經過控制檯改變某個節點的狀態,而後zk將這些變化發送給註冊了這個節點的watcher的全部客戶端。
對於執行狀況彙報:每一個工做進程都在某個目錄下建立一個臨時節點。並攜帶工做的進度數據,這樣彙總的進程能夠監控目錄子節點的變化得到工做進度的實時的全局狀況。
在分佈式環境中,有些業務邏輯只須要集羣中的某一臺機器進行執行,其餘的機器能夠共享這個結果,這樣能夠大大減小重複計算,提升性能,因而就須要進行master選舉。
Leader服務器會和每個Follower/Observer服務器都創建TCP鏈接,同時爲每一個F/O都建立一個叫作LearnerHandler的實體。LearnerHandler主要負責Leader和F/O之間的網絡通信,包括數據同步,請求轉發和Proposal提議的投票等。Leader服務器保存了全部F/O的LearnerHandler。
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
Storm:按期掃描
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的數據量不太多,數據量不太大的狀況下,酌情考慮,仍是可使用的。
隨機,客戶端在初始化( 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點中的加大風險之處。
在ZooKeeper中,服務器和客戶端之間維持的是一個長鏈接,在 SESSION_TIMEOUT 時間內,服務器會肯定客戶端是否正常鏈接(客戶端會定時向服務器發送heart_beat),服務器重置下次SESSION_TIMEOUT時間。所以,在正常狀況下,Session一直有效,而且zk集羣全部機器上都保存這個Session信息。在出現問題狀況下,客戶端與服務器之間鏈接斷了(客戶端所鏈接的那臺zk機器掛了,或是其它緣由的網絡閃斷),這個時候客戶端會主動在地址列表(初始化的時候傳入構造方法的那個參數connectString)中選擇新的地址進行鏈接。
好了,上面基本就是服務器與客戶端之間維持長鏈接的過程了。在這個過程當中,用戶可能會看到兩類異常CONNECTIONLOSS(鏈接斷開) 和SESSIONEXPIRED(Session 過時)。
CONNECTIONLOSS發生在上面紅色文字部分,應用在進行操做A時,發生了CONNECTIONLOSS,此時用戶不須要關心個人會話是否可用,應用所要作的就是等待客戶端幫咱們自動鏈接上新的zk機器,一旦成功鏈接上新的zk機器後,確認剛剛的操做A是否執行成功了。
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().
不支持用持久Watcher的緣由很簡單,ZK沒法保證性能。
使用watch須要注意的幾點
① Watches通知是一次性的,必須重複註冊.
② 發生CONNECTIONLOSS以後,只要在session_timeout以內再次鏈接上(即不發生SESSIONEXPIRED),那麼這個鏈接註冊的watches依然在。
③ 節點數據的版本變化會觸發NodeDataChanged,注意,這裏特地說明了是版本變化。存在這樣的狀況,只要成功執行了setData()方法,不管內容是否和以前一致,都會觸發NodeDataChanged。
④ 對某個節點註冊了watch,可是節點被刪除了,那麼註冊在這個節點上的watches都會被移除。
⑤ 同一個zk客戶端對某一個節點註冊相同的watch,只會收到一次通知。
⑥ Watcher對象只會保存在客戶端,不會傳遞到服務端。
若是節點數據的更新頻率很高的話,不能。
緣由在於:當一次數據修改,通知客戶端,客戶端再次註冊watch,在這個過程當中,可能數據已經發生了許屢次數據修改,所以,千萬不要作這樣的測試:」數據被修改了n次,必定會收到n次通知」來測試server是否正常工做。(我曾經就作過這樣的傻事,發現Server一直工做不正常?其實不是)。即便你使用了GitHub上這個客戶端也同樣。
不能。
ZK自己不提供這樣的功能,它僅僅提供了對單個IP的鏈接數的限制。你能夠經過修改iptables來實現對單個ip的限制,固然,你也能夠經過這樣的方式來解決。https://issues.apache.org/jira/browse/ZOOKEEPER-1320
不能
鏈接斷了以後,ZK不會立刻移除臨時數據,只有當SESSIONEXPIRED以後,纔會把這個會話創建的臨時數據移除。所以,用戶須要謹慎設置Session_TimeOut