大數據學習筆記之Zookeeper(四):Zookeeper實戰篇(二)

4.1 分佈式安裝部署

0)集羣規劃
在hadoop二、hadoop3和hadoop4三個節點上部署Zookeeper。
1)解壓安裝
(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/這個目錄下建立data/zkData
mkdir -p data/zkData
(3)重命名/opt/module/zookeeper-3.4.10/conf這個目錄下的zoo_sample.cfg爲zoo.cfg
mv zoo_sample.cfg zoo.cfg
2)配置zoo.cfg文件
(1)具體配置
dataDir=/opt/module/zookeeper-3.4.10/data/zkData
增長以下配置
#######################cluster##########################
server.2=hadoop102:2888:3888
server.3=hadoop103:2888:3888
server.4=hadoop104:2888:3888java

這裏配置了三個server節點,hadoop102 103 104 主機名,2888 leader和flower之間通訊的端口號,3888,leader掛掉了以後從新選舉leader,之間通訊的端口號。
(2)配置參數解讀
Server.A=B:C:D。
A是一個數字,表示這個是第幾號服務器;
B是這個服務器的ip地址;
C是這個服務器與集羣中的Leader服務器交換信息的端口;
D是萬一集羣中的Leader服務器掛了,須要一個端口來從新進行選舉,選出一個新的Leader,而這個端口就是用來執行選舉時服務器相互通訊的端口。node

集羣模式下配置一個文件myid,這個文件在dataDir目錄下,這個文件裏面有一個數據就是A的值,Zookeeper啓動時讀取此文件,拿到裏面的數據與zoo.cfg裏面的配置信息比較從而判斷究竟是哪一個server。linux

注意:每一個機器的myid是不同的,應該修改成本身對應的。
3)集羣操做
(1)在/opt/module/zookeeper-3.4.10/data/zkData目錄下建立一個myid的文件
touch myid
添加myid文件,注意必定要在linux裏面建立,在notepad++裏面極可能亂碼
(2)編輯myid文件
vi myid
在文件中添加與server對應的編號:如2
(3)拷貝配置好的zookeeper到其餘機器上
scp -r zookeeper-3.4.10/ root@hadoop3.atguigu.com:/opt/app/
scp -r zookeeper-3.4.10/ root@hadoop4.atguigu.com:/opt/app/
並分別修改myid文件中內容爲三、4
(4)分別啓動zookeeper
[root@hadoop2 zookeeper-3.4.10]# bin/zkServer.sh start
[root@hadoop3 zookeeper-3.4.10]# bin/zkServer.sh start
[root@hadoop4 zookeeper-3.4.10]# bin/zkServer.sh start
(5)查看狀態
[root@hadoop2 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
[root@hadoop3 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
[root@hadoop4 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: followerweb

4.2 客戶端命令行操做

命令基本語法 功能描述
help 顯示全部操做命令
ls path [watch] 使用 ls 命令來查看當前znode中所包含的內容
ls2 path [watch] 查看當前節點數據並能看到更新次數等數據
create 普通建立
-s 含有序列 -s 含有序列
-e 臨時(重啓或者超時消失) -e 臨時(重啓或者超時消失)
get path [watch] 得到節點的值
set 設置節點的具體值
stat 查看節點狀態
delete 刪除節點
rmr 遞歸刪除節點

1)啓動客戶端
[atguigu@hadoop103 zookeeper-3.4.10]$ bin/zkCli.sh
2)顯示全部操做命令
[zk: localhost:2181(CONNECTED) 1] help
3)查看當前znode中所包含的內容
[zk: localhost:2181(CONNECTED) 0] ls /
[zookeeper]
4)查看當前節點數據並能看到更新次數等數據(查看很是詳細的詳情)
[zk: localhost:2181(CONNECTED) 1] ls2 /
[zookeeper]
cZxid = 0x0 (事物建立的編號)
ctime = Thu Jan 01 08:00:00 CST 1970 (建立的時間)
mZxid = 0x0 (事物id)
mtime = Thu Jan 01 08:00:00 CST 1970 (節點最後的時間)
pZxid = 0x0
cversion = -1 (建立時候的版本)
dataVersion = 0 (子節點的版本)
aclVersion = 0(權限的版本)
ephemeralOwner = 0x0 (是不是短暫節點)
dataLength = 0(數據的長度)
numChildren = 1(子節點的個數)
5)建立普通節點
[zk: localhost:2181(CONNECTED) 2] create /app1 「hello app1」 (第一個參數,建立的目錄,第二個參數,建立時候的描述)
Created /app1
[zk: localhost:2181(CONNECTED) 4] create /app1/server101 「192.168.1.101」
Created /app1/server101
ls /
發現多了個剛纔建立的兩個目錄
6)得到節點的值
[zk: localhost:2181(CONNECTED) 6] get /app1
hello app1
cZxid = 0x20000000a
ctime = Mon Jul 17 16:08:35 CST 2017
mZxid = 0x20000000a
mtime = Mon Jul 17 16:08:35 CST 2017
pZxid = 0x20000000b
cversion = 1
dataVersion = 0
aclVersion = 0
ephemeralOwner = 0x0
dataLength = 10
numChildren = 1
[zk: localhost:2181(CONNECTED) 8] get /app1/server101
192.168.1.101
cZxid = 0x20000000b
ctime = Mon Jul 17 16:11:04 CST 2017
mZxid = 0x20000000b
mtime = Mon Jul 17 16:11:04 CST 2017
pZxid = 0x20000000b
cversion = 0
dataVersion = 0
aclVersion = 0
ephemeralOwner = 0x0
dataLength = 13
numChildren = 0
7)建立短暫節點
[zk: localhost:2181(CONNECTED) 9] create -e /app-emphemeral 8888
(1)在當前客戶端是能查看到的
[zk: localhost:2181(CONNECTED) 10] ls /
[app1, app-emphemeral, zookeeper]
(2)退出當前客戶端而後再重啓啓動客戶端
[zk: localhost:2181(CONNECTED) 12] quit
[atguigu@hadoop104 zookeeper-3.4.10]$ bin/zkCli.sh
(3)再次查看根目錄下短暫節點已經刪除
[zk: localhost:2181(CONNECTED) 0] ls /
[app1, zookeeper]
8)建立帶序號的節點
(1)先建立一個普通的根節點app2
[zk: localhost:2181(CONNECTED) 11] create /app2 「app2」
(2)建立帶序號的節點
[zk: localhost:2181(CONNECTED) 13] create -s /app2/aa 888
Created /app2/aa0000000000
[zk: localhost:2181(CONNECTED) 14] create -s /app2/bb 888
Created /app2/bb0000000001
[zk: localhost:2181(CONNECTED) 15] create -s /app2/cc 888
Created /app2/cc0000000002
若是原節點下有1個節點,則再排序時從1開始,以此類推。若是原來有兩個就從2開始
[zk: localhost:2181(CONNECTED) 16] create -s /app1/aa 888
Created /app1/aa0000000001
9)修改節點數據值
[zk: localhost:2181(CONNECTED) 2] set /app1 999
經過get /app1 查看值是否別修改
10)節點的值變化監聽
(1)在104主機上註冊監聽/app1節點數據變化
[zk: localhost:2181(CONNECTED) 26] get /app1 watch
(2)在103主機上修改/app1節點的數據
[zk: localhost:2181(CONNECTED) 5] set /app1 777
(3)觀察104主機收到數據變化的監聽
WATCHER::
WatchedEvent state:SyncConnected type:NodeDataChanged path:/app1
11)節點的子節點變化監聽(路徑變化)
(1)在104主機上註冊監聽/app1節點的子節點變化
[zk: localhost:2181(CONNECTED) 1] ls /app1 watch
[aa0000000001, server101]
或者get /app1 watch
(2)在103主機/app1節點上建立子節點
[zk: localhost:2181(CONNECTED) 6] create /app1/bb 666
Created /app1/bb
(3)觀察104主機收到子節點變化的監聽
WATCHER::
WatchedEvent state:SyncConnected type:NodeChildrenChanged path:/app1
意思就是別人修改了數據,我作出了監聽,而且監聽到了變化,數據發生了變化。
可是注意,這裏的監聽事件只能監聽一次,即若是103再次修改這個目錄,可是104監聽不到了。
固然除了監聽子節點的變化,也能夠監聽節點中數據的變化,即「」中的內容,即get /app1 獲得的內容
12)刪除節點(單一節點)
[zk: localhost:2181(CONNECTED) 4] delete /app1/bb
13)遞歸刪除節點
[zk: localhost:2181(CONNECTED) 7] rmr /app2
14)查看節點狀態
[zk: localhost:2181(CONNECTED) 12] stat /app1
cZxid = 0x20000000a
ctime = Mon Jul 17 16:08:35 CST 2017
mZxid = 0x200000018
mtime = Mon Jul 17 16:54:38 CST 2017
pZxid = 0x20000001c
cversion = 4
dataVersion = 2
aclVersion = 0
ephemeralOwner = 0x0
dataLength = 3
numChildren = 2apache

注意啓動的時候經過jps,發現多了QuorumPeerMain不足以說明已經啓動,必須經過bin/zkServersh status 查看時候有mode:leader或者mode:follower,才能說明已經正常啓動。若是配置信息錯誤的話,前者是沒問題的可是後面查看status是錯誤的api

4.3 API應用

4.3.1 eclipse環境搭建

1)建立一個工程
2)解壓zookeeper-3.4.10.tar.gz文件
3)拷貝zookeeper-3.4.10.jar、jline-0.9.94.jar、log4j-1.2.16.jar、netty-3.10.5.Final.jar、slf4j-api-1.6.1.jar、slf4j-log4j12-1.6.1.jar到工程的lib目錄。並build一下,導入工程。
4)拷貝log4j.properties文件到項目根目錄
在這裏插入圖片描述服務器

4.3.2 建立ZooKeeper客戶端:

//鏈接zookeeper的地址
private static String connectString = "hadoop102:2181,hadoop103:2181,hadoop104:2181";
//會話超時時間單位毫秒
	private static int sessionTimeout = 2000;
	private ZooKeeper zkClient = null;

	@Before
	public void init() throws Exception {
//watcher監聽事件
	zkClient = new ZooKeeper(connectString, sessionTimeout, new Watcher() {
			@Override
			public void process(WatchedEvent event) {
				// 收到事件通知後的回調函數(用戶的業務邏輯)
				System.out.println(event.getType() + "--" + event.getPath());

				// 再次啓動監聽
				//由於每次都會從新調用init方法
				//若是沒有下面這幾行的話,只能監聽一次,就像以前介紹的linux指令同樣
				try {
					zkClient.getChildren("/", true);
				} catch (Exception e) {
					e.printStackTrace();
				}
			}
		});
	}

4.3.3 建立子節點

// 建立子節點
	@Test
	public void create() throws Exception {
		// 數據的增刪改查
		// 參數1:要建立的節點的路徑; 參數2:節點數據 ; 參數3:節點權限 ;參數4:節點的類型
		String nodeCreated = zkClient.create("/eclipse", "hello zk".getBytes(), Ids.OPEN_ACL_UNSAFE,CreateMode.PERSISTENT);
	}

若是中斷輸出 None–null 而後輸出/atguigu
這裏的None–null是上面的System.out.println(event.getType() + 「–」 + event.getPath());監聽輸出的。session

4.3.4 獲取子節點

// 獲取子節點
	@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);
	}

4.3.5 判斷znode是否存在

// 判斷znode是否存在
	@Test
	public void exist() throws Exception {
		Stat stat = zkClient.exists("/eclipse", false);

		System.out.println(stat == null ? "not exist" : "exist");
	}

4.3.6 監聽服務器節點動態上下線案例

1)需求:某分佈式系統中,主節點能夠有多臺,能夠動態上下線,任意一臺客戶端都能實時感知到主節點服務器的上下線
2)需求分析
在這裏插入圖片描述
上圖能夠理解成淘寶雙十一,第一步,服務端像zookeeper集羣註冊信息,就是去上面建立一個節點,servers是管理全部節點的最外層的信息,/severs/server1是路徑,hadoop101 80 nodes是數據,hadoop101是代號,80nodes表示當前服務器鏈接了多少客戶端,第二步,客戶端獲取剛纔的信息,查看有幾個server,根據拿到的數據,根據地址能夠請求相應的服務器,第三步,服務器下線,下線以後zookeeper集羣上的對應的節點信息就沒了,第四部,下線的時間通知給客戶端,第五步,從新獲取服務器列表
3)具體實現:
(0)如今集羣上建立/servers節點
[zk: localhost:2181(CONNECTED) 10] create /servers 「servers」
Created /servers
(1)服務器端代碼app

package com.atguigu.zkcase;

import java.io.IOException;
import org.apache.zookeeper.CreateMode;
import org.apache.zookeeper.WatchedEvent;
import org.apache.zookeeper.Watcher;
import org.apache.zookeeper.ZooKeeper;
import org.apache.zookeeper.ZooDefs.Ids;

public class DistributeServer {
	private static String connectString = "hadoop102:2181,hadoop103:2181,hadoop104:2181";
	private static int sessionTimeout = 2000;
	private ZooKeeper zk = null;
	private String parentNode = "/servers";
	
	// 建立到zk的客戶端鏈接
	//這裏注意概念,不管是server,仍是client對於zk來講都是client
	public void getConnect() throws IOException{
		
		zk = new ZooKeeper(connectString, sessionTimeout, new Watcher() {

			@Override
			public void process(WatchedEvent event) {
				// 收到事件通知後的回調函數(用戶的業務邏輯)
				System.out.println(event.getType() + "--" + event.getPath());

				// 再次啓動監聽
				try {
					zk.getChildren("/", true);
				} catch (Exception e) {
					e.printStackTrace();
				}
			}
		});
	}
	
	// 註冊服務器
	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 noline "+ 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 {
		// 獲取zk鏈接
		DistributeServer server = new DistributeServer();
		server.getConnect();
		
		// 利用zk鏈接註冊服務器信息
		server.registServer(args[0]);
		
		// 啓動業務功能
		server.business(args[0]);
	}
}

(2)客戶端代碼eclipse

package com.atguigu.zkcase;

import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import org.apache.zookeeper.WatchedEvent;
import org.apache.zookeeper.Watcher;
import org.apache.zookeeper.ZooKeeper;

public class DistributeClient {
	private static String connectString = "hadoop102:2181,hadoop103:2181,hadoop104:2181";
	private static int sessionTimeout = 2000;
	private ZooKeeper zk = null;
	private String parentNode = "/servers";
	private volatile ArrayList<String> serversList = new ArrayList<>();

	// 建立到zk的客戶端鏈接
	public void getConnect() throws IOException {
		zk = new ZooKeeper(connectString, sessionTimeout, new Watcher() {

			@Override
			public void process(WatchedEvent event) {
				System.out.print(event.getType()+"--"+event.getPath());
				// 再次啓動監聽
				try {
					//保證能循環監聽。
					getServerList();

				} catch (Exception e) {
					e.printStackTrace();
				}
			}
		});
	}

	//
	public void getServerList() throws Exception {
		
		// 獲取服務器子節點信息,而且對父節點進行監聽
		//true表示會執行上面的process這個監聽的方法
		List<String> children = zk.getChildren(parentNode, true);
		ArrayList<String> servers = new ArrayList<>();
		//獲取全部子節點信息
		for (String child : children) {
			byte[] data = zk.getData(parentNode + "/" + child, false, null);

			servers.add(new String(data));
		}

		// 把servers賦值給成員serverList,已提供給各業務線程使用
		serversList = servers;

		System.out.println(serversList);
	}

	// 業務功能
	public void business() throws Exception {
		System.out.println("client is working ...");
	}

	public static void main(String[] args) throws Exception {

		// 獲取zk鏈接
		DistributeClient client = new DistributeClient();
		client.getConnect();

		// 獲取servers的子節點信息,從中獲取服務器信息列表
		client.getServerList();

		// 業務進程啓動
		client.business();
	}
}

在這裏插入圖片描述
在這裏插入圖片描述
在這裏插入圖片描述 server端作相應的處理,客戶端都能感知到。

相關文章
相關標籤/搜索