3.大資料學習之旅——Zookeeper
阿新 • • 發佈:2019-01-12
Zookeeper
Zookeeper是開源的分散式的協調服務框架,是Apache Hadoop的子件,適用
於絕大部分分散式叢集的管理
分散式引發問題:
- 死鎖:至少有一個執行緒佔用了資源,但是不佔用CPU
- 活鎖:所有執行緒都沒有把持資源,但是執行緒卻是在不斷地排程佔用CPU
- 需要引入一個管理節點
- 為了防止入口的單點問題,需要引入管理節點的叢集
- 需要在管理階段中選舉出一個主節點
- 需要確定一套選舉演算法
- 主節點和從節點之間要保證資料的一致
Zookeeper的安裝可以分為單機版和叢集式
Zookeeper的單機版安裝
Zookeeper可以安裝在Linux下,也可以安裝在Windows中,但是官網上宣告
在Windows中Zookeeper不保證穩定性
- 關閉Linux的防火牆
- 臨時關閉:service iptables stop
- 永久關閉:chkconfig iptables off
- 下載並且安裝jdk,要求jdk是1.6以上的版本
- 下載Zookeeper的安裝包
- 解壓安裝包:tar - xvf zookeeper-3.4.8.tar.gz
- 進入Zookeeper的安裝目錄中的conf目錄:cd zookeeper-3.4.8/conf
- 將zoo_sample.cfg複製為zoo.cfg:cp zoo_sample.cfg zoo.cfg
- Zookeeper在啟動的時候會自動載入zoo.cfg,從裡面讀取配置資訊,需要
修改zoo.cfg,將其中的dataDir進行修改:
dataDir=/home/software/zookeeper-3.4.8/tmp - 建立指定的資料儲存目錄:mkdir tmp
- 進入bin目錄:cd bin
- 啟動伺服器端:sh zkServer.sh start
- 啟動客戶端:sh zkCli.sh
注意:
Zookeeper返回Started不代表啟動成功,可以通過jps或者是sh zkServer.sh
status來檢視是否啟動成功
如果使用的是jps,檢視是否有QuorumPeerMain
如果使用的是sh zkServer.sh status, 檢視是否有Mode:standalone
當Zookeeper啟動之後,在bin目錄下會出現zookeeper.out檔案 — 記錄
Zookeeper的啟動過程的日誌檔案
Zookeeper的特點
- 本身是一個樹狀結構 — Znode樹
- 每一個節點稱之為znode節點
- 根節點是 / 3.
- Zookeeper的所有操作都必須以根節點為基準進行計算 /
- 每一個znode節點都必須儲存資料
- 任意一個持久節點都可以有子節點
- 任意一個節點的路徑都是唯一的
- Znode樹是維繫在記憶體中 — 目的是為了快速查詢
- Zookeeper不適合儲存海量資料。原因:1)維繫在記憶體中,如果儲存大
量資料會耗費記憶體 2) 不是一個儲存框架而是一個服務協調框架 - Zookeeper會為每一次事務(除了讀取以外的所有操作都是事務)分配一
個全域性的事務id —Zxid
Zookeeper的命令
- create /node01 “hello zookeeper” 在根節點下建立子節點node01並且賦值
為hello zookeeper - set /node01 “hi” 將node01的資料更新為hi
- get /node01 獲取node01的資料
- ls / 檢視根節點下的所有的子節點
- delete /node02 刪除子節點,要求這個節點中沒有子節點
- rmr /node01 刪除node01及其子節點
- quit 退出客戶端
- create -e /node02 ‘’ 表示在根目錄下建立臨時節點/node02
- create -s /node03 ‘’ 表示在根目錄下建立持久順序節
點/node03000000000X - create -e -s /node04 ‘’ 表示在根目錄下建立臨時順序節點/node04000000000X
Zookeeper的節點型別
- 持久節點
- 臨時節點:在客戶端退出之後就自動刪除
- 持久順序節點
- 臨時順序節點
Zookeeper的節點資訊
- cZxid - 全域性分配的建立的事務id — 建立這個節點是Zookeeper的第n個操
作 — 定義好之後就不變了 - ctime - 建立時間
- mZxid - 修改的事務id — 記錄自己本身修改
- mtime - 修改時間
- pZxid - 表示子節點的變化的事務id — 記錄直接子節點的建立或者刪除
- cversion - 記錄子節點變化次數
- dataVersion - 資料版本 — 記錄當前節點的資料的變化次數
- aclVersion - acl版本 — 記錄當前節點的acl的變化次數
- ephemeralOwner - 如果當前節點不是臨時節點,那麼這個屬性的值為0;
如果是臨時節點,那麼這個屬性的值記錄的是當前臨時節點的session id - dataLength - 資料長度 - 實際上是位元組個數
- numChildren - 子節點個數
Zookeeper的API操作
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.util.List;
import java.util.concurrent.CountDownLatch;
import org.apache.zookeeper.CreateMode;
import org.apache.zookeeper.KeeperException;
import org.apache.zookeeper.WatchedEvent;
import org.apache.zookeeper.Watcher;
import org.apache.zookeeper.Watcher.Event.KeeperState;
import org.apache.zookeeper.ZooDefs.Ids;
import org.apache.zookeeper.ZooKeeper;
import org.apache.zookeeper.data.Stat;
import org.junit.Before;
import org.junit.Test;
public class ZookeeperDemo {
ZooKeeper zk;
@Before
public void connect() throws IOException, InterruptedException {
CountDownLatch cdl = new CountDownLatch(1);
// connectString - 連線地址+埠號
// sessionTimeout - 會話超時時間 - 表示連線超時時間,單位預設為毫秒
// watcher - 監控者 - 監控連線狀態
// Zookeeper本身是一個非阻塞式連線
zk = new ZooKeeper("117.50.90.232:2181", 5000, new Watcher() {
// 監控連線狀態
public void process(WatchedEvent event) {
if (event.getState() == KeeperState.SyncConnected) {
System.out.println("連線成功~~~");
}
cdl.countDown();
}
});
cdl.await();
}
// 建立節點
@Test
public void create() throws KeeperException, InterruptedException {
// path - 節點路徑
// data - 資料
// acl - acl策略
// createMode - 節點型別
// 返回值表示節點的實際路徑
String str = zk.create("/node08", "hello,1807".getBytes(), Ids.OPEN_ACL_UNSAFE,
CreateMode.PERSISTENT_SEQUENTIAL);
System.out.println(str);
}
// 刪除節點
@Test
public void delete() throws InterruptedException, KeeperException {
// path - 節點路徑
// version - 資料版本
// 在刪除節點的時候回比較指定的資料版本和節點的實際資料版本是否一致
// 如果一致則刪除,如果不一致則放棄該操作
// zk.delete("/node04", 0);
// -1表示強制執行
zk.delete("/node04", -1);
}
// 更新資料
@Test
public void set() throws KeeperException, InterruptedException{
// path - 節點路徑
//data - 資料
// version - 資料版本
// 返回節點資訊
Stat s = zk.setData("/node02", "hi,zk".getBytes(), -1);
System.out.println(s);
}
// 獲取節點的資料
@Test
public void get() throws KeeperException, InterruptedException, UnsupportedEncodingException {
// path - 節點路徑
// watch - 監控
// stat - 節點資訊
Stat s = new Stat();
byte[] data = zk.getData("/node01", null, s );
System.out.println(new String(data, "utf-8"));
}
// 判斷節點是否存在
@Test
public void exist() throws KeeperException, InterruptedException{
// path - 節點路徑
// watch - 監控者
// 返回的節點的資訊
Stat s = zk.exists("/node07", null);
System.out.println(s);
}
// 獲取子節點
@Test
public void getChidren() throws KeeperException, InterruptedException {
// path - 節點路徑
// watch - 監控者
// 返回子節點的路徑
List<String> nodes = zk.getChildren("/" ,null);
for (String p : nodes) {
System.out.println(p);
}
}
}
Zookeeper的叢集安裝
- 關閉防火牆
- 安裝jdk
- 下載Zookeeper的安裝包
- 解壓Zookeeper的安裝包
- 進入Zookeeper的安裝目錄中conf目錄
- 將zoo_sample.cfg複製為zoo.cfg
- 編輯zoo.cfg,修改dataDir屬性:
dataDir=/home/software/zookeeper-3.4.8/tmp
server.1=10.9.162.133:2888:3888 # 1是編號,要求每一個節點的編號是數
字且不重複;
server.2=10.9.152.65:2888:3888 #2888,3888是埠號,只要不和已經佔用
的埠號衝突即可
server.3=10.9.130.83:2888:3888 - 建立儲存資料的目錄
- 進入資料儲存目錄
- 編輯檔案myid, 將當前機器的編號寫到myid中
- 將配置好的Zookeeper的安裝目錄拷到其他叢集主機中:scp -r
zookeeper-3.4.8 10.9.130.83:/home/software/ - 根據指定的編號修改對應的myid
在Zookeeper叢集中,單獨啟動一臺主機是不對外提供服務的
Zookeeper在使用過程中,會進行選舉,選舉出主節點-leader,其他的節點
就會成為從節點-follower
Zookeeper的選舉
第一階段:資料恢復階段
會從資料目錄(dataDir)中恢復資料
- 所有的節點都會推薦自己當leader並且傳送自己的選舉資訊(最大事務
id - pZxid,編號 - myid,邏輯時鐘值) - 選舉原則:先比較最大事務id,誰的事務id大誰就勝出;如果最大事務id
一樣,則比較myid,誰的myid大誰就勝出 - 選舉出的leader的勝出要滿足過半性:即要比至少一半的節點大
- 如果在叢集中新加入一個節點,節點的事務id比leader的事務id大,新的
節點是否會成為leader? — 不會。只要選定了一個leader,那麼後續節點
的事務id和myid無論是多少,一律都是follower - 如果leader宕機,叢集中會自動選舉一個新的leader
第二階段:選舉階段
如果超過一半的伺服器宕機,那麼此時Zookeeper不再對外提供服務 — 過
半性
01 02 03 => 02成為leader
01 03 02 => 03成為leader
節點的狀態
- Looking - 選舉狀態
- follower - 追隨者
- leader - 領導者
- observer - 觀察者
Zookeeper的投票是ZAB協議。ZAB是2PC協議的基礎上來進行的延伸。
2PC:將節點分為了協調者和參與者。當來一個請求的時候,協調者是將請
求分發給每一個參與者,如果所有的參與者決定執行這個請求,那麼協調者
就真正提交操作,有參與者執行,參與者在執行完成之後返回Ack表示執行
成功。如果協調者將請求分發給每一個參與者之後,有一個或者多個參與者
不同意執行或者是沒有返回訊息,那麼將這個操作回滾,不執行 — 一票否
決
在Zookeeper中,接收一個請求之後,leader會將請求分發給每一個節點,由
所有的節點投票確定是否執行這個請求 — 如果有超過一半的節點同意執行
這個請求,那麼這個時候leader才會決定執行這個操作
過半性:
- 選舉leader的要滿足過半性
- 請求操作也要滿足過半性
- 過半叢集才能對外提供服務 — 防止腦裂 — 腦裂:叢集中產生2個及以
上的leader — 一般將叢集節點設定為奇數
觀察者
執行操作,但是不參與選舉和投票。
- 12個觀察者宕機,依然對外提供服務
- 4個follower宕機,不對外提供服務
21個節點 — 14個觀察者,6個follower以及1個leader
觀察者不參與投票,所以就不影響叢集的執行狀態 — 適用於網路不穩定的
情況
找到要設定為觀察者的主機,編輯zoo.cfg,新增:peerType=observer,再在
要設定的主機之後新增observer標記,例如:server.3=
10.9.130.83:2888:3888:observer,然後重新啟動這一個節點
上一篇 2.大資料學習之旅——紅黑樹