Zookeeper實戰
1.常用的命令
命令基本語法 |
功能描述 |
help |
顯示所有操作命令 |
ls path [watch] |
使用 ls 命令來查看當前znode中所包含的內容 |
ls2 path [watch] |
查看當前節點數據並能看到更新次數等數據 |
create |
普通創建 -s 含有序列 -e 臨時(重啓或者超時消失) |
get path [watch] |
獲得節點的值 |
set |
設置節點的具體值 |
stat |
查看節點狀態 |
delete |
刪除節點 |
rmr |
遞歸刪除節點 |
啓動zk服務
bin/zkServer.sh start
啓動客戶端
bin/zkCli.sh
查看zk的運行狀態
bin/zkServer.sh status
help 查看客戶端幫助命令
help
查看當前znode中所包含的內容
ls /
查看當前節點詳細數據
ls2 /
get 獲取節點數據和更新信息
get內容爲空
cZxid :創建節點的id
ctime : 節點的創建時間
mZxid :修改節點的id
mtime :修改節點的時間
pZxid :子節點的id
cversion : 子節點的版本
dataVersion : 當前節點數據的版本
aclVersion :權限的版本
ephemeralOwner :判斷是否是臨時節點
dataLength : 數據的長度
numChildren :子節點的數量
stat 獲得節點的更新信息
stat path
create 創建節點
create [-s] [-e] path data acl 可以注意一下各個版本的變化
create -e 創建臨時節點
create -e path data
create -s 創建順序節點 自動累加
create -s path data
修改節點
set path data [version]
刪除節點
delete path [version]
遞歸刪除節點
rmr path
關於watcher機制大體的理解可以爲,當每個節點發生變化,都會觸發watcher事件,類似於mysql的觸發器。zk中 watcher是一次性的,觸發後立即銷燬。
節點的值變化監聽
stat path [watch] 設置watch事件
get path [watch]設置watch事件
節點的子節點變化監聽(路徑變化)
ls path watch
當路徑發生變化
2.集羣部署
部署前的準備工作
保證各個主機之間能夠正常通信,最好是在同一網段,開放要使用的端口或者關閉防火牆。
修改host文件,加入IP和主機名的映射。方法爲修改/etc/hosts和etc/hostname文件,不同的Linux發行版方法不一定一樣。
訪問官網下載Zookeeper安裝包,並解壓。
tar -xvzf zookeeper-3.4.10.tar.gz
創建數據目錄
執行以下命令創建數據目錄:
mkdir /usr/zookeeper/data
執行以下命令創建日誌目錄:
mkdir /usr/zookeeper/data/log
執行以下命令創建myid文件,並寫入ID:
echo 1 > /usr/zookeeper/data/myid
修改配置
執行以下命令編輯zoo.cfg文件:
cd zookeeper-3.4.10/conf/ && mv zoo_sample.cfg zoo.cfg && vi zoo.cfg
修改配置如下:
dataDir=/usr/zookeeper/data
dataLogDir=/usr/zookeeper/data/log
autopurge.snapRetainCount=3
autopurge.purgeInterval=1
在最後添加Zookeeper集羣各節點地址:
server.1=node1:2888:3888
server.2=node2:2888:3888
server.3=node3:2888:3888
配置參數解讀
server.A=B:C:D
A是一個數字,表示這個是第幾號服務器;
集羣模式下配置一個文件myid,這個文件在dataDir目錄下,這個文件裏面有一個數據就是A的值,Zookeeper啓動時讀取此文件,拿到裏面的數據與zoo.cfg裏面的配置信息比較從而判斷到底是哪個server。
B是這個服務器的ip地址;
C是這個服務器與集羣中的Leader服務器交換信息的端口;
D是萬一集羣中的Leader服務器掛了,需要一個端口來重新進行選舉,選出一個新的Leader,而這個端口就是用來執行選舉時服務器相互通信的端口。
拷貝配置文件到其他節點
scp -r zookeeper-3.4.10/ node2:/usr/
這裏需要注意的是,每個節點中的myid是不能相同的。
3.代碼中應用
創建maven工程,添加依賴
<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>
客戶端代碼
private static String connectString =
"host1:2181,host2:2181,host3:2181";
private static int sessionTimeout = 2000;
private ZooKeeper zkClient = null;
@Before
public void init() throws Exception {
zkClient = new ZooKeeper(connectString, sessionTimeout, new Watcher() {
@Override
public void process(WatchedEvent event) {
// 收到事件通知後的回調函數(用戶的業務邏輯)
System.out.println(event.getType() + "--" + event.getPath());
// 再次啓動監聽
try {
zkClient.getChildren("/", true);
} catch (Exception e) {
e.printStackTrace();
}
}
});
}
創建子節點
@Test
public void create() throws Exception {
// 參數1:要創建的節點的路徑; 參數2:節點數據 ; 參數3:節點權限 ;參數4:節點的類型
String nodeCreated = zkClient.create("/atguigu", "jinlian".getBytes(), Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT);
}
獲取子節點並監聽節點變化
@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是否存在
@Test
public void exist() throws Exception {
Stat stat = zkClient.exists("/eclipse", false);
System.out.println(stat == null ? "not exist" : "exist");
}
監聽服務器節點動態上下線案例
先在集羣上創建/servers節點 create /servers "servers"
服務器端向Zookeeper註冊代碼
public class DistributeServer {
private static String connectString = "host1:2181,host2:2181,host3:2181";
private static int sessionTimeout = 2000;
private ZooKeeper zk = null;
private String parentNode = "/servers";
// 創建到zk的客戶端連接
public void getConnect() throws IOException{
zk = new ZooKeeper(connectString, sessionTimeout, new Watcher() {
@Override
public void process(WatchedEvent event) {
}
});
}
// 註冊服務器
public void registServer(String hostname) throws Exception{
String create = zk.create(parentNode + "/server", hostname.getBytes(), Ids.OPEN_ACL_UNSAFE, CreateMode.EPHEMERAL_SEQUENTIAL);
System.out.println(hostname +" is online "+ create);
}
// 業務功能
public void business(String hostname) throws Exception{
System.out.println(hostname+" is working ...");
Thread.sleep(Long.MAX_VALUE);
}
public static void main(String[] args) throws Exception {
// 1獲取zk連接
DistributeServer server = new DistributeServer();
server.getConnect();
// 2 利用zk連接註冊服務器信息
server.registServer(args[0]);
// 3 啓動業務功能
server.business(args[0]);
}
}
客戶端代碼
public class DistributeClient {
private static String connectString = "host1:2181,host2:2181,host3:2181";
private static int sessionTimeout = 2000;
private ZooKeeper zk = null;
private String parentNode = "/servers";
// 創建到zk的客戶端連接
public void getConnect() throws IOException {
zk = new ZooKeeper(connectString, sessionTimeout, new Watcher() {
@Override
public void process(WatchedEvent event) {
// 再次啓動監聽
try {
getServerList();
} catch (Exception e) {
e.printStackTrace();
}
}
});
}
// 獲取服務器列表信息
public void getServerList() throws Exception {
// 1獲取服務器子節點信息,並且對父節點進行監聽
List<String> children = zk.getChildren(parentNode, true);
// 2存儲服務器信息列表
ArrayList<String> servers = new ArrayList<>();
// 3遍歷所有節點,獲取節點中的主機名稱信息
for (String child : children) {
byte[] data = zk.getData(parentNode + "/" + child, false, null);
servers.add(new String(data));
}
// 4打印服務器列表信息
System.out.println(servers);
}
// 業務功能
public void business() throws Exception{
System.out.println("client is working ...");
Thread.sleep(Long.MAX_VALUE);
}
public static void main(String[] args) throws Exception {
// 1獲取zk連接
DistributeClient client = new DistributeClient();
client.getConnect();
// 2獲取servers的子節點信息,從中獲取服務器信息列表
client.getServerList();
// 3業務進程啓動
client.business();
}
}