Zookeeper簡單概念介紹
過去,每個應用都是一個CPU,一個主機上的單一系統。然而今天,隨著大數據和云計算時代的到來,任何相互獨立的程序都可以運行在多個計算機上。然而面臨的問題是,協調這些集群的系統比在單一主機上要復雜的多,因此對于開發者來說,很難在集中精力來關注他們的系統邏輯上,大部分的時間都花費在了協調這些集群系統上。Zookeeper的出現就解決了這個問題,讓開發者能夠集中精力在系統邏輯上,而免于協調這些集群計算機的運行情況。Zookeeper暴漏了一套簡單的額API,能夠讓開發者實現公共需要協調的任務。例如配置維護、組服務、分布式消息隊列、分布式通知/協調等。Zookeeper有兩套實現的分別是C和java。另外集群的zookeeper具有容錯性和增加集群系統的吞吐量。
當用zookeeper來設計一套應用的時候,好的方式是獨立的管控和協調數據,例如對于那些web-mail的用戶來說,他們只關心的是郵件的內容,而不是每一臺服務器是如何來接受請求的,zookeeper來負責請求的管理。
Zookeeper的使命
可以把zookeeper來理解為一個螺絲刀,可以讓我們來上下螺絲,組裝家具等,而zookeeper正如螺絲刀一樣來協調分布式系統中的不同任務。一個協調的任務組可能牽涉到多個進程中,協調意味著任務之間需要做相同的事情,并且也需要保持多個進程之間的步調一致。例如在一個主從模式的結構中,slavee去master領取任務。Master負責分發工作。并且在主從模式中,我們常常希望只有一個master,但是其他的進程都會競相的爭取master的機會,我們可以認為選舉的master就相當于獲取到了一把鎖,只有他釋放了,其他人才有機會爭取。
Zookeeper目前的應用已經很廣泛,例如Apache HBase、Apache Kaflka、Apache Solr等,當我們的程序用zookeeper來協調管理的時候,開發者就可以通過zookeeper clientapi來操作zookeeper。ZooKeeper已經成為一種為分布式應用所設計的高可用、高性能且一致的開源協調服務。但是話說回來,zookeeper并不是萬能的,例如并不適合有大數據的存儲,對于數據的存儲有其他可供選擇的方法,例如數據庫或者分布式文件系統。
上面很抽象的討論了分布式系統,下面我們來通過一個例子來更深入的了解一下。
一般來說,在上述的結構圖中,master用來監控worker,最終把任務分配到worker上。而在zookeeper中,上圖是一個典型的案例,從這個結構中,我們就可以了解到zookeeper是如何來選舉master的、是如何來監聽空閑的worker和獲取應用的元數據。下面我們來分析一下。
為了實現上述的主從系統,我們需要考慮以下三個問題。
Master崩潰
如果master崩潰或者不能正常運轉的話,系統就不能再分配任務或者重新在從失敗的worker上分配任務。
Worker崩潰
如果worker崩潰的話,分配給worker的任務將不能被完成
信息傳遞失敗
如果master和worker之間信息傳遞失敗的話,worker將不能被分配到任務
上述是我們面臨的問題,針對以上三個問題,我們來解答一下。
Master崩潰
為了應對master崩潰的情況,我們需要一個備份的master。當主master崩潰掉的話,備份的master就可以取代主master。當然了,故障也不是那么輕易就能夠轉移的,新的master必須能夠從中回復先前master的狀態。當然了由于先前的master已經down掉了,狀態就不可能從先前的來獲得,這時候就需要從其他地方來獲得,這就是zookeeper內部機制了。
此外還有一個問題存在,試想如果master沒有down掉,但是備份的master懷疑他有問題,已經down掉的,例如主master負載過重,消息延遲嚴重的話,就會懷疑主master可能down掉了。此時如果取代的話,將會出現兩個master的情況。如果此時由于網絡原因的話,worker不能與主master正常傳遞消息的話,那么work直接就會結束掉。
Worker失敗的情況
Client提交任務到master上面,master合理的分配任務給worker來執行,當worker執行完后,提交執行狀態給master,最終master返回給client處理的結果信息。而如果worker崩潰的話,先前所有分發給他的任務,需要重新的分配。首先,master需要檢測崩潰的worker,并且能夠決定其他可運行的worker來執行它的任務。
消息傳遞失敗。
由于網絡原因,其中的worker失去了連接的話,master重新分配任務的話,可能導致兩個worker執行到了相同的任務。如果實際需求并沒有那么嚴密的話,我們就沒必要去驗證worker是否執行了任務。如果實際要求需要的話,那么必須考慮到多個worker重復執行task的情況。
執行一次并且至多執行一次
在任務上加鎖,并不能有效的避免一個任務重復執行的情況,例如下面的這個例子。
1. MasterM1分配任務T1給worker W1去執行
2. W1獲得了任務T1的鎖,執行了任務,然后把鎖給釋放了
3. MasterM1懷疑W1已經崩潰了,然后重新分配任務Task1給worker2去執行
4. W2獲得的任務T1的鎖,然后執行它,最后釋放了T1任務的鎖
上面例子中,任務T1上添加的鎖,并不能避免任務的重復執行情況,因為兩個Work之間執行任務時并行的,不是交替執行的。為了解決上面這種任務只能嚴格的執行一次的情況,應用之間必須依靠它自己本質的機制去實現上述操作。例如給應用數據上添加時間戳等,并且應用之間也必須擁有回滾的功能,以防出現信息不一致的情況。
另外一種嚴重的問題是,鎖的同步機制也會帶來影響。例如一個節點崩潰了,那么將會占用這鎖,導致其他worker執行不了此任務。為了避免這種情況,zookeeper需要實現一種機制來處理這樣的場景。首先,客戶端允許zookeeper中的數據狀態是臨時的;其次需要客戶端定期的通知zookeeper集群他們的狀態。如果客戶端未能及時的通知的話,那么屬于這個客戶端的所有臨時的狀態,將會被刪除。運用鎖和客戶端通知這兩種機制,我們可以防止客戶端獨立的停止應用程序和消息傳遞的失敗的情況發生。
試想一下,在系統中,我們不可能控制消息延遲的情況,不可能去判斷客戶端是否已經崩潰或者正在負載過重的執行任務,因此,當我們懷疑客戶已經崩潰,我們需要通過假設它可能只是慢反應,而且它在未來可能會執行一些其他操作。
根據上面的描述,我們總結一下主從結構
Master選舉
必須能夠有一個master去分配task給worker
Crash檢測
Master必須能夠檢測worker的狀態,以防worker崩潰或者失去連接
組成員管理
Master必須能夠確定哪些worker能夠執行任務
元數據管理
Master和worker必須能夠存儲一些執行時的狀態信息。
為什么分布式系統是困難的。
在看了圖1.1所示的分布式環境之后,有人可能會感覺這不是很難。無非是將原來在同一臺機器上對進程調度的原語,通過網絡實現在分布式環境中。是的,表面上是可以這么說。但是問題就在網絡這,在分布式系統中,所有在同一臺機器上的假設都不存在:因為網絡是不可靠的。
比如,在同一臺機器上,你對一個服務的調用如果成功,那就是成功,如果調用失敗,比如拋出異常那就是調用失敗。但是在分布式環境中,由于網絡的不可靠,你對一個服務的調用失敗了并不表示一定是失敗的,可能是執行成功了,但是響應返回的時候失敗了。還有,A和B都去調用C服務,在時間上 A還先調用一些,B后調用,那么最后的結果是不是一定A的請求就先于B到達呢? 這些在同一臺機器上的種種假設,我們都要重新思考,我們還要思考這些問題給我們的設計和編碼帶來了哪些影響。還有,在分布式環境中為了提升可靠性,我們往往會部署多套服務,但是如何在多套服務中達到一致性,這在同一臺機器上多個進程之間的同步相對來說比較容易辦到,但在分布式環境中確實一個大難題。
所以分布式協調遠比在同一臺機器上對多個進程的調度要難得多,而且如果為每一個分布式應用都開發一個獨立的協調程序。一方面,協調程序的反復編寫浪費,且難以形成通用、伸縮性好的協調器。另一方面,協調程序開銷比較大,會影響系統原有的性能。所以,急需一種高可靠、高可用的通用協調機制來用以協調分布式應用。來自: http://blog.csdn.net/luckyzhoustar/article/details/50527944