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
命令基本語法 | 功能描述 |
---|---|
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
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文件到項目根目錄
服務器
//鏈接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(); } } }); }
// 建立子節點 @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
// 獲取子節點 @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"); }
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端作相應的處理,客戶端都能感知到。