背景
最近在看到Pachyderm的介紹時,看到作者拿YARN和Kubernetes做類比,拿Zookeeper和etcd做對比。YARN和Kubernetes的類比還相對比較好理解,畢竟他們都有資源管理和調度的職能,只不過YARN上運行的對象是JVM,而Kubernetes上運行的是容器。但是拿Zookeeper和etcd來類比我就有些不懂了,在我之前的概念里zookeeper並不是一個存儲組件啊,因此有了本文的過程。
ZK和etcd可以做類比嗎?
etcd的官網介紹是一個分布式的K/V存儲,而Zookeeper的官網介紹是一個高度可用的分布式協調者。看起來他們做的事情完全不同啊,那我們來比較一下功能介紹。
-
watcher指的是訂閱/通知,當一個值改變時,通知訂閱過的節點,在etcd中是K/V值對的改變,在Zookeeper中是znode的改變(值改變、節點刪除等)
-
raft和zab都是paxos算法的變形,都是為了解決分布式系統中的讀寫一致性問題
-
選舉都是通過相應的一致性算法實現的
功能總結的不到位,歡迎補充
從功能上看,他們干的事好像也都差不多,分布式的一致性、選舉算法、分布式鎖,那么,我們來看一下各自的典型應用吧。
分別參考了ZooKeeper應用場景匯總和ETCD的應用場景
zk可以作為分布式存儲嗎?
在應用場景上,etcd和Zookeeper也很一致,難道Zookeeper本質上是分布式存儲組件,為此,我查了下 Zookeeper是否可以作為分布式存儲系統?
在知乎上的答案為:zookeeper只存元數據(https://www.zhihu.com/question/22116083)
總結幾點原因如下:
-
znode只能存1M以內的數據
-
寫入性能低,為保證一致性,每次需要n/2+1的寫入完成才算完成
-
zookeeper的數據是全部存儲在內存,只適合存元數據
-
Zookeeper的使用場景是有高一致性的
所以,邏輯上來說,可以。因為Zookeeper本質上是一個內存式的文件系統,它的znode就相當於dictionary和file的結合體,但是由於性能和存儲容量以及使用場景來看,Zookeeper適合存有強一致性要求的配置信息,也就是元數據。
到這一步,基本搞清楚了Zookeeper的應用場景了,如果etcd可以和Zookeeper作類比的話,難道etcd不是一個分布式存儲組件?
etcd究竟是干啥的?
回到etcd的官方文檔,在Reference下看到一個FAQ目錄,發現了etcd的名稱由來,原來它是”/etc”和”d” (distributed) 的結合體, 它存的也是大型分布式系統的配置信息,也就是“distributed etc directory.”
到此可知,Zookeeper和etcd解決的問題是一樣的,都解決分布式系統的協調和元數據的存儲,所以它們都不是一個存儲組件,或者說都不是一個分布式數據庫。etcd靈感來源於Zookeeper,但在實現的時候有了很多的改進。
-
更輕量級、更易用
-
高負載下的穩定讀寫
-
數據模型的多版本並發控制
-
穩定的watcher功能,通知訂閱者監聽值的變化
-
客戶端協議使用gRPC協議,支持go、C++、Java等,而Zookeeper的RPC協議是自定制的,目前只支持C和Java
-
可以容忍腦裂現象的發生
腦裂現象指的是,在一個分布式集群中,只允許一個leader協調工作,由於網絡或其他原因,導致一個集群分成了兩個集群,產生了兩個leader同時工作,此時集群不再具備讀寫一致性。
etcd是使用raft算法解決的腦裂問題,raft算法具體參考 raft的動畫(http://thesecretlivesofdata.com/raft/)看這個就很好理解。
關於腦裂現象的一些推薦資料
Linuex-ha split-brain
Split-brain, Quorum, and Fencing - updated
總結
ZooKeeper
-
watch children只能watch子節點,不能遞歸watch孫節點
-
watch children只能watch子節點的創建和刪除,不能watch子節點值的變化
-
watch node只能對已經存在的node進行watch,對不存在的node需要watch existence
除了上述的這些不足以外,在其官網文檔中自己也提到,在watch被觸發和重新設置之間發生的事件將被丟棄,無法被捕捉。接下來讓我們看看Etcd的watch。
Etcd
Etcd支持單點watch,prefix watch以及ranged watch。
和ZooKeeper不同,Etcd不會根據事件的不同而要求調用不同的watch API,三類watch的區別僅在於
對key的處理不同:
-
單點watch僅對傳入的單個key進行watch;
-
ranged watch可以對傳入的key的范圍進行watch,范圍內的key的事件都會被捕捉;
-
而prefix則可以對所有具有給定prefix的key進行watch。
之前在使用etcd的時候,只是在官網看到了分布式存儲,就默認它為一個存儲組件,導致了對etcd的誤解,這也是第一次用到的時候沒有深入了解導致的,在經過和Zookeeper的比較學習之后,發現兩者在很多方面有着相同的特性。以前我對Zookeeper也有一定的誤解,以為它是一個協調者,一定有管理的功能,可以控制很多東西,但經過這番學習之后,發現其實Zookeeper本質上也是一個存儲單元,用於存放配置信息,解決分布式中的讀寫一致性問題。總的來說,etcd和Zookeeper有相似的功能,做的事情也大同小異,只是可能具體的應用場景不太一樣,我目前的了解是Zookeeper主要用於Hadoop組件的協調上,etcd主要用於Kubernetes上對於容器的協調上,兩者都是用於存放配置信息等元數據的,隨着以后的深入學習,希望可以慢慢把他們的區別理清晰。
不得不承認,作為后起之秀,Etcd在watch方面完勝ZooKeeper。
從功能的角度來看,Etcd只需要調用一次watch操作就可以捕捉所有的事件,相比ZooKeeper大大簡化了客戶端開發者的工作量。
ZooKeeper的watch獲得的channel只能使用一次,而Etcd的watch獲得的channel可以被復用,新的事件通知會被不斷推送進來,而無需客戶端重復進行watch,這種行為也更符合我們對go channel的預期。
ZooKeeper對事件丟失的問題沒有解決辦法(如果新版本可以解決記得留言告訴我)。Etcd則提供了版本號幫助客戶端盡量捕捉每一次變化。要注意的是每一次變化都會產生一個新的版本號,而這些版本不會被永久保留。Etcd會根據其版本留存策略定時將超出閾值的舊版本從版本歷史中清除。
從開發者的角度來看,ZooKeeper是用Java寫的,且使用了自己的TCP協議。對於程序員來說不太友好,如果離開了ZooKeeper提供的SDK自己寫客戶端會有一定的技術壁壘,而ZooKeeper官方只提供了Java和C語言的SDK,其它語言的開發者就只能去尋求第三方庫的幫助,比如github.com/samuel/go-zookeeper/zk。
另一方面,Etcd是用Go寫的,使用了Google的gRPC協議,官方除了提供Go語言的SDK之外,也提供了Java的SDK:https://github.com/etcd-io/jetcd。
另外Etcd官方還維護了一個zetcd項目:https://github.com/etcd-io/zetcd,它在Etcd外面套了一個ZooKeeper的殼。讓那些ZooKeeper的客戶端可以無縫移植到Etcd上。有興趣的小伙伴可以嘗試一下。
為什么用etcd而不用Zookeeper?
閱讀了“ZooKeeper應用場景匯總(超詳細)”一文的讀者可能會發現,etcd實現的這些功能,Zookeeper都能實現。那么為什么要用etcd而非直接使用Zookeeper呢?
相較之下,Zookeeper有如下缺點:
-
復雜。Zookeeper的部署維護復雜,管理員需要掌握一系列的知識和技能;而Paxos強一致性算法也是素來以復雜難懂而聞名於世;另外,Zookeeper的使用也比較復雜,需要安裝客戶端,官方只提供了java和C兩種語言的接口。
-
Java編寫。這里不是對Java有偏見,而是Java本身就偏向於重型應用,它會引入大量的依賴。而運維人員則普遍希望機器集群盡可能簡單,維護起來也不易出錯。
-
發展緩慢。Apache基金會項目特有的“Apache Way”在開源界飽受爭議,其中一大原因就是由於基金會龐大的結構以及松散的管理導致項目發展緩慢。
而etcd作為一個后起之秀,其優點也很明顯。
-
簡單。使用Go語言編寫部署簡單;使用HTTP作為接口使用簡單;使用Raft算法保證強一致性讓用戶易於理解。
-
數據持久化。etcd默認數據一更新就進行持久化。
-
安全。etcd支持SSL客戶端安全認證。
最后,etcd作為一個年輕的項目,正在高速迭代和開發中,這既是一個優點,也是一個缺點。優點在於它的未來具有無限的可能性,缺點是版本的迭代導致其使用的可靠性無法保證,無法得到大項目長時間使用的檢驗。然而,目前CoreOS、Kubernetes和Cloudfoundry等知名項目均在生產環境中使用了etcd,所以總的來說,etcd值得你去嘗試。
轉自https://blog.csdn.net/zzhongcy/article/details/89401204
