Zookeeper
目錄
Zookeeper 1
第一章 Zookeeper簡介... 1
1.1 Zookeeper概述和功能... 1
1.2 Zookeper安裝... 1
1.3 Zookeper數(shù)據(jù)模型... 3
第二章 Zookeeper命令操作... 4
1.1 Zookeeper Client 4
1.2 Zookeeper JavaClient 6
第三章 集群角色... 28
??????????????????????????????????????????????Zookeeper
第一章 Zookeeper簡介
1.1 Zookeeper概述和功能
Zookeeper 是 Apache Hadoop 項目下的一個子項目, 翻譯過來就是 動物園管理員,他是用來管 Hadoop(大象)、Hive(蜜蜂)、Pig(小豬)的管理員.簡稱zk.
Zookeeper 是一個分布式的、開源的分布式應用程序的協(xié)調服務。其本質上就是提供一種集中式信息存儲服務.就是一個將數(shù)據(jù)存放到內存中,以樹形結構存儲數(shù)據(jù)的服務.我們根據(jù)其存儲數(shù)據(jù)的特點可以實現(xiàn)分布式統(tǒng)一配置中心,分布式鎖等功能,主要用于分布式應用程序的高性能協(xié)調,集群高可靠等.
主要功能:
配置管理

分布式鎖

3.服務器動態(tài)上下線

1.2 Zookeper安裝
上傳解壓
#進入到apps文件夾 使用rz上傳 也可以直接拖拽到crt上傳 cd /opt/apps ? #上傳后解壓 tar -zxvf zookeeper-3.5.6.tar.gz
配置
#1.進入到解壓后的zk文件夾下 創(chuàng)建一個文件夾zkData cd /opt/apps/zookeeper-3.5.6 mkdir zkData #2.進入到zk的conf文件夾下 將zoo_sample.cfg改為zoo.cfg cd conf mv zoo_sample.cfg zoo.cfg #3.修改zoo.cfg的配置 vi zoo.cfg ? ?#將第12行dataDir的值改為我們剛才創(chuàng)建的文件夾 ?12+shift+G 直接跳轉 ? ?dataDir=/opt/apps/zookeeper-3.5.6/zkData ? ?#在文件的最后配置server的信息和端口 ? ?server.1=linux01:2888:3888 ? ?server.2=linux02:2888:3888 ? ?server.3=linux03:2888:3888 #4.進入到zkData文件夾下 添加linux01的myid為1 cd ../zkData echo 1 > myid
分發(fā)
#進入到linux01的/opt/apps文件夾下 scp -r zookeeper-3.5.6 linux02:$PWD scp -r zookeeper-3.5.6 linux03:$PWD #設置linux02上zk的myid為2 echo 2 > /opt/apps/zookeeper-3.5.6/zkData/myid cat ?/opt/apps/zookeeper-3.5.6/zkData/myid #設置linux03上zk的myid為3 echo 3 > /opt/apps/zookeeper-3.5.6/zkData/myid cat /opt/apps/zookeeper-3.5.6/zkData/myid
啟動
#zk沒有一鍵啟動我們需要挨個啟動 /opt/apps/zookeeper-3.5.6/bin/zkServer.sh start #zk查看狀態(tài) /opt/apps/zookeeper-3.5.6/bin/zkServer.sh status
一鍵啟動腳本
#!/bin/bash for hostname in linux01 linux02 linux03 do ? ?echo "當前正在操作的主機$hostname" ? ?ssh $hostname "source /etc/profile ; /opt/apps/zookeeper-3.5.6/bin/zkServer.sh $1 ;exit" done
1.3 Zookeper數(shù)據(jù)模型
ZooKeeper是一個樹形目錄服務,其數(shù)據(jù)模型和linux的文件系統(tǒng)目錄樹很類似,擁有一個層次化結構。

這里面的每一個節(jié)點都被稱為: ZNode,每個節(jié)點上都會保存自己的數(shù)據(jù)和節(jié)點信息.節(jié)點可以擁有子節(jié)點,同時也允許少量(1MB)數(shù)據(jù)存儲在該節(jié)點之下。
節(jié)點可以分為四大類:
- PERSISTENT持久化節(jié)點 - EPHEMERAL臨時節(jié)點:-e - PERSISTENT_SEQUENTIAL持久化順序節(jié)點:-s - EPHEMERAL_SEQUENTIAL臨時順序節(jié)點: -es
第二章 Zookeeper命令操作
1.1 Zookeeper Client
1.1.1 服務端命令
/opt/apps/zookeeper-3.5.6/bin/zkServer.sh start
/opt/apps/zookeeper-3.5.6/bin/zkServer.sh stop
/opt/apps/zookeeper-3.5.6/bin/zkServer.sh status
/opt/apps/zookeeper-3.5.6/bin/zkServer.sh restart
1.1.2 客戶端命令
連接服務端 /opt/apps/zookeeper-3.5.6/bin/zkCli.sh -server ?linux001:2181?
連接本地
/opt/apps/zookeeper-3.5.6/bin/zkCli.sh?
查看命令幫助
help?
?查看 ls ?目錄
?創(chuàng)建節(jié)點
?create ?/節(jié)點名 描述 create -e /節(jié)點名 描述?
? 臨時節(jié)點 create -s /節(jié)點名 描述 ? 順序節(jié)點?
?create -e -s /節(jié)點 描述 ? 臨時順序節(jié)點
查看節(jié)點?
get /節(jié)點名?
設置節(jié)點描述?
set /節(jié)點名 描述?
刪除節(jié)點
delete /節(jié)點名
刪除非空節(jié)點?
deleteAll /節(jié)點名
監(jiān)聽
ls -w 路徑 ? ?
?-- 監(jiān)聽根目錄 所有子節(jié)點的變化 ? ls - w / ??
?WATCHER::
?WatchedEvent state:SyncConnected type:NodeChildrenChanged path:/?
get -w 路徑?
-- 監(jiān)聽 /app3 節(jié)點數(shù)據(jù)的變化
?WATCHER::
?WatchedEvent state:SyncConnected type:NodeDataChanged path:/app3
1.2 Zookeeper JavaClient
1.2.1 Cuator介紹
Curator是 ApacheZooKeeper的Java客戶端庫.
常見的ZooKeeper Java APl :
????????原生JavaAPI
????????zkClient
????????Curator
Curator項目的目標是簡化ZooKeeper客戶端的使用。
Curator最初是Netfix研發(fā)的,后來捐獻了Apache基金會,目前是Apache的頂級項目。
http://curator.apache.org
坐標
? ? ? ? ? ?<!--curator--> ? ? ??
.? ? ?<dependency>? ? ? ? ?
?? ? ? <groupId>org.apache.curator</groupId> ? ? ? ? ??
? ? ?<artifactId>curator-framework</artifactId> ? ? ? ??
? ? ? ?<version>4.0.0</version> ? ? ??
? ? ?</dependency> ? ? ??
? ? ?<dependency> ? ? ?
?? ? ? ? ?<groupId>org.apache.curator</groupId> ? ? ? ?
?? ? ? ?<artifactId>curator-recipes</artifactId>?
?? ? ? ? ? ? ? ?<version>4.0.0</version>?
?? ? ? ? ? ?</dependency> ? ? ??
?????????<dependency> ? ? ?
?? ? ?????<groupId>org.apache.curator</groupId>? ??
? ? ? ? <artifactId>curator-client</artifactId> ? ? ? ?
?? ?????<version>4.0.0</version> ? ?
?? ?????</dependency>
1.2.2 建立連接
/* ??
? CuratorFrameworkFactory ? ? ? ?
? ?靜態(tài)方法獲取連接對象 ? ? ? ? ? ?
?? static CuratorFramework newClient(String connectString, int sessionTimeoutMs, int connectionTimeoutMs, RetryPolicy retryPolicy) ? ? ? ? ? ? ? ? ? ?
?? ? ? ?String connectString:連接的字符串 ? ?zkserver地址:端口 ? ? ? ? ??
? ? ? ? ? ? ????? ? ?int sessionTimeoutMs:會話超時時間 單位ms ? 默認 60 * 1000 ? ? ? ? ? ? ? ??
? ? ? ? ????? ?int connectionTimeoutMs 連接超時時間 單位ms ?默認 15 * 1000 ? ? ? ? ? ? ? ? ? ? ? ? ? ?????????????????????RetryPolicy retryPolicy 重試策略 ? 接口?? ? ? ? ? ? ? ? ? ? ? ? ??
?? ? ? ????????? ? ? ? ? ? 實現(xiàn)類ExponentialBackoffRetry ? ? ? ?
?? ? ?static CuratorFramework newClient(String connectString, RetryPolicy retryPolicy) ? ? ????????????????????CuratorFramework ? ? ? ? ?
????????????? 方法 ? ? ? ? ?
????????????? ? void ?start() 開始連接
*/?
public class Test { ?
??public static void main(String[] args) { ? ??
? ?String connectString = "linux001:2181";
// ? ? ? ?//基礎等待時間 20 ?重試次數(shù) 10 ? ??
? ?RetryPolicy r = new ExponentialBackoffRetry(20,10);?
//? ? ?? ?CuratorFramework curatorFramework = CuratorFrameworkFactory.newClient(connectString, r);
//? ? ? ? curatorFramework.start();; ? ??
? ?//第二種方式 ? ??
? ?CuratorFramework client = CuratorFrameworkFactory.builder(). ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?????????????????????????connectString(connectString) ? ? ? ? ? ? ? ? ? ? ?
?? ? ? ? ?.retryPolicy(r).build(); ? ? ? ?client.start(); ?
?}?
}
1.2.3 創(chuàng)建節(jié)點
/* ??
?CuratorFramework ? ? ?
?創(chuàng)建節(jié)點 ? ? ?
?create().forPath(節(jié)點) 創(chuàng)建節(jié)點 不指定數(shù)據(jù) 默認為 ip地址 ??
?create().forPath(節(jié)點,byte[] data) ?創(chuàng)建節(jié)點 指定數(shù)據(jù) 字節(jié)數(shù)組 ? ? ? ?create().withMode().forPath(節(jié)點,byte[] data) ?創(chuàng)建節(jié)點 指定節(jié)點類型 默認類型 持久化 ? ? ? ? ? ? ? ? ? ?CreateMode.EPHEMERAL 臨時節(jié)點 ? ? ? ? ? ?
? ? ? ?????CreateMode.PERSISTENT 持久節(jié)點? ? ? ??? ? ? ? ? ??????????????????????????????? ? ? ? ? CreateMode.PERSISTENT_SEQUENTIAL 持久順序節(jié)點 ? ? ? ? ? ? ? ? ? ?CreateMode.EPHEMERAL_SEQUENTIAL ?臨時順序節(jié)點 ? ? ? ?create().creatingParentsIfNeeded().forPath(節(jié)點,byte[] data) 創(chuàng)建多級節(jié)點
*/
?public class Test {?
? public static void main(String[] args) throws Exception { ? ??
? ?CuratorFramework client = CuratorUtils.getClient(); ? ??
? ?client.start(); ? ??
? ?//創(chuàng)建節(jié)點 ?由于指定了命名空間 所以會在 /doit下創(chuàng)建 ? ??
? ?//沒有指定數(shù)據(jù) 默認數(shù)據(jù)是當前客戶端的ip地址 ? ??
? ?// ?client.create().forPath("/app1"); ? ? ?
??//創(chuàng)建節(jié)點 指定數(shù)據(jù) ? ? ?
??//client.create().forPath("/app2","abc".getBytes()); ? ? ?
??//創(chuàng)建臨時節(jié)點 ?指定數(shù)據(jù)?
// ? ? ? ?client.create().withMode(CreateMode.EPHEMERAL).forPath("/app3","aa".getBytes()); ? ? ? ?//Thread.sleep(10000); ? ??
? ?//創(chuàng)建多級節(jié)點 ? ? ??
?client.create().creatingParentsIfNeeded().forPath("/app3/p1/p", "abc".getBytes()); ? ? ? ?client.close(); ?
??}?
}
1.2.4 查看節(jié)點
/* ??
? 查看節(jié)點 ? ?
* 1. 查詢數(shù)據(jù):get: getData().forPath() ? ??
* 2. 查詢子節(jié)點: ls: getChildren().forPath() ? ??
* 3. 查詢節(jié)點狀態(tài)信息:ls -s:getData().storingStatIn(狀態(tài)對象).forPath()
*/?
public class Test02 { ? ?
public static void main(String[] args) throws Exception { ? ? ??
?CuratorFramework client = CuratorUtils.getClient(); ? ? ??
?client.start(); ? ? ?
??//查詢節(jié)點數(shù)據(jù) ? ?
?? ?byte[] bytes = client.getData().forPath("/app1"); ? ? ?
??System.out.println(new String(bytes)); ? ?
?? ?//查詢子節(jié)點 ? ?
?? ?List<String> list = client.getChildren().forPath("/"); ? ?
?? ?for (String s : list) { ? ??
? ? ? ?System.out.println(s); ? ? ?
??} ? ??
? ?//查詢節(jié)點狀態(tài)信息 ?ls -s ? ??
? ?Stat s = new Stat();?
?? ? ? ?client.getData().storingStatIn(s).forPath("/app1"); ??
? ? ?System.out.println(s.getCzxid()); ?
?? ? ?client.close();?
?? ?}
?}
1.2.5 修改數(shù)據(jù)
/** ??
? * 修改數(shù)據(jù) ? ??
* 1. 基本修改數(shù)據(jù):setData().forPath() ? ??
* 2. 根據(jù)版本修改: setData().withVersion().forPath() ? ?
* * version 是通過查詢出來的。目的就是為了讓其他客戶端或者線程不干擾我。 ? ??
*/ public class Test03 { ?
?public static void main(String[] args) throws Exception { ? ? ??
?CuratorFramework client = CuratorUtils.getClient(); ? ? ?
??client.start(); ? ??
? ?//基本修改數(shù)據(jù)?
//? ? ??? client.setData().forPath("/app1","v1".getBytes());
?// ? ? ? ?byte[] bytes = client.getData().forPath("/app1");?
// ? ? ? ?System.out.println(new String(bytes)); ? ? ? ?
//查詢版本 ? ? ?
??Stat s = new Stat(); ? ??
? ?client.getData().storingStatIn(s).forPath("/app1"); ? ? ? ?int version = s.getVersion(); ? ? ? ?
//使用版本進行設置 ? ? ??
?client.setData().withVersion(version).forPath("/app1"); ? ?
?? ?byte[] bytes = client.getData().forPath("/app1"); ? ?
?? ?System.out.println(new String(bytes)); ? ? ? ? ??
? ? ?client.close(); ??
? ? }
?}
1.2.6 刪除節(jié)點
/** ? ?
* 刪除節(jié)點: delete deleteall ? ??
* 1. 刪除單個節(jié)點:delete().forPath("/app1"); ? ??
* 2. 刪除帶有子節(jié)點的節(jié)點:delete().deletingChildrenIfNeeded().forPath("/app1"); ? ??
* 3. 必須成功的刪除:為了防止網(wǎng)絡抖動。本質就是重試。 ?client.delete().guaranteed().forPath("/app2"); ? ??
* 4. 回調:inBackground? ? ?
*/
public class Test04 { ??
?public static void main(String[] args) throws Exception { ? ? ??
?CuratorFramework client = CuratorUtils.getClient(); ? ? ?
??client.start(); ? ? ??
?//刪除單個節(jié)點 ? ?
?// ? client.delete().forPath("/app1"); ? ??
? ?//刪除帶子節(jié)點的節(jié)點
// ? ? ? ?client.delete().deletingChildrenIfNeeded().forPath("/app3"); ? ? ??
?//必須成功的刪除:為了防止網(wǎng)絡抖動。本質就是重試。
// ? ? ? ?client.delete().guaranteed().forPath("/aa"); ? ? ? ?client.delete().guaranteed().inBackground(new BackgroundCallback() { ? ? ? ? ? ?
@Override ? ? ? ? ?
??public void processResult(CuratorFramework client, CuratorEvent event) throws Exception { ? ? ? ? ? ? ? ?System.out.println("我被刪除了"); ? ? ? ? ? ??
? ?System.out.println(event); ? ? ? ??
? ?} ? ? ?
??}).forPath("/app2"); ? ? ??
?client.close(); ??
?}?
}
1.2.7 注冊監(jiān)聽
監(jiān)聽數(shù)據(jù)變化
public class Test05 { ??
?public static void main(String[] args) throws Exception { ? ? ?
??CuratorFramework client = CuratorUtils.getClient(); ? ? ??
?client.start(); ? ? ?
??//創(chuàng)建 NodeCache對象 ? ??
? ?NodeCache nodeCache = new NodeCache(client,"/app1"); ? ??
? ?//2.注冊監(jiān)聽 ? ? ?
?nodeCache.getListenable().addListener(new NodeCacheListener() { ? ? ? ?
?? ?@Override ? ? ??
? ? ?public void nodeChanged() throws Exception { ? ? ? ??
? ? ? ?System.out.println("節(jié)點變化了"); ? ? ? ?
?? ? ? ?byte[] data = nodeCache.getCurrentData().getData(); ? ? ? ? ? ?
?? ?System.out.println(new String(data)); ? ? ??
? ? ?} ? ??
? ?}); ? ?
??//3. 開啟監(jiān)聽.如果設置為true,則開啟監(jiān)聽是,加載緩沖數(shù)據(jù) ? ? ?
??nodeCache.start(true); ? ? ? ?
?// ? ? ? ?Thread.sleep(1000000); ? ?
}
?}
監(jiān)聽子節(jié)點變化
public class Test06 { ?
??public static void main(String[] args) throws Exception { ? ? ?
??CuratorFramework client = CuratorUtils.getClient(); ? ??
? ?client.start(); ??
? ? ?PathChildrenCache pathChildrenCache = new PathChildrenCache(client,"/app3",true); ? ? ? ?pathChildrenCache.getListenable().addListener(new PathChildrenCacheListener() { ? ? ? ? ? ?@Override ? ? ?
?? ? ?public void childEvent(CuratorFramework curatorFramework,?
PathChildrenCacheEvent pathChildrenCacheEvent) throws Exception {? ? ? ? ??
? ? ? System.out.println("子節(jié)點變化了"); ? ? ? ? ? ? ? ?System.out.println(pathChildrenCacheEvent); ? ? ? ? ? ?
?? ?PathChildrenCacheEvent.Type type = pathChildrenCacheEvent.getType(); ? ? ? ? ? ? ? ?if(type.equals(PathChildrenCacheEvent.Type.CHILD_UPDATED)){ ? ? ? ? ??
? ? ? ? ?byte[] data = pathChildrenCacheEvent.getData().getData(); ? ? ? ? ? ? ? ? ? ?System.out.println(new String(data)); ? ? ? ?
?? ? ? ?} ? ? ? ?
?? ?} ? ?
?? ?}); ? ? ? ?
pathChildrenCache.start(); ? ? ? ? ??
? ? ?Thread.sleep(1000000); ??
?}
?}
/* ??
? TreeCache 相當于 NodeCache與PathChildrenCache組合 ? ?
?? ?監(jiān)聽當前節(jié)點 與 子節(jié)點?
?*/
public class Test07 { ?
?public static void main(String[] args) throws Exception { ? ??
? ?CuratorFramework client = CuratorUtils.getClient(); ? ? ?
??client.start(); ? ? ?
??TreeCache treeCache = new TreeCache(client,"/app4"); ? ? ? ?treeCache.getListenable().addListener(new TreeCacheListener() { ??
? ? ? ? ?@Override ? ??
? ? ? ?public void childEvent(CuratorFramework curatorFramework,?
TreeCacheEvent treeCacheEvent) throws Exception { ? ? ??
? ? ? ? ?System.out.println(treeCacheEvent); ? ? ??
? ? ?} ? ?
?? ?}); ??
? ? ?treeCache.start(); ? ? ?
??Thread.sleep(10000000);?
?? ?}
?}
第三章 集群角色
在ZooKeeper集群服中務中有三個角色:
Leader 領導者 :
1. 處理事務請求 2. 集群內部各服務器的調度者
Follower 跟隨者 :
1.處理客戶端非事務請求,轉發(fā)事務請求給Leader服務器
2.參與Leader選舉投票
Observer 觀察者:
1.處理客戶端非事務請求,轉發(fā)事務請求給Leader服務器

選舉機制
假設3臺linux linux01 啟動 投自己一票 廣播 linux02 啟動 收到linux01 廣播 ? 投自己一票 linux01 發(fā)現(xiàn) linux02的id比自己的id大 ?投linux02一票 linux02 投票超過半數(shù) 選為 leader ? linux03 啟動 由于已經(jīng)有了leader ?follower
如果leader宕機
看誰的版本號新 誰為leader 如果版本號相同 誰id大 誰是leader