知識點:
1)zookeeper客戶端的使用
2)zoo.cfg裡面配置資訊的講解
3)zookeeper的一些常見概念模型
4)zookeeper java客戶端的使用
zoo.cfg配置檔案引數分析
tickTime= 2000 zookeeper最小時間單位長度(ms)
initLimit=10 結果是10tickTime follower節點啟動之後與leader節點完成資料同步的時間
syncLimit=5 5tickTime follower節點與leader節點進行心跳檢測的最大延遲時間
dataDir=/tmp/zookeeper 表示zookeeper伺服器儲存快照檔案的目錄
dataLogDir 表示配置zookeeper事務日誌的儲存日誌 預設指定在dataDir目錄下
clientport 表示客戶端和伺服器建立連線的埠號:2181【預設】
客戶端的操作
先進入客戶端 sh zkCli.sh
看看他有哪些命令
zookeeper中的一些概念 1)資料模型 zookeeper的資料模型和檔案系統類似,每一個節點稱為:znode 是zookeeper中的最小資料單元,每個znode上都可以儲存資料和掛載子節點,從而構成一個層次化的屬性結構。 持久化節點 :節點建立後會一直存在zookeeper伺服器上,直到主動給刪除持久化有序節點:每個節點都會為他的一級子節點維護一個順序
臨時節點:臨時節點的生命週期和客戶端的會話保持一致,當客戶端會話失效,該節點自動清理
臨時有序節點:臨時節點上多了一個順序性的特性
會話:四種狀態
NOT CONNECTED 未連線
CONNECTING 連線中
CONNECTED 已連線
CLOSED 關閉
watcher
zookeeper 提供了分散式資料釋出/訂閱 ,zookeeper允許客戶端向伺服器註冊一個watcher監聽,當伺服器端的節點觸發指定事件的時候會觸發watcher,服務端會向客戶端傳送一個事件通知
watcher的通知是一次性,一旦觸發一次通知後,該watcher就失效了。
ACL
zookeeper提供了控制節點訪問許可權的功能,用於有效保證zookeeper中資料的安全性,避免誤操作而導致系統出現重大事故。
create/read/write/delete/admin
zookeeper命令
根據上面的說話,zookeeper是基於類似於檔案系統的資料結構
我們先看下它的根
建立節點命令
1) create [-s] [-e] path data acl
-s 代表是否是有序的
-e 代表是否是臨時的
預設是持久化節點
path 代表路徑
data 代表資料
acl 代表許可權
create /lulf 123
我們再來看下這個節點下的是否有值
建立子節點必須要攜帶完整路徑2)get path [watch]
獲取指定path的資訊
3) set path data [version]
修改節點path對應的data
刪除指定節點
version表示鎖的概念【樂觀鎖】
資料庫中有個version欄位來控制資料行的版本好 stat資訊
節點的狀態資訊
cZxid = 0x100000006 節點被建立時的事務id
ctime = Mon Aug 27 17:05:03 CST 2018 節點被建立時的時間
mZxid = 0x10000000d 節點被最後一次修改的事務id
mtime = Mon Aug 27 18:58:20 CST 2018 節點被最後一次修改的時間
pZxid = 0x100000007 子節點被最後一次修改的事務id
cversion = 1 子節點的版本號
dataVersion = 1 資料版本號
aclVersion = 0 accesscontrol 節點修改許可權
ephemeralOwner = 0x0 建立臨時節點的時候,會有一個sessionid,該值儲存的就是這個id
dataLength = 3 資料長度
numChildren = 1 子節點數
java API的使用 1)匯入jar包
<dependency>
<groupId>org.apache.zookeeper</groupId>
<artifactId>zookeeper</artifactId>
<version>3.4.8</version>
</dependency>
複製程式碼
2)建立連線
package com.lulf.javaapi;
import java.io.IOException;
import java.util.concurrent.CountDownLatch;
import org.apache.zookeeper.WatchedEvent;
import org.apache.zookeeper.Watcher;
import org.apache.zookeeper.ZooKeeper;
public class CreateSessionDemo {
private final static String CONNECTSTRING = "192.168.48.128:2181,192.168.48.130:2181,"
+ "192.168.48.131:2181,192.168.48.132:2181";
private static CountDownLatch countDownLatch=new CountDownLatch(1);
public static void main(String[] args) throws IOException, InterruptedException {
ZooKeeper zooKeeper = new ZooKeeper(CONNECTSTRING, 5000, new Watcher() {
@Override
public void process(WatchedEvent watchedEvent) {
//如果當前連線狀態是連線成功的,通過計數器去控制
if(watchedEvent.getState()==Event.KeeperState.SyncConnected){
countDownLatch.countDown();
System.out.println(watchedEvent.getState());
}
}
});
countDownLatch.await();
System.out.println("test "+zooKeeper.getState());
}
}
複製程式碼
3)建立節點
package com.lulf.javaapi;
import java.io.IOException;
import java.util.List;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;
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;
import org.apache.zookeeper.ZooKeeper;
import org.apache.zookeeper.data.ACL;
import org.apache.zookeeper.data.Stat;
public class CreateNodeDemo implements Watcher {
private final static String CONNECTSTRING = "192.168.48.128:2181,192.168.48.130:2181,"
+ "192.168.48.131:2181,192.168.48.132:2181";
private static CountDownLatch countDownLatch = new CountDownLatch(1);
private static ZooKeeper zooKeeper = null;
private static Stat stat = new Stat();
public static void main(String[] args) throws IOException, InterruptedException, KeeperException {
zooKeeper = new ZooKeeper(CONNECTSTRING, 5000, new CreateNodeDemo());
countDownLatch.await();
System.out.println("test " + zooKeeper.getState());
// 建立節點
String path = "/FXP";
byte[] data = "1234".getBytes();
List<ACL> acl = ZooDefs.Ids.OPEN_ACL_UNSAFE;
CreateMode createMode = CreateMode.EPHEMERAL;
String result = zooKeeper.create(path, data, acl, createMode);
zooKeeper.getData(path, true, stat);// 增加一個watcher
System.out.println("建立成功 " + result);
// 修改資料 -1代表不用管他版本號
zooKeeper.setData(path, "311".getBytes(), -1);
//刪除節點
zooKeeper.delete(path, -1);
Thread.sleep(2000);
//建立節點和子節點【這邊要注意只有持久化節點才有子節點】
zooKeeper.create("/LULF", "123".getBytes(), ZooDefs.Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT);
TimeUnit.SECONDS.sleep(1);
zooKeeper.create("/LULF/lulf1-1", "123".getBytes(), ZooDefs.Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT);
TimeUnit.SECONDS.sleep(1);
}
@Override
public void process(WatchedEvent watchedEvent) {
// 如果當前連線狀態是連線成功的,通過計數器去控制
if (watchedEvent.getState() == Event.KeeperState.SyncConnected) {
if (Event.EventType.None == watchedEvent.getType() && null == watchedEvent.getType()) {
countDownLatch.countDown();
System.out.println(watchedEvent.getState());
} else if (watchedEvent.getType() == Event.EventType.NodeDataChanged) {
try {
System.out.println("路徑 " + watchedEvent.getPath() + "改變後的值 "
+ zooKeeper.getData(watchedEvent.getPath(), true, new Stat()));
} catch (KeeperException | InterruptedException e) {
e.printStackTrace();
}
} else if (watchedEvent.getType() == Event.EventType.NodeChildrenChanged) {
} else if (watchedEvent.getType() == Event.EventType.NodeCreated) {
try {
System.out.println("路徑 " + watchedEvent.getPath() + "節點的值 "
+ zooKeeper.getData(watchedEvent.getPath(), true, new Stat()));
} catch (KeeperException | InterruptedException e) {
e.printStackTrace();
}
} else if (watchedEvent.getType() == Event.EventType.NodeDeleted) {
System.out.println("刪除路徑 " + watchedEvent.getPath());
}
}
}
}
複製程式碼
許可權控制模式
schema:授權物件
ip : 192.168.48.131
digest : username password
world :開放式的許可權控制模式 訪問許可權對所有使用者開放 world:anyone
super :超級使用者 可以對zookeeper上的資料節點進行操作
連線狀態
1)keeperStat:expored
在一定的時間內客戶端沒有收到伺服器的通知,則認為當前的會話已經過期了,
2)disconnected 斷開連線狀態
3)keeperstat.syncConnected 客戶端和伺服器端在某個節點上建立連線,並且完成一次ersion,
zxid的同步
4)keeperstatus.authFailed 授權失敗
NodeCreated 當節點被建立時觸發
NodeChildrenChanged 標識子節點被建立,被刪除,子節點資料發生變化
NodeDataChanged 節點資料發生改變
NodeDeleted 節點被刪除
None 當客戶端和伺服器連線狀態發生變化的時候,事件型別就是None
zkclient
1)引入jar包
<dependency>
<groupId>com.101tec</groupId>
<artifactId>zkclient</artifactId>
<version>0.10</version>
</dependency>
複製程式碼
2)建立會話
它的watcher怎麼做呢?
curator
Curator本身是Netfilx公司開源的zookeeper客戶端
curator提供了各種應用場景的實現封裝
curator-framework 提供了fluent風格的api
curator-replice 提供了實現封裝
1)建立seesion
ExponentialBackoffRetry 衰減重試 減少系統負擔 間隔時間 充實次數
RetryNTimes 指定最大重試次數
ReteyOneTime 僅僅重試一次
RetryUnitilElapsed 一直重試知道規定的時間
3)非同步操作及事務處理 Collection transresult=curatorFramework.inTransaction().create().forPath("/trans", "111".getBytes()).and().setData() .forPath("/lll", "555".getBytes()).and().commit();
package com.lulf.curator;
import java.util.Collection;
import java.util.Collections;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import org.apache.curator.framework.CuratorFramework;
import org.apache.curator.framework.api.BackgroundCallback;
import org.apache.curator.framework.api.CuratorEvent;
import org.apache.curator.framework.api.transaction.CuratorTransactionResult;
import org.apache.zookeeper.CreateMode;
import org.apache.zookeeper.data.Stat;
public class CuratorOperationDemo {
public static void main(String[] args) throws Exception {
CuratorFramework curatorFramework = CuratorClientUtils.getInstance();
System.out.println("連線成功。。。。");
// 建立節點
curatorFramework.create().creatingParentsIfNeeded().withMode(CreateMode.PERSISTENT)
.forPath("/curator/curator1-1/curator1-1-1", "123445".getBytes());
// 刪除節點 預設情況下,version是-1
curatorFramework.delete().deletingChildrenIfNeeded().forPath("/curator");
// 獲取資料
Stat stat = new Stat();
byte[] bs = curatorFramework.getData().storingStatIn(stat).forPath("/curator");
String result = new String(bs);
// 更新
Stat stat1 = curatorFramework.setData().forPath("/curator", "312".getBytes());
// 非同步操作
ExecutorService service = Executors.newFixedThreadPool(1);
curatorFramework.create().creatingParentContainersIfNeeded().withMode(CreateMode.PERSISTENT)
.inBackground(new BackgroundCallback() {
@Override
public void processResult(CuratorFramework arg0, CuratorEvent arg1) throws Exception {
System.out.println(Thread.currentThread().getName() + "-->" + arg1.getResultCode());
}
}, service).forPath("/Allen", "allen".getBytes());
// 事務【curator獨有的】
Collection<CuratorTransactionResult> transresult=curatorFramework.inTransaction().create().forPath("/trans", "111".getBytes()).and().setData()
.forPath("/lll", "555".getBytes()).and().commit();
System.out.println("success");
}
}
複製程式碼
4)事件處理
package com.lulf.curator;
import java.util.concurrent.TimeUnit;
import org.apache.curator.framework.CuratorFramework;
import org.apache.curator.framework.recipes.cache.NodeCache;
import org.apache.curator.framework.recipes.cache.PathChildrenCache;
import org.apache.curator.framework.recipes.cache.PathChildrenCacheEvent;
import org.apache.zookeeper.CreateMode;
public class CuratorEventDemo {
public static void main(String[] args) throws Exception {
CuratorFramework curatorFramework = CuratorClientUtils.getInstance();
//System.out.println("連線成功。。。");
// curator事件處理
// 三種watcher來做節點監聽
// pathcache 監視一個路徑下子節點的建立,刪除節點,資料更新
// NodeCache 監視一個節點的建立,更新,刪除
// TreeCache pathcache和nodecache的結合(監視路徑下的建立更新和刪除事件),
// 快取路徑下所有子節點的資料
//node變化NodeCache
// NodeCache cache = new NodeCache(curatorFramework, "/lulf", false);
// cache.start(true);
// cache.getListenable()
// .addListener(() -> System.out.println("節點資料發生變化" + new String(cache.getCurrentData().getData())));
// curatorFramework.setData().forPath("/lulf", "gbcq".getBytes());
//pathcache
PathChildrenCache cache2=new PathChildrenCache(curatorFramework, "/event", false);
cache2.start(PathChildrenCache.StartMode.POST_INITIALIZED_EVENT);
cache2.getListenable().addListener((curatorFramework1,PathChildrenCacheEvent)->{
switch (PathChildrenCacheEvent.getType()) {
case CHILD_ADDED:
System.out.println("增加子節點");
break;
case CHILD_REMOVED:
System.out.println("刪除子節點");
break;
case CHILD_UPDATED:
System.out.println("更新子節點");
break;
default:
break;
}
});
curatorFramework.create().withMode(CreateMode.PERSISTENT).forPath("/event", "1".getBytes());
TimeUnit.SECONDS.sleep(1);
curatorFramework.create().withMode(CreateMode.EPHEMERAL).forPath("/event/event1", "1.1".getBytes());
TimeUnit.SECONDS.sleep(1);
curatorFramework.setData().forPath("/event/event1", "1.2".getBytes());
curatorFramework.delete().forPath("/event/event1");
System.in.read();
}
}
複製程式碼