大資料技術之_06_Zookeeper學習_Zookeeper入門+Zookeeper安裝+Zookeeper內部原理+Zookeeper實戰(...

第2章 Zookeeper安裝
2.1 本地模式安裝部署
1、安裝前準備
(1)安裝jdk
(2)拷貝Zookeeper安裝包到Linux系統下
(3)解壓到指定目錄
[atguigu@hadoop102 software]$ tar -zxvf zookeeper-3.4.10.tar.gz -C /opt/module/
2、配置修改
(1)將/opt/module/zookeeper-3.4.10/conf/這個路徑下的zoo_sample.cfg修改為zoo.cfg;
[atguigu@hadoop102 conf]$ pwd /opt/module/zookeeper-3.4.10/conf [atguigu@hadoop102 conf]$ mv zoo_sample.cfg zoo.cfg
(2)開啟zoo.cfg檔案,修改dataDir路徑:
[atguigu@hadoop102 zookeeper-3.4.10]$ vim zoo.cfg
修改如下內容:
dataDir=/opt/module/zookeeper-3.4.10/zkData
(3)在/opt/module/zookeeper-3.4.10/這個目錄上建立zkData資料夾
[atguigu@hadoop102 zookeeper-3.4.10]$ mkdir zkData
3、操作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
2.2 配置引數解讀
Zookeeper中的配置檔案zoo.cfg中引數含義解讀如下:
- 1、tickTime=2000:通訊心跳數,Zookeeper伺服器與客戶端心跳時間,單位毫秒。
Zookeeper使用的基本時間,伺服器之間或客戶端與伺服器之間維持心跳的時間間隔,也就是每個tickTime時間就會發送一個心跳,時間單位為毫秒。
它用於心跳機制
,並且設定最小的session超時時間為兩倍心跳時間。(session的最小超時時間是2*tickTime) - 2、initLimit=10:LF初始通訊時限
叢集中的Follower跟隨者伺服器
與Leader領導者伺服器
之間初始連線時能容忍的最多心跳數(tickTime的數量),用它來限定叢集中的Zookeeper伺服器連線到Leader的時限。 - 3、syncLimit=5:LF同步通訊時限
叢集中Leader與Follower之間的最大響應時間單位,假如響應超過syncLimit * tickTime,Leader認為Follwer死掉,從伺服器列表中刪除Follwer。 - 4、dataDir:資料檔案目錄+資料持久化路徑
主要用於儲存Zookeeper中的資料。 - 5、clientPort=2181:客戶端連線埠
監聽客戶端連線的埠。
第3章 Zookeeper內部原理
3.1 選舉機制(面試重點)
-
1)半數機制:叢集中半數以上機器存活,叢集可用。所以Zookeeper適合安裝奇數臺伺服器。
-
2)Zookeeper雖然在配置檔案中並沒有指定Master和Slave。但是,Zookeeper工作時,是有一個節點為Leader,其他則為Follower,Leader是通過
內部的選舉機制
臨時產生的。 -
3)以一個簡單的例子來說明整個選舉的過程。
假設有五臺伺服器組成的Zookeeper叢集,它們的id從1-5,同時它們都是最新啟動的,也就是沒有歷史資料,在存放資料量這一點上,都是一樣的。假設這些伺服器依序啟動,來看看會發生什麼,如下圖所示。
-
(1)伺服器1啟動,此時只有它一臺伺服器啟動了,它發出去的報文沒有任何響應,所以它的選舉狀態一直是LOOKING狀態。
-
(2)伺服器2啟動,它與最開始啟動的伺服器1進行通訊,互相交換自己的選舉結果,由於兩者都沒有歷史資料,所以id值較大的伺服器2勝出,但是由於沒有達到超過半數以上的伺服器都同意選舉它(這個例子中的半數以上是3),所以伺服器1、2還是繼續保持LOOKING狀態。
-
(3)伺服器3啟動,根據前面的理論分析,伺服器3成為伺服器1、2、3中的老大,而與上面不同的是,此時有三臺伺服器選舉了它,所以它成為了這次選舉的Leader。
-
(4)伺服器4啟動,根據前面的分析,理論上伺服器4應該是伺服器1、2、3、4中最大的,但是由於前面已經有半數以上的伺服器選舉了伺服器3,所以它只能接收當小弟的命了。
(5)伺服器5啟動,同4一樣當小弟。
3.2 節點型別

3.3 stat結構體

- 1)cZxid - 建立節點的事務zxid
每次修改ZooKeeper狀態都會收到一個zxid形式的時間戳,也就是ZooKeeper事務ID。
事務ID是ZooKeeper中所有修改總的次序。每個修改都有唯一的zxid,如果zxid1小於zxid2,那麼zxid1在zxid2之前發生。 - 2)ctime - znode被建立的毫秒數(從1970年開始)
- 3)mZxid - znode最後更新的事務zxid
- 4)mtime - znode最後修改的毫秒數(從1970年開始)
- 5)pZxid - znode最後更新的子節點zxid
- 6)cversion - znode子節點變化號,znode子節點修改次數
- 7)dataVersion - znode資料變化號
- 8)aclVersion - znode訪問控制列表的變化號
- 9)ephemeralOwner - 如果是臨時節點,這個是znode擁有者的session id。如果不是臨時節點則是0。
-
10)dataLength - znode的資料長度
-
11)numChildren - znode子節點數量
3.4 監聽器原理(面試重點)

3.5 寫資料流程

第4章 Zookeeper實戰(開發重點)
4.1 分散式安裝部署
1、叢集規劃
在hadoop102、hadoop103和hadoop104三個節點上部署Zookeeper。
2、解壓安裝
(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/目錄內容到hadoop103、hadoop104
[atguigu@hadoop102 module]$ xsync zookeeper-3.4.10/
3、配置伺服器編號
(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對應的編號:
(4)拷貝配置好的zookeeper到其他機器上
[atguigu@hadoop102 zkData]$ xsync myid
並分別在hadoop102、hadoop103上修改myid檔案中內容為3、4
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,而這個埠就是用來 執行選舉時
伺服器相互通訊的埠。
4、叢集操作
(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
4.2 客戶端命令列操作
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 mtime = Thu Jan 01 08:00:00 CST 1970 pZxid = 0x0 cversion = -1 dataVersion = 0 aclVersion = 0 ephemeralOwner = 0x0 dataLength = 0 numChildren = 1
5、分別建立2個普通節點
[zk: localhost:2181(CONNECTED) 3] create /sanguo "zhuge" Created /sanguo [zk: localhost:2181(CONNECTED) 4] create /sanguo/shuguo "liubei" Created /sanguo/shuguo
6、獲得節點的值
[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
7、建立短暫節點
[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]
8、建立帶序號的節點
(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開始,以此類推。
9、修改節點資料值
[zk: localhost:2181(CONNECTED) 6] set /sanguo/weiguo "simayi"
10、節點的值變化監聽
(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
注意:該註冊監聽一次,那麼就只生效一次。下次需要重新註冊。
11、節點的子節點變化監聽(路徑變化)
(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
注意:該註冊監聽一次,那麼就只生效一次。下次需要重新註冊。
12、刪除節點
[zk: localhost:2181(CONNECTED) 4] delete /sanguo/jin
13、遞迴刪除節點
[zk: localhost:2181(CONNECTED) 15] rmr /sanguo/shuguo
14、檢視節點狀態
[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
4.3 API應用
4.3.1 Eclipse環境搭建
1、建立一個Maven工程
2、新增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>
3、拷貝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
4.3.2 建立ZooKeeper客戶端
/** * 建立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(); } } }); }
4.3.3 建立子節點
/** * 建立子節點 * @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); }
4.3.4 獲取子節點並監聽節點變化
/** * 獲取子節點並監聽節點變化 * @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); }
4.3.5 判斷Znode是否存在
/** * 判斷znode是否存在 * @throws Exception */ @Test public void exist() throws Exception { Stat stat = zkClient.exists("/eclipse", false); System.out.println(stat == null ? "not exist" : "exist"); }
4.4 監聽伺服器節點動態上下線案例
1、需求
某分散式系統中,主節點可以有多臺,可以動態上下線,任意一臺客戶端都能實時感知到主節點伺服器的上下線。
2、需求分析,如下圖所示

3、具體實現
(0)先在叢集上建立/servers節點
[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 { // 1、連線zookeeper叢集 DistributeServer server = new DistributeServer(); server.getConnect(); // 2、註冊伺服器節點 server.registerServer(args[0]); // 3、業務邏輯功能 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 { // 1、連線zookeeper叢集 DistributeClient client = new DistributeClient(); client.getConnect(); // 2、獲取子節點並監聽節點變化 client.getChildren(); // 3、業務邏輯功能 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 { // 1、獲取伺服器子節點資訊,並且對父節點進行監聽 List<String> children = zkClient.getChildren(parentNode , true); // 2、儲存伺服器資訊列表 ArrayList<String> hosts = new ArrayList<String>(); // 3、遍歷所有節點,獲取節點中的主機名稱資訊 for (String child : children) { byte[] data = zkClient.getData(parentNode + "/" + child, false, null); hosts.add(new String(data)); } // 4、列印伺服器列表資訊 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(); } } }); } }
第5章 企業面試真題
5.1 請簡述ZooKeeper的選舉機制(半數機制)
詳見3.1。
5.2 ZooKeeper的監聽原理是什麼?
詳見3.4。
5.3 ZooKeeper的部署方式有哪幾種?叢集中的角色有哪些?叢集最少需要幾臺機器?
(1)部署方式單機模式、叢集模式。
(2)角色:Leader和Follower。
(3)叢集最少需要機器數:3。
5.4 ZooKeeper的常用命令
ls
create
get
delete
set
……