第1章 Zookeeper入門1.1 概述1.2 特色1.3 數據結構1.4 應用場景1.5 下載地址第2章 Zookeeper安裝2.1 本地模式安裝部署2.2 配置參數解讀第3章 Zookeeper內部原理3.1 選舉機制(面試重點)3.2 節點類型3.3 stat結構體3.4 監聽器原理(面試重點)3.5 寫數據流程第4章 Zookeeper實戰(開發重點)4.1 分佈式安裝部署4.2 客戶端命令行操做4.3 API應用4.3.1 Eclipse環境搭建4.3.2 建立ZooKeeper客戶端4.3.3 建立子節點4.3.4 獲取子節點並監聽節點變化4.3.5 判斷Znode是否存在4.4 監聽服務器節點動態上下線案例第5章 企業面試真題5.1 請簡述ZooKeeper的選舉機制(半數機制)5.2 ZooKeeper的監聽原理是什麼?5.3 ZooKeeper的部署方式有哪幾種?集羣中的角色有哪些?集羣最少須要幾臺機器?5.4 ZooKeeper的經常使用命令java
Zookeeper是一個開源的分佈式的,爲分佈式應用提供協調服務的Apache項目。node
提供的服務包括:統一命名服務、統一配置管理、統一集羣管理、服務器節點動態上下線、軟負載均衡等。
統一命名服務linux
一、官網首頁:
https://zookeeper.apache.org/面試
一、安裝前準備
(1)安裝jdk
(2)拷貝Zookeeper安裝包到Linux系統下
(3)解壓到指定目錄spring
[atguigu@hadoop102 software]$ tar -zxvf zookeeper-3.4.10.tar.gz -C /opt/module/
二、配置修改
(1)將/opt/module/zookeeper-3.4.10/conf/這個路徑下的zoo_sample.cfg修改成zoo.cfg;apache
[atguigu@hadoop102 conf]$ pwd
/opt/module/zookeeper-3.4.10/conf
[atguigu@hadoop102 conf]$ mv zoo_sample.cfg zoo.cfg
(2)打開zoo.cfg文件,修改dataDir路徑:vim
[atguigu@hadoop102 zookeeper-3.4.10]$ vim zoo.cfg
修改以下內容:ruby
dataDir=/opt/module/zookeeper-3.4.10/zkData
(3)在/opt/module/zookeeper-3.4.10/這個目錄上建立zkData文件夾bash
[atguigu@hadoop102 zookeeper-3.4.10]$ mkdir zkData
三、操做Zookeeper
(1)啓動Zookeeper:服務器
[atguigu@hadoop102 zookeeper-3.4.10]$ bin/zkServer.sh start
(2)查看進程是否啓動:
[atguigu@hadoop102 zookeeper-3.4.10]$ jps
4020 Jps
4001 QuorumPeerMain
(3)查看狀態:
[atguigu@hadoop102 zookeeper-3.4.10]$ bin/zkServer.sh status
ZooKeeper JMX enabled by default
Using config: /opt/module/zookeeper-3.4.10/bin/../conf/zoo.cfg
Mode: standalone
(4)啓動客戶端:
[atguigu@hadoop102 zookeeper-3.4.10]$ bin/zkCli.sh
(5)退出客戶端:
[zk: localhost:2181(CONNECTED) 0] quit
(6)中止Zookeeper服務:
[atguigu@hadoop102 zookeeper-3.4.10]$ bin/zkServer.sh stop
Zookeeper中的配置文件zoo.cfg中參數含義解讀以下:
心跳機制
,而且設置最小的session超時時間爲兩倍心跳時間。(session的最小超時時間是2*tickTime)Follower跟隨者服務器
與Leader領導者服務器
之間初始鏈接時能容忍的最多心跳數(tickTime的數量),用它來限定集羣中的Zookeeper服務器鏈接到Leader的時限。1)半數機制(Paxos 協議):集羣中半數以上機器存活,集羣可用。因此Zookeeper適合安裝奇數臺服務器。
2)Zookeeper雖然在配置文件中並無指定Master和Slave。可是,Zookeeper工做時,是有一個節點爲Leader,其餘則爲Follower,Leader是經過內部的選舉機制
臨時產生的。
3)以一個簡單的例子來講明整個選舉的過程。
假設有五臺服務器組成的Zookeeper集羣,它們的id從1-5,同時它們都是最新啓動的,也就是沒有歷史數據,在存放數據量這一點上,都是同樣的。假設這些服務器依序啓動,來看看會發生什麼,以下圖所示。
(1)服務器1啓動,此時只有它一臺服務器啓動了,它發出去的報文沒有任何響應,因此它的選舉狀態一直是LOOKING狀態。
(2)服務器2啓動,它與最開始啓動的服務器1進行通訊,互相交換本身的選舉結果,因爲二者都沒有歷史數據,因此id值較大的服務器2勝出,可是因爲沒有達到超過半數以上的服務器都贊成選舉它(這個例子中的半數以上是3),因此服務器一、2仍是繼續保持LOOKING狀態。
(3)服務器3啓動,根據前面的理論分析,服務器3成爲服務器一、二、3中的老大,而與上面不一樣的是,此時有三臺服務器選舉了它,因此它成爲了此次選舉的Leader。
(4)服務器4啓動,根據前面的分析,理論上服務器4應該是服務器一、二、三、4中最大的,可是因爲前面已經有半數以上的服務器選舉了服務器3,因此它只能接收當小弟的命了。
(5)服務器5啓動,同4同樣當小弟。
10)dataLength - znode的數據長度
11)numChildren - znode子節點數量
一、集羣規劃
在hadoop10二、hadoop103和hadoop104三個節點上部署Zookeeper。
二、解壓安裝
(1)解壓Zookeeper安裝包到/opt/module/目錄下
[atguigu@hadoop102 software]$ tar -zxvf zookeeper-3.4.10.tar.gz -C /opt/module/
(2)同步/opt/module/zookeeper-3.4.10/目錄內容到hadoop10三、hadoop104
[atguigu@hadoop102 module]$ xsync zookeeper-3.4.10/
三、配置服務器編號
(1)在/opt/module/zookeeper-3.4.10/這個目錄下建立zkData
[atguigu@hadoop102 zookeeper-3.4.10]$ mkdir -p zkData
(2)在/opt/module/zookeeper-3.4.10/zkData目錄下建立一個myid的文件
[atguigu@hadoop102 zkData]$ touch myid
添加myid文件,注意必定要在linux裏面建立,在notepad++裏面極可能亂碼。
(3)編輯myid文件
[atguigu@hadoop102 zkData]$ vim myid
在文件中添加與server對應的編號:
2
(4)拷貝配置好的zookeeper到其餘機器上
[atguigu@hadoop102 zkData]$ xsync myid
並分別在hadoop10二、hadoop103上修改myid文件中內容爲三、4
四、配置zoo.cfg文件
(1)重命名/opt/module/zookeeper-3.4.10/conf這個目錄下的zoo_sample.cfg爲zoo.cfg
[atguigu@hadoop102 conf]$ mv zoo_sample.cfg zoo.cfg
(2)打開zoo.cfg文件
[atguigu@hadoop102 conf]$ vim zoo.cfg
修改數據存儲路徑配置
dataDir=/opt/module/zookeeper-3.4.10/zkData
增長以下配置
#######################cluster##########################
server.2=hadoop102:2888:3888
server.3=hadoop103:2888:3888
server.4=hadoop104:2888:3888
(3)同步zoo.cfg配置文件
[atguigu@hadoop102 conf]$ xsync zoo.cfg
(4)配置參數解讀
server.A=B:C:D。
A是一個數字,表示這個是第幾號服務器;
集羣模式下配置一個文件myid,這個文件在dataDir目錄下,這個文件裏面有一個數據就是A的值,Zookeeper啓動時讀取此文件,拿到裏面的數據與zoo.cfg裏面的配置信息比較從而判斷究竟是哪一個server。
B是這個服務器的ip地址;
C是這個服務器與集羣中的Leader服務器交換信息
的端口;
D是萬一集羣中的Leader服務器掛了,須要一個端口來從新進行選舉,選出一個新的Leader,而這個端口就是用來執行選舉時
服務器相互通訊的端口。
四、集羣操做
(1)分別啓動Zookeeper
[atguigu@hadoop102 zookeeper-3.4.10]$ bin/zkServer.sh start
[atguigu@hadoop103 zookeeper-3.4.10]$ bin/zkServer.sh start
[atguigu@hadoop104 zookeeper-3.4.10]$ bin/zkServer.sh start
(2)查看狀態
[atguigu@hadoop102 zookeeper-3.4.10]# bin/zkServer.sh status
JMX enabled by default
Using config: /opt/module/zookeeper-3.4.10/bin/../conf/zoo.cfg
Mode: follower
[atguigu@hadoop103 zookeeper-3.4.10]# bin/zkServer.sh status
JMX enabled by default
Using config: /opt/module/zookeeper-3.4.10/bin/../conf/zoo.cfg
Mode: leader
[atguigu@hadoop104 zookeeper-3.4.5]# bin/zkServer.sh status
JMX enabled by default
Using config: /opt/module/zookeeper-3.4.10/bin/../conf/zoo.cfg
Mode: follower
一、啓動客戶端
[atguigu@hadoop103 zookeeper-3.4.10]$ bin/zkCli.sh
二、顯示全部操做命令
[zk: localhost:2181(CONNECTED) 1] help
三、查看當前znode中所包含的內容
[zk: localhost:2181(CONNECTED) 0] ls /
[zookeeper]
四、查看當前節點詳細數據
[zk: localhost:2181(CONNECTED) 1] ls2 /
[zookeeper]
cZxid = 0x0
ctime = Thu Jan 01 08:00:00 CST 1970
mZxid = 0x0
mtime = Thu Jan 01 08:00:00 CST 1970
pZxid = 0x0
cversion = -1
dataVersion = 0
aclVersion = 0
ephemeralOwner = 0x0
dataLength = 0
numChildren = 1
五、分別建立2個普通節點
[zk: localhost:2181(CONNECTED) 3] create /sanguo "zhuge"
Created /sanguo
[zk: localhost:2181(CONNECTED) 4] create /sanguo/shuguo "liubei"
Created /sanguo/shuguo
六、得到節點的值
[zk: localhost:2181(CONNECTED) 5] get /sanguo
zhuge
cZxid = 0x100000003
ctime = Wed Aug 29 00:03:23 CST 2018
mZxid = 0x100000003
mtime = Wed Aug 29 00:03:23 CST 2018
pZxid = 0x100000004
cversion = 1
dataVersion = 0
aclVersion = 0
ephemeralOwner = 0x0
dataLength = 7
numChildren = 1
[zk: localhost:2181(CONNECTED) 6]
[zk: localhost:2181(CONNECTED) 6] get /sanguo/shuguo
liubei
cZxid = 0x100000004
ctime = Wed Aug 29 00:04:35 CST 2018
mZxid = 0x100000004
mtime = Wed Aug 29 00:04:35 CST 2018
pZxid = 0x100000004
cversion = 0
dataVersion = 0
aclVersion = 0
ephemeralOwner = 0x0
dataLength = 6
numChildren = 0
七、建立短暫節點
[zk: localhost:2181(CONNECTED) 7] create -e /sanguo/wuguo "zhouyu"
Created /sanguo/wuguo
(1)在當前客戶端是能查看到的
[zk: localhost:2181(CONNECTED) 3] ls /sanguo
[wuguo, shuguo]
(2)退出當前客戶端而後再重啓客戶端
[zk: localhost:2181(CONNECTED) 12] quit
[atguigu@hadoop104 zookeeper-3.4.10]$ bin/zkCli.sh
(3)再次查看根目錄下短暫節點已經刪除
[zk: localhost:2181(CONNECTED) 0] ls /sanguo
[shuguo]
八、建立帶序號的節點
(1)先建立一個普通的根節點/sanguo/weiguo
[zk: localhost:2181(CONNECTED) 1] create /sanguo/weiguo "caocao"
Created /sanguo/weiguo
(2)建立帶序號的節點
[zk: localhost:2181(CONNECTED) 2] create -s /sanguo/weiguo/xiaoqiao "jinlian"
Created /sanguo/weiguo/xiaoqiao0000000000
[zk: localhost:2181(CONNECTED) 3] create -s /sanguo/weiguo/daqiao "jinlian2"
Created /sanguo/weiguo/daqiao0000000001
[zk: localhost:2181(CONNECTED) 4] create -s /sanguo/weiguo/diaocan "jinlian3"
Created /sanguo/weiguo/diaocan0000000002
若是原來沒有序號節點,序號從0開始依次遞增。若是原節點下已有2個節點,則再排序時從2開始,以此類推。
九、修改節點數據值
[zk: localhost:2181(CONNECTED) 6] set /sanguo/weiguo "simayi"
十、節點的值變化監聽
(1)在hadoop104主機上註冊監聽/sanguo節點數據變化
[zk: localhost:2181(CONNECTED) 8] get /sanguo watch
(2)在hadoop103主機上修改/sanguo節點的數據
[zk: localhost:2181(CONNECTED) 1] set /sanguo "xisi"
(3)觀察hadoop104主機收到數據變化的監聽
WATCHER::
WatchedEvent state:SyncConnected type:NodeDataChanged path:/sanguo
注意:該註冊監聽一次,那麼就只生效一次。下次須要從新註冊。
十一、節點的子節點變化監聽(路徑變化)
(1)在hadoop104主機上註冊監聽/sanguo節點的子節點變化
[zk: localhost:2181(CONNECTED) 1] ls /sanguo watch
[aa0000000001, server101]
(2)在hadoop103主機/sanguo節點上建立子節點
[zk: localhost:2181(CONNECTED) 2] create /sanguo/jin "simayi"
Created /sanguo/jin
(3)觀察hadoop104主機收到子節點變化的監聽
WATCHER::
WatchedEvent state:SyncConnected type:NodeChildrenChanged path:/sanguo
注意:該註冊監聽一次,那麼就只生效一次。下次須要從新註冊。
十二、刪除節點
[zk: localhost:2181(CONNECTED) 4] delete /sanguo/jin
1三、遞歸刪除節點
[zk: localhost:2181(CONNECTED) 15] rmr /sanguo/shuguo
1四、查看節點狀態
[zk: localhost:2181(CONNECTED) 17] stat /sanguo
cZxid = 0x100000003
ctime = Wed Aug 29 00:03:23 CST 2018
mZxid = 0x100000011
mtime = Wed Aug 29 00:21:23 CST 2018
pZxid = 0x100000014
cversion = 9
dataVersion = 1
aclVersion = 0
ephemeralOwner = 0x0
dataLength = 4
numChildren = 1
一、建立一個Maven工程
二、添加pom文件
<dependencies>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>RELEASE</version>
</dependency>
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-core</artifactId>
<version>2.8.2</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.apache.zookeeper/zookeeper -->
<dependency>
<groupId>org.apache.zookeeper</groupId>
<artifactId>zookeeper</artifactId>
<version>3.4.10</version>
</dependency>
</dependencies>
三、拷貝log4j.properties文件到項目根目錄
須要在項目的src/main/resources目錄下,新建一個文件,命名爲「log4j.properties」,在文件中填入。
log4j.rootLogger=INFO, stdout
log4j.appender.stdout=org.apache.log4j.ConsoleAppender
log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
log4j.appender.stdout.layout.ConversionPattern=%d %p [%c] - %m%n
log4j.appender.logfile=org.apache.log4j.FileAppender
log4j.appender.logfile.File=target/spring.log
log4j.appender.logfile.layout=org.apache.log4j.PatternLayout
log4j.appender.logfile.layout.ConversionPattern=%d %p [%c] - %m%n
/**
* 建立ZooKeeper客戶端
* @throws IOException
*/
@Before
public void init() throws IOException {
zkClient = new ZooKeeper(connectString, sessionTimeout, new Watcher() {
public void process(WatchedEvent event) {
// 再次啓動監聽
try {
zkClient.getChildren("/", true);
} catch (Exception e) {
e.printStackTrace();
}
}
});
}
/**
* 建立子節點
* @throws Exception
*/
@Test
public void create() throws Exception {
// 參數1:要建立的節點的路徑; 參數2:節點數據 ; 參數3:節點權限 ;參數4:節點的類型
String nodeCreated = zkClient.create("/atguigu", "jinlian".getBytes(), Ids.OPEN_ACL_UNSAFE,CreateMode.PERSISTENT);
System.out.println(nodeCreated);
}
/**
* 獲取子節點並監聽節點變化
* @throws Exception
*/
@Test
public void getChildren() throws Exception {
List<String> children = zkClient.getChildren("/", true);
for (String child : children) {
System.out.println(child);
}
// 延時阻塞
Thread.sleep(Long.MAX_VALUE);
}
/**
* 判斷znode是否存在
* @throws Exception
*/
@Test
public void exist() throws Exception {
Stat stat = zkClient.exists("/eclipse", false);
System.out.println(stat == null ? "not exist" : "exist");
}
一、需求
某分佈式系統中,主節點能夠有多臺,能夠動態上下線,任意一臺客戶端都能實時感知到主節點服務器的上下線。
二、需求分析,以下圖所示
[zk: localhost:2181(CONNECTED) 10] create /servers "servers"
Created /servers
(1)服務器端向Zookeeper註冊代碼
package com.atguigu.zookeeper;
import java.io.IOException;
import org.apache.zookeeper.CreateMode;
import org.apache.zookeeper.KeeperException;
import org.apache.zookeeper.WatchedEvent;
import org.apache.zookeeper.Watcher;
import org.apache.zookeeper.ZooDefs.Ids;
import org.apache.zookeeper.ZooKeeper;
public class DistributeServer {
public static void main(String[] args) throws IOException, KeeperException, InterruptedException {
// 一、鏈接zookeeper集羣
DistributeServer server = new DistributeServer();
server.getConnect();
// 二、註冊服務器節點
server.registerServer(args[0]);
// 三、業務邏輯功能
server.business(args[0]);
}
private void business(String hostname) throws InterruptedException {
System.out.println(hostname + " is working ...");
Thread.sleep(Long.MAX_VALUE);
}
private String parentNode = "/servers";
private void registerServer(String hostname) throws KeeperException, InterruptedException {
String path = zkClient.create(parentNode + "/server", hostname.getBytes(), Ids.OPEN_ACL_UNSAFE, CreateMode.EPHEMERAL_SEQUENTIAL);
System.out.println(hostname + " is online " + path);
}
private String connectString = "hadoop102:2181,hadoop103:2181,hadoop104:2181";
private int sessionTimeout = 2000;
private ZooKeeper zkClient = null;
private void getConnect() throws IOException {
zkClient = new ZooKeeper(connectString, sessionTimeout, new Watcher() {
public void process(WatchedEvent event) {
}
});
}
}
(2)客戶端代碼
package com.atguigu.zookeeper;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import org.apache.zookeeper.KeeperException;
import org.apache.zookeeper.WatchedEvent;
import org.apache.zookeeper.Watcher;
import org.apache.zookeeper.ZooKeeper;
public class DistributeClient {
public static void main(String[] args) throws IOException, KeeperException, InterruptedException {
// 一、鏈接zookeeper集羣
DistributeClient client = new DistributeClient();
client.getConnect();
// 二、獲取子節點並監聽節點變化
client.getChildren();
// 三、業務邏輯功能
client.business();
}
private void business() throws InterruptedException {
System.out.println("client is working ...");
Thread.sleep(Long.MAX_VALUE);
}
private String parentNode = "/servers";
private void getChildren() throws KeeperException, InterruptedException {
// 一、獲取服務器子節點信息,而且對父節點進行監聽
List<String> children = zkClient.getChildren(parentNode , true);
// 二、存儲服務器信息列表
ArrayList<String> hosts = new ArrayList<String>();
// 三、遍歷全部節點,獲取節點中的主機名稱信息
for (String child : children) {
byte[] data = zkClient.getData(parentNode + "/" + child, false, null);
hosts.add(new String(data));
}
// 四、打印服務器列表信息
System.out.println(hosts);
}
private String connectString = "hadoop102:2181,hadoop103:2181,hadoop104:2181";
private int sessionTimeout = 2000;
private ZooKeeper zkClient = null;
private void getConnect() throws IOException {
zkClient = new ZooKeeper(connectString, sessionTimeout, new Watcher() {
public void process(WatchedEvent event) {
// 再次啓動監聽
try {
getChildren();
} catch (Exception e) {
e.printStackTrace();
}
}
});
}
}
詳見3.1。
詳見3.4。
(1)部署方式單機模式、集羣模式。
(2)角色:Leader和Follower。
(3)集羣最少須要機器數:3。
ls create get delete set……