初識分佈式協調器html
分佈式協調器的「協調」二字讓人摸不到頭腦,怎麼就協調了,用的着協調嗎?實際上這個東西在以前就是爲了提供分佈式鎖服務而設計的,偉大的google公司發明了chubby,雅虎隨後也推出了chubby的開源實現zookeeper。因爲其高可用高容錯的特性逐漸的衍生出了很是豐富的功能。目前來講最重要的三個功能是分佈式鎖、選主節點、命名服務。git
好比選主時,爲了讓集羣的全部節點達成一致,必需要經過選舉算法來實現,可能有人會問,我直接配置好不就好了,已啓動你們都知道誰是主節點。可是master掛了咋辦?那你的HA就不能保證了,這叫single point of failure(單點故障)。那有人可能又說了,輪流來當master不就好了?可是動態增長刪除節點你的集羣怎麼作到Scalable(可伸縮)。總之別問了,人擇原理,存在便是合理的,因此請聽我細細道來…github
關於cocklebur的開發目的算法
我閒暇時間開發了一個叫作cocklebur的東西,已經開源到github。其實當初在看了一些關於paxos的文章以後以爲很困惑,因而就去看zookeeper的源碼,以及一些源碼剖析的文章,但依然以爲不得要領。因此就打算本身去搞一下,由於在開發過程當中,你可以正面的遇到問題,而後去解決問題,而不是旁觀別人提出問題,而後直接去看答案。緩存
開發cocklebur,徹底是爲了學習,而並無指望把它打形成向zookeeper那樣的項目,本人水平有限,接觸分佈式領域也不過1年半,因此有寫的不對很差的地方,還望各路高手指點一二。服務器
Cocklebur概述數據結構
首先cocklebur能夠部署成爲一個集羣,每一個節點都維護着全部節點的地址信息;Cocklebur集羣剛剛啓動時,每一個節點都會提議本身是master(由於它們不知道彼此的狀況),通過一個選舉過程,最終達成一致。選出master以後,整個集羣就開始同步數據,每一個節點都保存了一份相似Unix文件系統的數據結構,裏面存放着目錄、文件。同步的目的就是保證集羣每一個節點都持有最新且一致的數據,以後集羣就能夠對外服務了。外界的客戶端能夠向集羣提交一些對文件系統修改的一些操做(建立目錄,刪除目錄,上傳文件等等),而要求就是節點的每個節點的數據在任什麼時候候都要保證最終一致(能夠不立刻一致,但邏輯上最終數據都會一致,因此client的操做順序確定須要保證)。服務的方式不光是可讀寫,並且還提供了訂閱機制,也就是說,client告訴集羣(其實是註冊到某個節點,通常是Follower)我關注了那個文件(或目錄),它只要發生了變化,集羣(接受註冊的那個Follower)就能立馬(其實有必定的時間窗口)通知client發生了什麼樣的變化。因此從這方面看他更像信號量的機制,因此稱之爲分佈式「鎖」。koa
也就是說最終每一個節點都會維護了一份最新並且一致的數據,不管集羣發生宕機(總體宕機也算)仍是個別機器壞掉,只要client向集羣的任意一個節點提交了修改(create,delete,upload file)請求,那麼必定不會保證數據丟失,固然你整個機房都被炸掉了那就沒辦法了...補充一句,可能已經向集羣訂閱的client接受通知與某client提交修改有必定的時間窗口,延遲嘛,你懂的。異步
一些可能存在的疑問分佈式
選舉都考慮那些因素?Leader是否是永遠都是擁有最新數據的那個?
要考慮的就是每一個節點保存數據的版本,原則上最新的要當選Leader。可是出於容錯和性能考慮,能夠沒必要是最新的,只是在某個多數派中是最新就能夠了(這尼瑪也太隨便了吧,隨便一個多數派就行麼?聽我把話說完~)。說到這,有人就搞不懂了,數據不是最新就能當選Leader?沒錯!由於你啓動集羣后不能保證擁有最新數據的節點啓動成功了;那若是成功了呢?那也沒這個必要!若是它啓動的慢了影響你們的進度怎麼辦,並且若是在集羣服務以前,擁有最新數據的節點只要被Leader發現,那麼Leader也會善解人意的從這個節點上同步最新數據,而後分發給每一個Follower。這就是爲何Zookeeper在提出當選Leader前要等待200ms。其實等多長時間要看你的需求,這沒有辦法太絕對。正若有些人爲了愛情能夠苦等一生,有些人牽牽手就像旅遊~麻痹的又不正經了,原諒我吧~
爲啥可以實現分佈式的觀察者模式?(那個訂閱機制是怎麼實現的)
其實這個是經過客戶端異步實現的。你們確定很熟悉本地的觀察者模式,觀察者向發佈者註冊後,發佈者只要更新了觀察者所關注的信息就會直接調用觀察者的引用,從而產生一個觀察者方法的回調。其實分佈式的觀察者模式實現的關鍵在客戶端(觀察者)這裏。傳統的方式就是輪詢,服務端的數據變化了,就能夠作其餘事情了。可是如今須要自動的通知,所謂通知就是回調client端的一個函數去處理返回的結果便可。你們能夠參考我寫的這篇文章:利用thrift實現一個非阻塞帶有回調機制的客戶端。
爲什麼不管怎麼宕機,出故障都能保證數據最終一致切完整?
其實這並非絕對的,只能儘量的把丟失數據的機率減小到最少,而且儘量的讓集羣對外服務。
理論上來說,只要有一個節點有最新數據,而且已經持久化到磁盤,磁盤還沒壞,那麼就必定能讓整個集羣恢復到最新的狀態,只是時間長短的問題。因此本着這樣的思路,咱們就採用了Paxos的理念。另外,只要集羣總數存活的節點數量超過一半,就能構成一個多數派,因此集羣就可以對外提供服務。
文件系統數據內存和磁盤是如何交換的?
這個問題比較實在。其實現機制很簡單,按期的把內存數據序列化到磁盤上造成快照,並且每執行一個操做以前就先寫日誌。這樣咱們就能以快照做爲時間節點並利用日誌去恢復數據了。有人可能會說「尼瑪,這麼粗暴!直接把文件系統所有序列化到磁盤了?」。是的!由於所謂「文件系統」並非你想象中的那種服務器上的文件系統,它只是利用文件系統這種數據結構去管理少許的數據,好比配置文件,命名空間(就是一些目錄結構),或者寫個ip在某個目錄下這種。定位不一樣,因此設計越簡單越好。
更有思惟縝密的同窗問道,若是Leader接受完收據,還沒同步到Follower卻掛了,那麼剩下的Follower組成新的集羣,後續一來新的操做,不就漏掉了以前的操做了嗎?
別忘了咱們有數據版本這一說,數據的操做版本號必須是連續的,若是不連續說明中間漏掉了操做,因此,這就須要客戶端能夠緩存操做以便重試。若是有人問,若是客戶端也掛了呢?緩存的操做不就沒了嗎?答客戶端沒接到成功它本身知道,只要從新讀取任務就好了,因此多慮啦!另外補充一句,發生任何災難性的狀況都有可能,只不過是機率問題。咱們能作的就是盡最大可能把能避免的問題避免,正如前面所說的,全部節點都壞了,那確定完了。你咋不說世界末日呢,別說機房數據了,本身本本上備份的種子也沒了呢!