分布式專題(3)- Zookeeper

什么是Zookeeper?

總結(jié)一句話,就是:

ZooKeeper是一種分布式協(xié)調(diào)服務(wù),可以實現(xiàn)分布式應(yīng)用配置管理、統(tǒng)一命名服務(wù)、狀態(tài)同步服務(wù)、集群管理、分布式鎖和分布式隊列等功能。

從這句話我們可以知道 Zookeeper 的基本定位是作為一個分布式服務(wù)協(xié)調(diào)框架,能夠提供配置管理、統(tǒng)一命名服務(wù)、轉(zhuǎn)態(tài)同步服務(wù)、管理集群、分布式鎖和分布式隊列等功能。

為什么選擇Zookeeper?

在講《分布式專題(2)- 分布式 Java通信》時我們說過,所謂分布式,無非就是“將一個系統(tǒng)拆分成多個子系統(tǒng)并散布到不同設(shè)備”的過程而已。在微服務(wù)的大潮之中, 我們把系統(tǒng)拆分成了多個服務(wù),根據(jù)需要部署在多個機器上,這些服務(wù)非常靈活,單個或幾個系統(tǒng)的故障不會使整個系統(tǒng)出現(xiàn)故障。并且可以隨著訪問量彈性擴展,能夠持續(xù)不間斷地提供服務(wù)。

雖然分布式應(yīng)用給我們帶來了諸多好處,但拆分系統(tǒng)的同時也帶來了巨大的復(fù)雜性,我們要寫一個分布式應(yīng)用還是非常困難的,如需要處理分布式session、分布式跨域、分布式任務(wù)調(diào)度、分布式事務(wù)、分布式鎖、分布式局部故障等問題。如局部故障問題,一個消息通過網(wǎng)絡(luò)在兩個節(jié)點之間傳遞時,網(wǎng)絡(luò)如果發(fā)生故障,發(fā)送方并不知道接收方是否接收到了這個消息。他可能在網(wǎng)絡(luò)故障前就收到了此消息,也可能沒有收到,又或者可能接收方的進程死了。發(fā)送方了解情況的唯一方法就是再次連接接收方,并向他進行詢問。這就是局部故障:根本不知道操作是否失敗。因此,大部分分布式應(yīng)用需要一個主控、協(xié)調(diào)控制器來管理物理分布的子進程。目前,大部分應(yīng)用需要開發(fā)私有的協(xié)調(diào)程序,缺乏一個通用的機制。協(xié)調(diào)程序的反復(fù)編寫浪費,且難以形成通用、伸縮性好的協(xié)調(diào)器。協(xié)調(diào)服務(wù)非常容易出錯,并很難從故障中恢復(fù)。例如:協(xié)調(diào)服務(wù)很容易處于競態(tài)甚至死鎖。Zookeeper的設(shè)計目的,是為了減輕分布式應(yīng)用程序所承擔的協(xié)調(diào)任務(wù)。

Zookeeper并不能阻止局部故障的發(fā)生,因為它們的本質(zhì)是分布式系統(tǒng)。他當然也不會隱藏局部故障。ZooKeeper的目的就是提供一些工具集,用來建立安全處理局部故障的分布式應(yīng)用。

ZooKeeper是一個分布式小文件系統(tǒng),并且被設(shè)計為高可用性(數(shù)據(jù)保持在內(nèi)存中)。通過選舉算法和集群復(fù)制可以避免單點故障,由于是文件系統(tǒng),所以即使所有的ZooKeeper節(jié)點全部掛掉,數(shù)據(jù)也不會丟失,重啟服務(wù)器之后,數(shù)據(jù)即可恢復(fù)。另外ZooKeeper的節(jié)點更新是原子的,也就是說更新不是成功就是失敗。通過版本號,ZooKeeper實現(xiàn)了更新的樂觀鎖,當版本號不相符時,則表示待更新的節(jié)點已經(jīng)被其他客戶端提前更新了,而當前的整個更新操作將全部失敗。當然所有的一切ZooKeeper已經(jīng)為開發(fā)者提供了保障,我們需要做的只是調(diào)用API。與此同時,隨著分布式應(yīng)用的的不斷深入,需要對集群管理逐步透明化監(jiān)控集群和作業(yè)狀態(tài),可以充分利ZK的獨有特性。

總結(jié)上面的幾段話,得出選擇使用Zookeeper的原因就是:

大部分分布式應(yīng)用需要一個主控、協(xié)調(diào)控制器來管理物理分布的子進程;

大部分分布式應(yīng)用需要開發(fā)私有的協(xié)調(diào)程序,缺乏一個通用的機制;

協(xié)調(diào)程序的反復(fù)編寫浪費,且難以形成通用、伸縮性好的協(xié)調(diào)器;

ZooKeeper提供了通用且高可用的分布式服務(wù),用以協(xié)調(diào)分布式應(yīng)用

下面,我們先把Zookeeper下載回來安裝,結(jié)合實例,一起來認識和理解“ZooKeeper是一種分布式協(xié)調(diào)服務(wù),可以實現(xiàn)分布式應(yīng)用配置管理、統(tǒng)一命名服務(wù)、狀態(tài)同步服務(wù)、集群管理、分布式鎖和分布式隊列等功能”的含義。

Zookeeper數(shù)據(jù)模型

ZooKeeper是一種分布式協(xié)調(diào)服務(wù),可以實現(xiàn)分布式應(yīng)用配置管理、統(tǒng)一命名服務(wù)、狀態(tài)同步服務(wù)、集群管理、分布式鎖和分布式隊列等功能。具體是通過它獨特的數(shù)據(jù)結(jié)構(gòu)來實現(xiàn)的,我們可以認為 Zookeeper = 文件系統(tǒng)+監(jiān)聽通知機制。下面我們看一下它的數(shù)據(jù)結(jié)構(gòu):

文件系統(tǒng)

在Zookeeper的數(shù)據(jù)結(jié)構(gòu)中,每個子目錄項如 NameService 都被稱作為 znode(目錄節(jié)點),和文件系統(tǒng)一樣,我們能夠自由的增加、刪除znode,在一個znode下增加、刪除子znode,唯一的不同在于znode是可以存儲數(shù)據(jù)的。

有持久、持久有序、臨時、臨時有序四種類型的znode:

PERSISTENT(持久節(jié)點):客戶端與zookeeper斷開連接后,該節(jié)點依舊存在

PERSISTENT_SEQUENTIAL(持久有序節(jié)點):客戶端與zookeeper斷開連接后,該節(jié)點依舊存在,只是Zookeeper給該節(jié)點名稱進行順序編號

EPHEMERAL(臨時節(jié)點):客戶端與zookeeper斷開連接后,該節(jié)點被刪除

EPHEMERAL_SEQUENTIAL(臨時有序節(jié)點):客戶端與zookeeper斷開連接后,該節(jié)點被刪除,只是Zookeeper給該節(jié)點名稱進行順序編號

通知機制

zookeeper客戶端注冊監(jiān)聽它關(guān)心的目錄節(jié)點,當目錄節(jié)點發(fā)生變化(數(shù)據(jù)改變、被刪除、子目錄節(jié)點增加刪除)時,zookeeper會通知客戶端。

我們說 Zookeeper = 文件系統(tǒng)+監(jiān)聽通知機制,好像看起來挺簡單的啊(E=mc2看起來也挺簡單的),它怎么就能通過這么簡單兩點東西,實現(xiàn)分布式應(yīng)用配置管理、統(tǒng)一命名服務(wù)、狀態(tài)同步服務(wù)、集群管理等功能呢?我們看一個它實現(xiàn)配置管理功能的例子,就大概知道它是怎么實現(xiàn)其它功能了。

配置管理

假設(shè)我們的程序是分布式部署在多臺機器上,如果我們要改變程序的配置文件,需要逐臺機器去修改,非常麻煩,現(xiàn)在把這些配置全部放到zookeeper上去,保存在 zookeeper 的某個目錄節(jié)點中,然后所有相關(guān)應(yīng)用程序?qū)@個目錄節(jié)點進行監(jiān)聽,一旦配置信息發(fā)生變化,每個應(yīng)用程序就會收到 zookeeper 的通知,然后從 zookeeper 獲取新的配置信息應(yīng)用到系統(tǒng)中。

是不是通過配置管理這個例子,對Zookeeper的了解就更清晰了?還有另外一個經(jīng)典用法,如下

如上圖所示,系統(tǒng)A發(fā)送一個請求到MQ,然后系統(tǒng)B消費消息之后處理了。那系統(tǒng)A如何知道系統(tǒng)B的處理結(jié)果?

用ZK就可實現(xiàn)分布式系統(tǒng)之間的協(xié)調(diào)工作!

系統(tǒng)A發(fā)送請求之后可以在ZK上對某個節(jié)點的值注冊監(jiān)聽器,一旦系統(tǒng)B處理完了就修改ZK那個節(jié)點的值,A立馬就可以收到通知。

通過上面這兩個例子,我們對 “Zookeeper = 文件系統(tǒng)+監(jiān)聽通知機制,ZooKeeper是一種分布式協(xié)調(diào)服務(wù),可以實現(xiàn)分布式應(yīng)用配置管理、統(tǒng)一命名服務(wù)、狀態(tài)同步服務(wù)、集群管理、分布式鎖和分布式隊列等功能”可以有更形象地理解。

下面我們就看看Zookeeper一些基本命令,如節(jié)點的增刪改查等,然后通過Zookeeper提供的API,一起用Java代碼實現(xiàn)配置管理、統(tǒng)一命名服務(wù)、狀態(tài)同步服務(wù)、集群管理、分布式鎖和分布式隊列等功能。

Zookeeper基本命令

Zookeeper是用來解決分布式應(yīng)用中經(jīng)常遇到的數(shù)據(jù)管理問題,對于數(shù)據(jù),那基礎(chǔ)的無非都是增刪改查。下面我們啟動zookeeper服務(wù)端,然后啟動zookeeper客戶端,一起敲一下它增刪改查的命令。

zookeeper基本的五個命令為 ls 、 create 、 delete 、 set 、get 。輸入-h可以查看所有命令,相關(guān)命令示例可參考這里。

下面開始使用

1、使用 ls 命令來查看當前 ZooKeeper 中所包含的內(nèi)容(默認只有zookeeper一個節(jié)點)

2、創(chuàng)建一個新的 znode ,使用 create /zkPro myData

3、再次使用 ls 命令來查看現(xiàn)在 zookeeper 中所包含的內(nèi)容:

4、下面我們運行 get 命令來確認第二步中所創(chuàng)建的 znode 是否包含我們所創(chuàng)建的字符串:

5、下面我們通過 set 命令來對 zk 所關(guān)聯(lián)的字符串進行設(shè)置:

6、下面我們將剛才創(chuàng)建的 znode 刪除

可以看到,客戶端中對節(jié)點進行增刪改查的命令還是非常簡單的。

Zookeeper集群

以上的講解中都是基于單機模式,這種模式下,如果當前主機宕機,那么所有依賴于當前zookeeper服務(wù)工作的其他服務(wù)器都不能在進行正常工作,這種事件稱為單節(jié)點故障。所以這種模式一般用在測試環(huán)境。為了防止這種情況出現(xiàn),生產(chǎn)環(huán)境一般都是會在多臺機器上配置zookeeper來組成集群,以實現(xiàn)容錯和高可用。集群就涉及到數(shù)據(jù)一致性的問題,即集群中的的數(shù)據(jù)都應(yīng)該要保持同步。為此,zookeeper集群引入了Leader、Follower的概念。即對來自于Client的寫服務(wù)(Write Requst),都會被轉(zhuǎn)發(fā)到Leader節(jié)點來處理,Leader節(jié)點會對這次的更新發(fā)起投票,并且發(fā)送提議消息給集群中的其他節(jié)點,當半數(shù)以上的Follower節(jié)點將本次修改持久化成功之后,Leader 節(jié)點會認為這次寫請求處理成功了,提交本次的事務(wù)。而來自于Client的讀服務(wù)(Read Requst),是直接由對應(yīng)Server的本地副本來進行服務(wù)的。具體可以參考Zookeeper一致性原理(ZAB協(xié)議),另外此處補充幾個著名的分布式理論。

zookeeper搭建集群也很簡單,只需要簡單的幾步即可完成。

(在一臺機器上搭建多個zookeeper就是俗稱的偽集群了,資源有限,此處模擬搭建的是偽集群)

1.修改zoo.cfg配置文件

在conf下將zoo_sample.cfg復(fù)制為zoo-1.cfg并修改內(nèi)容如下(其它配置不用動,只修改目錄和端口,并添加集群信息):

dataDir=/tmp/zookeeper-1

clientPort=2181

server.1=127.0.0.1:12181:13181

server.2=127.0.0.1:12182:13182

server.3=127.0.0.1:12183:13183

對比單機模式,配置zk集群時配置文件只需要添加一句:server.id=ip:port1:port2 即可,配置3條即指集群中有3個zk。

可以看到zookeeper的配置中有三個端口,其作用如下:

clientPort:表示與服務(wù)端與 clinet 端交換信息的端口號;

port1:表示follower節(jié)點與leader節(jié)點交換信息的端口號;

port2:表示leader節(jié)點掛掉了, 來重新選舉leader需要的端口號。

2.復(fù)制zoo-1.cfg配置文件

再從zoo-1.cfg復(fù)制兩個配置文件zoo-2.cfg和zoo-3.cfg,只需修改dataDir和clientPort不同即可,其它配置保存不變。

# zoo2.cfg中的目錄和clientPort:

dataDir=/tmp/zookeeper-2

clientPort=2182

# zoo3.cfg中的目錄和clientPort:

dataDir=/tmp/zookeeper-3

clientPort=218

3.創(chuàng)建dataDir目錄和標識server.id

每個人都有自己的身份證,每臺電腦都有自己的Mac地址,每個zookeeper也有自己唯一標識,就是 server.id 中的id,這個值需要記錄在 dataDir 的 myid 文件中。所以我們要為集群中的zookeeper創(chuàng)建這個myid文件,內(nèi)容就是我們zoo.cfg中配置的id。

# 創(chuàng)建zoo-1.cfg對應(yīng)的目錄及server.id

mkdir /tmp/zookeeper-1

vim /tmp/zookeeper-1/myid

1

# 創(chuàng)建zoo-2.cfg對應(yīng)的目錄及server.id

mkdir /tmp/zookeeper-2

vim /tmp/zookeeper-2/myid

2

# 創(chuàng)建zoo-3.cfg對應(yīng)的目錄及server.id

mkdir /tmp/zookeeper-3

vim /tmp/zookeeper-3/myid

3

4.啟動集群實例

bin/zkServer.sh start conf/zoo-1.cfg

bin/zkServer.sh start conf/zoo-2.cfg

bin/zkServer.sh start conf/zoo-3.cfg

5.檢測集群狀態(tài)

bin/zkServer.sh status conf/zoo-1.cfg

bin/zkServer.sh status conf/zoo-2.cfg

bin/zkServer.sh status conf/zoo-3.cfg

可以看到,有一臺leader、兩臺作為follower,集群啟動成功。選舉過程可以參看這里。

可以通過多個客戶端連接集群中不同的機器,并修改其中一臺機器上的數(shù)據(jù),觀察數(shù)據(jù)是否會同步更新到其它機器上

可以通過安裝zookeeper圖形化界面來更方便地觀察zk的節(jié)點信息和對zk節(jié)點進行增刪改查

終于把zookeeper的基本使用和集群講完了。接下來,我們就一起再次理解“ZooKeeper是一種分布式協(xié)調(diào)服務(wù),可以實現(xiàn)分布式應(yīng)用配置管理、統(tǒng)一命名服務(wù)、狀態(tài)同步服務(wù)、集群管理、分布式鎖和分布式隊列等功能”這句話。

最新免費java,架構(gòu),大數(shù)據(jù)AI編程資料獲取添加

薇信:18410263200

通過驗證填寫“111”(備注必填)

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容