1. 程式人生 > >ZK那些事

ZK那些事

汪汪汪汪汪汪汪汪汪汪汪汪汪汪汪汪汪汪汪汪汪汪汪汪汪汪汪汪汪汪。
沒儲存啊,都是淚啊。

前言

心好累啊,又要寫一遍。

從去年初次接觸Zookeeper到現在,正好一年了,一直沒總結,一方面也是因為自己對分散式系統理解很少,沒有什麼可說的,如果只是描述一下zk提供的幾個原語實在沒什麼意義。(另一方面就是懶)。

感覺自己終於對分散式可以說是有一定的入門了,所以趕緊記錄下自己的成長。

正文

我接觸zk相對來說是挺緣分的,因為C++出身,對於Hadoop家族瞭解甚少,只是在專案中對於模糊的“分散式協同”而找到了zk。就像一場倉促的戀愛,摸不準對方的脾氣, 鬧出了很多尷尬(夠了)。

明天繼續。。。

什麼是zk

zk是hadoop全家桶的一員,後來獨立為apache的頂級專案,是google的chubby的開源實現。

很高大對吧。。。但是說了好像沒說。。。

通俗的理解,在一個分散式系統的開發中,我們會面對很多共同的問題,比如leader選舉/分散式鎖,叢集管理等等等等,就像後臺開發,都會需要序列化/翻序列化,日誌等功能,如果所有事情都自己去實現,那麼不僅低效,而且可能會遇到很多坑。

zk就是一個解決分散式協同的輪子,讓開發者能專注於業務邏輯的實現,同時避免了很多坑。

作為一個廣泛使用的輪子,不光要能正確高效的使用,同時還可以通過它學習到很多知識。

zk能做什麼

zk主要是用來進行分散式協同。在Hadoop專案中,有很多動物名字命名的專案,想要管理好這麼多動物(程序),自然需要一個動物園管理者(zookeeper)。

這裡的協同包括提供分散式鎖, 崩潰檢測, 元資料儲存,服務發現等功能。

如果只單純來看zk的API,可能會不知所云,像目錄樹一樣的znode?建立節點?刪除節點??而上述的功能沒啥關係啊。。。

對client來說, chubby直接上菜,提供加鎖,釋放鎖等api,而zk相當於提供了菜的原材料(create node, delete node等),由client自己組合為各種想要的功能,當然,對於一個會做菜的人來說,後者更加open,想吃啥自己做就行了。

但是對於分散式初學者/不會做菜的人來說,面對一堆原材料就很尷尬了。

當然,和現實,初學者需要一份菜譜來嘗試做菜了,隨便胡亂做菜。。。。小心煉出丹來。(為什麼寫這段時總想到桂綸鎂 “要不要和我學做菜啊~” )

啥叫菜譜

官方給出了一系列功能的實現方法,稱為菜譜(recipes)[1]
推薦學習菜譜來感受做菜。。。啊不,zk。。。

當然,這裡我們也舉一個實際的例子來講解菜譜。

菜譜之Leader選舉

最簡單的方法就是使用 SEQUENCE|EPHEMERAL(有序|短暫) 的znode來代表參與選舉的client的proposals(這個詞不翻譯,相信我,只要你學分散式,這個詞絕對會出現N次的)。具體步驟如下

1.所有參與選舉的client在一個指定的目錄下建立屬性為SEQUENCE|EPHEMERAL的znode
2.seq最小的client即為leader,其他的client為follower,同時watch Leader的znode。
3.一旦Leader因某種原因掛了,其他的client會收到通知,開始新一輪的Leader選舉。

然而這種方法並不完美。Why?
讓我們明天繼續~

轉眼就是明天的明天的……好多個明天了..自己挖的坑還是要填上啊~

為什麼不完美呢,讓我們想一下上述操作的具體步驟是如何操作的.
對於每個客戶端,邏輯如下

// .........
// 主函式
my_node = zk.create("/leader/clientId-", "SEQUENCE|EPHEMERAL")
all_nodes = zk.getChildren("/leader")
if(judgeMinSeq(my_node, all_nodes) == true)
    doMaster();
else
    doSlave();
// .........

void doSlave() 
{
    // 設定watch點

    //slave正常邏輯
}
void watchpointCallback()
{
    all_nodes = zk.getChildren("/leader")
    if(judgeMinSeq(my_node, all_nodes) == true)
        doMaster();
    else
        doSlave();
}

當Leader掛掉時,所有的slave都會收到通知,呼叫callback檢查自己的znode的seq是否為最小可以當選為下一個Leader.
這就導致了 herd effect(牧群效應,個人感覺很類似於epoll的thundering herd).所有的slave都呼叫getChildren,當slave數量很多時,大大影響了整個叢集的效率.而且這樣並沒有什麼意義,畢竟順序已經固定了.除了真正的下一任Leader外,其他的呼叫都是無用的.
zk的這種Leader選舉方式,其實是帶有隱含的繼承順序,換句話說並不是battle一輪決出C位,更像是皇位繼承,要從太子…五阿哥….十三阿哥(你看,這也是帶上了Seq)…按照順序來選出繼承者.

那麼如何改進呢?

就像之前我們說的那樣,對於太子來說,他需要關心的是皇上是否掛了,只有皇上掛了他才能登基,而對於後面的阿哥來說,只要太子沒掛,即使皇上掛了,下一個皇位也輪不上自己,那麼只需要關注比自己更年長的那個阿哥….

好,我知道把你繞暈了,對於每個slave來說,在第一次Leader選舉getChildren時,只要關注剛好小於自己seq的znode就行了.
比如5節點
[0,1,2,3,4]
那麼第一次選舉之後
0為Leader
0<-1 1watch0,0掛了1就是leader
1<-2 同上
…剩下繼續同上

當然,一旦觸發事件(watch的znode掛了),並不是想當然的認為自己是Leader,仍要呼叫一次getChildren確認現有Leader是否存活(或者說確認自己的seq為最小)

可以看出zk的菜譜博大精深,我們這裡拿出Leader選舉作為最簡單的例子來講解,就有很多可以說的.在設計自己的應用時還是要多多用心,比如用zk實現一個分散式互斥鎖也和Leader選舉很像啊,你能將Leader選舉這個菜譜改一改,改成你需要的鎖嗎?

和etcd的區別

註冊中心??

參考
http://jm.taobao.org/2018/06/13/%E5%81%9A%E6%9C%8D%E5%8A%A1%E5%8F%91%E7%8E%B0%EF%BC%9F/
https://yq.aliyun.com/articles/227260
http://www.infoq.com/cn/articles/background-architecture-and-solutions-of-service-discovery
http://zhangtielei.com/posts/blog-redlock-reasoning.html

我要是明天沒寫完我就是狗