(一)zookeeper單機模式的安裝和使用
阿新 • • 發佈:2018-12-13
1、分散式常見問題
- 容易出現死鎖
- 容易活鎖,處於活鎖的執行緒都是非阻塞的,而且每個執行緒都搶不到資源,會造成cpu的耗費
- 叢集的管理問題,比如某臺的宕機需要能夠檢測到
- 叢集配置檔案的統一管理問題
- 叢集中資訊更新通知問題,某一臺機器釋出一個資訊,能夠讓整個叢集的機器都知道
- 管理叢集的選舉問題,管理叢集的機器本身也是一個叢集(例如zookeeper叢集),其中有一臺為主(選舉得到),其他為從。
- 分散式鎖
2、Zookeeper定義
Zookeeper是一個分散式的協調服務框架,Zookeeper可以解決分散式環境常見的問題:統一命名服務,資訊配置管理,資料一致性,叢集管理,分散式鎖等等。
3、Zookeeper的安裝
- 下載壓縮包:連結:https://pan.baidu.com/s/1NtffnJ0ttT475KSQqAKcSw 提取碼:0qp5
- 解壓:tar -xf zookeeper-3.4.7.tar.gz
- 建立配置檔案:zookeeper的配置檔案是conf/zoo.cfg,conf目錄下有一個配置檔案的樣本zoo_sample.cfg,複製該檔案並修改檔名為zoo.cfg即可
- 更改配置檔案內容:單機模式配置如下,其中dataDir為儲存快照的目錄,建議修改為自定義目錄
# The number of milliseconds of each tick tickTime=2000 # The number of ticks that the initial # synchronization phase can take initLimit=10 # The number of ticks that can pass between # sending a request and getting an acknowledgement syncLimit=5 # the directory where the snapshot is stored. # do not use /tmp for storage, /tmp here is just # example sakes. dataDir=/opt/zookeeper/tmp # the port at which the clients will connect clientPort=2181 # the maximum number of client connections. # increase this if you need to handle more clients #maxClientCnxns=60 # # Be sure to read the maintenance section of the # administrator guide before turning on autopurge. # # http://zookeeper.apache.org/doc/current/zookeeperAdmin.html#sc_maintenance # # The number of snapshots to retain in dataDir #autopurge.snapRetainCount=3 # Purge task interval in hours # Set to "0" to disable auto purge feature #autopurge.purgeInterval=1
4、zookeeper的資料結構
Zookeeper儲存資料的結構是一棵樹,如圖所示:
Zookeeper資料結構的特徵:
- 有一個根節點 /,對於Zookeeper的操作都要基於根節點
- 每個節點都叫做Znode節點,都可以建立自己的子節點,都可以儲存資料
- 整個Znode樹會儲存在記憶體中,提高查詢速度。為了防止資料丟失,同時也會把Znode樹落到磁碟上,磁碟路徑即配置檔案zoo.cfg裡dataDir指定的目錄
- Znode的路徑是全域性唯一的
- 建立節點時,需指定初始化資料,否則建立報錯
- Zookeeper是事務的概念,針對每個事務(建立,更新或刪除節點等),Zookeeper都會分配一個遞增的Zxid(事務id)。其中有cZxid(建立節點的事務id),mZxid(修改節點的事務id)
5、Zookeeper單機模式啟動,檢視,關閉
- 進入bin目錄,啟動zookeeper:sh zkServer.sh start
- 驗證是否啟動:jps命令檢視活動的java程序
- 檢視狀態:sh zkServer.sh status
- 停止服務:sh zkServer.sh stop
6、Zookeeper客戶端啟動及操作
小技巧:在客戶端中,使用命令:ctrl + l 清屏。
- 進入bin目錄,啟動客戶端:sh zkCli.sh
- 查詢節點 ls / ls /zookeeper
- 建立節點:create /node01 hello
建立了節點 node01,並初始化資料為 “hello”
- 檢視節點:get /node01
可以看出,當執行命令 create /node01 hello時,這就是一個寫的事務,會分配一個事務id,事務id是一個自增的id。
- 修改節點資料:set /node01 hellodfr
- 刪除節點:delete /node01 單個刪除,存在子節點則刪除失敗 rmr /node01 遞迴刪除,
7、zookeeper的節點型別
- create /park01 "dateStr" 普通持久節點
- create -e /park01 "dateStr" 普通臨時節點
- create -s /park01 "dateStr" 順序持久節點
- create -e -s /park01 "dateStr" 臨時順序節點
臨時節點 |
客戶端連線zookeeper服務並建立臨時節點後,若客戶端掉線,則臨時節點會消失。 該特性可以用來檢測叢集中,有哪些機器掛掉 |
順序節點 |
建立順序節點後,會在節點名稱後帶上一個自增的順序id 如建立節點 create -s /park01 ddff,真正建立的節點名稱為 park010000000009 |
8、通過程式碼操作zookeeper
- 下載Zookeeper相關jar包:連結:https://pan.baidu.com/s/1ZlEBsshFOr_us44JpMGUpA 提取碼:5v0x
- 建立Maven的java工程,pom.xml配置如下
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.dfr</groupId>
<artifactId>zookeeper</artifactId>
<version>0.0.1-SNAPSHOT</version>
<dependencies>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.10</version>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-simple</artifactId>
<version>1.6.4</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>org.apache.zookeeper</groupId>
<artifactId>zookeeper</artifactId>
<version>3.4.7</version>
</dependency>
</dependencies>
<build>
</build>
</project>
- jar包簡單瞭解:工程建立成功後,可以看到依賴的jar包
netty是一個網路通訊的框架,底層是基於NIO來寫的,zookeeper就是通過netty來與其他機器進行網路互動的。
- Zookeeper的連線,和基本操作
package com.dfr.zookeeper;
import java.util.List;
import java.util.concurrent.CountDownLatch;
import org.apache.zookeeper.CreateMode;
import org.apache.zookeeper.WatchedEvent;
import org.apache.zookeeper.Watcher;
import org.apache.zookeeper.ZooDefs.Ids;
import org.apache.zookeeper.ZooKeeper;
import org.apache.zookeeper.Watcher.Event.KeeperState;
import org.junit.Test;
public class TestDemo {
@Test
public void testConnect() throws Exception {
//連線操作是非同步的(非阻塞連線),如果不做任何處理,可能導致還沒連線成功,testConnect方法執行緒就已經關閉了。
//這裡使用遞減鎖來處理
final CountDownLatch cdl = new CountDownLatch(1);
//ip埠,連線超時時間,監聽者
ZooKeeper zk = new ZooKeeper("39.107.244.148:2181", 3000, new Watcher() {
@Override
public void process(WatchedEvent event) {
if(event.getState() == KeeperState.SyncConnected) {
System.out.println("連線成功!");
cdl.countDown();
}
}
});
//遞減鎖沒減到0則阻塞
cdl.await();
//建立節點
//引數:節點,儲存資料,許可權,節點型別
zk.create("/gtt", "MsGao".getBytes(), Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT);
//修改節點資料
//引數:節點,儲存資料,資料版本號
//每更新一次,dataVersion + 1
zk.setData("/gtt", "gttTWO".getBytes(), 0);
//如果不需要確認當前資料版本,則傳入版本號為-1
zk.setData("/gtt", "gtt0000".getBytes(), -1);
//刪除資料
//版本號傳-1,則直接刪除節點
zk.delete("/gtt", -1);
//獲取資料
//引數:節點,監聽者,節點的狀態資訊如時間戳等
byte[] byteDate = zk.getData("/dfr", null, null);
System.out.println(new String(byteDate));
//獲取子節點
//引數:節點,監聽者
List<String> list = zk.getChildren("/", null);
for(String str : list) {
System.out.println(str);
}
}
}
- 對節點進行事件監聽
事件型別
程式碼示例如下,注意zookeeper中監聽預設是一次性的。要想永久監聽需要自己處理。
package com.dfr.zookeeper;
import java.util.concurrent.CountDownLatch;
import org.apache.zookeeper.WatchedEvent;
import org.apache.zookeeper.Watcher;
import org.apache.zookeeper.ZooKeeper;
import org.apache.zookeeper.Watcher.Event.EventType;
import org.apache.zookeeper.Watcher.Event.KeeperState;
import org.junit.Test;
public class TestDemo2 {
@Test
public void test() throws Exception {
//連線操作是非同步的(非阻塞連線),如果不做任何處理,可能導致還沒連線成功,testConnect方法執行緒就已經關閉了。
//這裡使用遞減鎖來處理
final CountDownLatch cdl = new CountDownLatch(1);
//ip埠,連線超時時間,監聽者
ZooKeeper zk = new ZooKeeper("39.107.244.148:2181", 3000, new Watcher() {
@Override
public void process(WatchedEvent event) {
if(event.getState() == KeeperState.SyncConnected) {
System.out.println("連線成功!");
cdl.countDown();
}
}
});
//對節點進行事件監聽,此處以getData方法為例,可以自行選擇監聽事件型別
//zk的預設監聽機制是:一次性監聽
/*zk.getData("/dfr", new Watcher() {
@Override
public void process(WatchedEvent event) {
if(event.getType() == EventType.NodeDataChanged) {
System.out.println("節點資料改變了!");
}
}
}, null);
while(true);
*/
//永久監聽
//監聽事件的型別從EventType中選擇
for(;;) {
final CountDownLatch countdl = new CountDownLatch(1);
zk.getData("/dfr", new Watcher() {
@Override
public void process(WatchedEvent event) {
if(event.getType() == EventType.NodeDeleted) {
System.out.println("節點資料刪除了!");
countdl.countDown();
}
}
}, null);
countdl.await();
}
}
}