zookeeper介紹
什么是zookeeper?
zookpeeper是一個高可用的分布式管理與協調框架,基于ZAB算法也就是原子消息廣播協議的實現。它能夠很好的保證分布式環境中數據的一致性。也正是基于這樣的特性,使得它成為了解決分布式一致性問題的利器。 它暴露了一些公共服務,比如配置維護、域名服務、分布式同步、組服務。我們可以使用zookeeper來實現比如集群管理、選舉、分布式鎖、分布式隊列等功能。
zookeeper在hadoop生態系統中的地位:
zookeeper的特性:
- 順序一致性,從一個客戶端發起的事務請求最終將會嚴格地按照其發起的順序被應用到zookeeper中去。
- 原子性,所有事務請求的處理結果在整個集群中所有機器上的應用情況是一致的。也就是說要么整個集群所有的機器都成功應用了某一事務。要么全部都沒有應用,一定不會出現部分機器應用了該事務,而另一部分沒有應用的情況。
- 單一視圖,無論客戶端連接的是哪一個zookeeper服務器。其看到的服務器端數據模型都是一致的。
- 可靠性,一旦服務器成功地應用了一個事務并完成了對客戶端的響應。那么該事務所引起的服務器端狀態將會被一直保留下來。除非有另外一個事務對其更改。
- 實時性,通常所說的實時性,就是指一旦事務被成功應用。那么客戶端就能立即從服務器上獲取變更后的新數據。zookeeper僅僅能保證在一段時間內客戶端最終一定能從服務器端讀取最新的數據狀態。
zookeeper設計目標
- 目標1:簡單的數據結構。zookeeper就是以簡單的樹形結構來進行相互協調的。
- 目標2:可以構建集群。一般 zookeeper集群通常由一組機器構成,一般3-5臺機器就可以組成一個 zookeeper集群了。只要集群中超過半數以上的機器能夠正常工作,那么整個集群就能夠正常對外提供服務。
- 目標3:順序訪問。對于來自每戶端的每一個請求,zookeeper都會分配一個全局唯一的遞增編號,這個編號反應了所有事務操作的先后順序。應用程序可以使用 zookeeper的這個特性來實現更高層次的同步。
- 目標4:高性能。由于 zookeeper將全量數據存儲在內存中,并直接服務于所有的非事務請求,因此尤其是在讀操作為主的場景下性能非常突出。在JMater壓力測試下(100%讀請求場景下),其結果大約在12~13W的QPS。
ZooKeeper的體系結構
ZooKeeper 所有組件:
領導者(leader),負責進行投票的發起和決議,更新系統狀態
學習者(learner),包括跟隨者(follower)和觀察者(observer),follower用于接受客戶端請求并想客戶端返回結果,在選主過程中參與投票Observer可以接受客戶端連接,將寫請求轉發給leader,但observer不參加投票過程,只同步leader的狀態,observer的目的是為了擴展系統,提高讀取速度
客戶端(client),請求發起方,也就是我們自己的java程序
zookeeper的數據結構
ZooKeeper會維護一個具有層次關系的數據結構,非常類似于一個標準的文件系統,如下圖所示:
ZooKeeper這種數據結構有如下這些特點:
- 每個子目錄項如NameService都被稱作znode,這個znode是被它所在的路徑唯一標識,如Server1這個znode的標識為/NameService/Server1
- znode可以有子節點目錄,并且每個znode可以存儲數據,注意EPHEMERAL類型的目錄節點不能有子節點目錄
- znode是有版本的,每個znode中存儲的數據可以有多個版本,也就是一個訪問路徑中可以存儲多份數據
- znode可以是臨時節點,一旦創建這個znode的客戶端與服務器失去聯系,這個znode也將自動刪除,ZooKeeper的客戶端和服務器通信采用長連接方式,每個客戶端和服務器通過心跳來保持連接,這個連接狀態成為session,如果znode是臨時節點,這個session失效,znode也就被刪除.
- znode的目錄名可以自動編號,如App1已經存在,再創建的話,將會自動命名為App2.
- znode可以被監控,包括這個目錄節點中存儲的數據被修改,子節點目錄的變化等,一旦變化可以通知設置監控的客戶端,這個是ZooKeeper的核心特性.
ZooKeeper的典型應用場景
Zookeeper從設計模式角度來看,是一個基于觀察者模式設計的分布式服務管理框架,它負責存儲和管理大家都關心的數據,然后接受觀察者的注冊,一旦這些數據的狀態發生變化,Zookeeper就將負責通知已經在Zookeeper上注冊的那些觀察者做出相應的反應,從而實現集群中類似:Master/Slave管理模式、配置管理、集群管理、發布與訂閱、數據庫切換、分布式日志的收集、分布式環境、隊列管理等等
- 配置管理:配置的管理在分布式應用環境中很常見,比如我們在平常的應用系統
中經常會碰到這樣的需求:如機器的配置列表、運行時的開關配置、數據庫配置信
息等。這些全局配置信息通常具備以下3個特性
1.數據量比較小
2.數據內容在運行時動態發生變化
3.集群中各個節點共享信息,配置一致 - 集群管理: Zookeeper不僅能夠幫你維護當前的集群中機器的服務狀態,而且能夠幫你選出一個“總管”,讓這個總管來管理集群,這就是 Zookeeper的另一個功能Leader,它能實現集群容錯功能
1.知道當前集群中究竟有多少機器工作
2.對集群中每臺機器的運行時狀態進行數據收集
3.對集群中每臺機器進行上下線操作 - 數據庫切換:比如我們初始化zookeeper的時候讀取其節點上的數據庫配置文件,當配置發生變更時,zookeeper就能幫助我們把變更的通知發送到各個客戶端,每個客戶端在收到這個通知的時候就可以重新獲取最新的數據
- 分布式日志收集:我們可以做一個日志系統收集集群中所有的日志信息,進行統一管理
- zookeeper的特性就是在分布式場景下高可用但是原生的API實現分布式功能非常困難,團隊去實現太浪費時間,即使實現了也未必穩定那么可以采用第三方的客戶端的完美實現,比如Apache的頂級項目 Curator框架。
Zookeeper選舉
在zookeeper的選舉過程中,為了保證選舉過程最后能選出leader,就一定不能出現兩臺機器得票相同的僵局,所以一般的,要求zk集群的server數量一定要是奇數,也就是2n+1臺,并且,如果集群出現問題,其中存活的機器必須大于n+1臺,否則leader無法獲得多數server的支持,系統就自動掛掉。所以一般是3個或者5個或者7個節點以此類推。
三臺主機的選舉過程:
A提案說,我要選自己,B你同意嗎?C你同意嗎?B說,我同意選A;C說,我同意選A。(注意,這里超過半數了,其實在現實世界選舉已經成功了。但是計算機世界是很嚴格,另外要理解算法,要繼續模擬下去。 接著B提案說,我要選自己,A你同意嗎;A說,我已經超半數同意當選,你的提案無效;C說,A已經超半數同意當選,B提案無效。接著C提案說,我要選自己,A你同意嗎;A說,我已經超半數同意當選,你的提案無效;B說,A已經超半數同意當選,C的提案無效。選舉已經產生了Leader,后面的都是follower,只能服從Leader的命令。而且這里還有個小細節,就是其實誰先啟動誰當頭。
Zookeeper安裝配置
1、結構:一共三個節點(zk服務器集群規模不小于3個節點),要求服務器之間系統時間保持一致。
2、上傳zk
進行解壓:tar -zxvf zookeeper-3.4.5.tar.gz
重命名:mv zookeeper-3.4.5 zookeeper1
修改環境變量:vim /etc/profile
export ZOOKEEPER_HOME=/usr/local/zookeeper1
export PATH=.:$ZOOKEEPER_HOME/bin:$JAVA_HOME/...
刷新環境變量: source /etc/profile
到zookeeper下修改配置文件
cd /usr/local/zookeeper1/conf
mv zoo_sample.cfg zoo.cfg
修改conf: vim zoo.cfg 修改兩處
(1)dataDir=/usr/local/zookeeper1/data
(2)最后面添加
server.1=127.0.0.1:20881:30881
server.2=127.0.0.1:20882:30882
server.3=127.0.0.1:20883:30883
服務器標識配置:
創建文件夾:mkdir data
創建文件myid并填寫內容為1:vi myid (內容為服務器標識 : 1)
進行復制zookeeper1目錄到zookeeper2和zookeeper3
還有/etc/profile文件
把zookeeper2、zookeeper3中的myid文件里的值修改為2和3
啟動zookeeper:
路徑:/usr/local/zookeeper1/bin
執行:zkServer.sh start
(注意這里3臺機器都要進行啟動)
狀態:zkServer.sh status(在三個節點上檢驗zk的mode,一個leader和兩個follower)
zoo.cfg詳解:
tickTime: 基本事件單元,以毫秒為單位。這個時間是作為 Zookeeper 服務器之間或客戶端與服務器之間維持心跳的時間間隔,也就是每隔 tickTime時間就會發送一個心跳。默認2000毫秒
*dataDir:存儲內存中數據庫快照的位置,顧名思義就是 Zookeeper 保存數據的目錄,默認情況下,Zookeeper將寫數據的日志文件也保存在這個目錄里。
clientPort: 這個端口就是客戶端連接 Zookeeper 服務器的端口,Zookeeper會監聽這個端口,接受客戶端的訪問請求。
initLimit:這個配置項是用來配置 Zookeeper接受客戶端初始化連接時最長能忍受多少個心跳時間間隔數,當已經超過 10 個心跳的時間(也就是 tickTime)長度后 Zookeeper 服務器還沒有收到客戶端的返回信息,那么表明這個客戶端連接失敗??偟臅r間長度就是 10*2000=20 秒。
syncLimit:這個配置項標識 Leader 與 Follower之間發送消息,請求和應答時間長度,最長不能超過多少個 tickTime 的時間長度,總的時間長度就是 5*2000=10 秒
server.A = B:C:D : A表示這個是第幾號服務器, B 是這個服務器的 ip 地址;C 表示的是這個服務器與集群中的 Leader 服務器交換信息的端口;D 表示的是萬一集群中的 Leader 服務器掛了,需要一個端口來重新進行選舉,選出一個新的 Leader
Zookeeper CLI
ZooKeeper 命令行界面(CLI)是用來與 ZooKeeper 集成作開發進行交互的。這是在調試和使用不同的選項時的工作有用。
為了執行ZooKeeper的CLI操作, ZooKeeper服務器首先要啟動 (“bin/zkServer.sh start”) , 然后使用 ZooKeeper 客戶端 (“bin/zkCli.sh”). 當客戶端啟動后,可以執行以下操作 -
創建Znode
由一個給定的路徑來創建znode。flag參數指定了創建的 znode 是否為短暫的,持久的,或連續的。默認情況下,所有的 znodes是持久的。
短暫 znode(flag: e)當會話過期或當客戶端斷開連接將被自動刪除。
連續 znode 保證 znode 路徑是唯一的。
語法:create /path data
要創建一個連續znode,如下圖所示添加 -s 標志。
語法:create -s /path data
要創建一個臨時Znode,添加-e標志,如下圖所示。
語法:create -e /path data
記住,當丟失一個客戶端連接,在臨時 znode 將被刪除。可以通過退出 ZooKeeper CLI 嘗試,然后重新打開命令行。獲取數據
它返回 znode 的相關數據和指定 znode 元數據。這里將得到信息,例如當數據最后一次修改,在那里它被修改和有關數據的信息。此外 CLI 還用于分配監視顯示通知有關的數據。
語法:get /path設置數據
設置指定znode的數據。當你完成設置操作,就可以使用get CLI命令檢查數據。
語法
set /path data創建子znode
創建子znode類似于創建新的znodes。唯一的區別在于,子 znode 的路徑將包含有父路徑。
語法:create /parent/path/subnode/path data列出子znode
該命令用于列出和顯示子 znode 。
語法:ls /path檢查狀態
狀態描述了指定znode的元數據。它包含詳細信息,如時間戳,版本號,訪問控制列表,數據長度和子znode。
語法:stat /path刪除Znode
刪除指定znode和遞歸刪除所有的子znode。這只有在znode可用時發生。
語法:rmr /path
刪除(刪除/路徑)命令類似remove命令,但它僅適用于無子znode的znode。
語法:delete /path
Zookeeper API
ZooKeeper有一個Java和C綁定的官方API。ZooKeeper社區提供了對于大多數語言(.NET,Python等)的非官方API。使用ZooKeeper的API,應用程序可以連接,互動,操作數據,協調,以及從ZooKeeper集成斷開。
ZooKeeper API有一組豐富的功能,在一個簡單而安全的方式在ZooKeeper集成獲得所有功能。ZooKeeper API提供同步和異步方法。
ZooKeeper的集成和ZooKeeper API 在各個方面完全互補,它有利于開發商在一個簡便的方式。 在本章討論Java綁定。
ZooKeeper的API基礎知識
應用程序使用 ZooKeeper 集成的交互稱為 ZooKeeper 客戶端。
Znode 是 ZooKeeper 集成的核心組件,ZooKeeper API提供一個方法來處理znode所有使用ZooKeeper 集成。
客戶端應遵循下面給出帶 ZooKeeper 集成一個清晰的交互步驟。
連接到ZooKeeper 。ZooKeeper 集成分配客戶端的會話ID。
定期發送心跳到服務器。否則,ZooKeeper 集成過期的會話ID,那么客戶端需要重新連接。
獲得/設置只要znodes會話ID是活動的。
從 ZooKeeper 集成斷開,當所有的任務都完成后。如果客戶端處于非活動狀態較長時間,那么 ZooKeeper 集成會自動斷開客戶機。
Java代碼
ZooKeeper API的中心部分是ZooKeeper 類。它提供了一些選項來連接 ZooKeeper 集成在其構造,有以下幾種方法
connect ? 連接到 ZooKeeper 的集成
create ? 創建一個 znode
exists ? 檢查znode是否存在及其信息
getData ? 從一個特定的znode獲取數據
setData ? 設置數據在特定znode
getChildren ? 得到一個特定 znode 的所有可用子節點
delete ? 刪除一個特定的 znode 及其所有子節點
close ? 關閉連接
連接到 ZooKeeper 集合
ZooKeeper類通過它的構造函數提供了連接功能。構造函數的簽名如下:
ZooKeeper(String connectionString, int sessionTimeout, Watcher watcher)
在這里,
connectionString ? ZooKeeper集合主機。
sessionTimeout ? 以毫秒為單位會話超時。
watcher ? 一個執行對象“觀察者”的接口。ZooKeeper 集合返回通過監控器對象的連接狀態。