Zookeeper框架curator
Curator是Netflix公司開源的一套zookeeper客戶端框架,以原生API爲基礎進行了包裝,解決了很多Zookeeper客戶端非常底層的細節開發工作,包括連接重連、反覆註冊Watcher和NodeExistsException異常等等,實現了Fluent風格的API接口
-
curator的特點
先說說zookeeper原生API存在的不便性,連接對象的異步創建,需要開發自行編碼創建等待,連接沒有自動連接超時機制,watcher一次註冊生效一次
在此基礎上,curator解決了session會話的超時重連,watcher的反覆註冊,Fluent風格的簡化了開發的API,並且也提供了分佈式鎖服務,共享計數器,緩存機制等等
-
curator pom.xml
<!-- 對zookeeper的底層api的一些封裝 -->
<dependency>
<groupId>org.apache.curator</groupId>
<artifactId>curator-framework</artifactId>
<version>4.0.1</version>
</dependency>
<!-- 封裝了一些高級特性,如:Cache事件監聽、選舉、分佈式鎖、分佈式Barrier -->
<dependency>
<groupId>org.apache.curator</groupId>
<artifactId>curator-recipes</artifactId>
<version>4.0.1</version>
</dependency>
- 連接zookeeper
/**
* @Author: zxx
* @Date: 2020/4/6 10:32
* @Description:
* 連接的重試策略四種:
* 1,每三秒重連一次,只會重連一次
* RetryPolicy retryPolicy = new RetryOneTime(3000);
* 2, 每三秒重連一次,重連三次
* RetryPolicy retryPolicy = new RetryNTimes(3,3000);
* 3,每三秒重連一次,總等待時間超過十秒後停止重連
* RetryPolicy retryPolicy = RetryUntilElapsed(10000,3000);
* 4,隨着重連次數的增加會隨着重連時間增加
* this.baseSleepTimeMs * Math.max(1, this.random.nextInt(1 << retryCount + 1));
* RetryPolicy retryPolicy = new ExponentialBackoffRetry(1000,3);
*
*/
public class ZKconnect {
public static void main(String[] args) {
String zkIP = "192.168.21.141:2181";
RetryPolicy retryPolicy = new ExponentialBackoffRetry(1000,3);
CuratorFramework client = CuratorFrameworkFactory.builder()
.connectString(zkIP)
//會話超時時間
.sessionTimeoutMs(10000)
//重連機制
.retryPolicy(retryPolicy)
//命名空間
.namespace("create")
.build();
client.start();
System.out.println(client.isStarted());
client.close();
}
}
- 新增節點
/**
* @Author: zxx
* @Date: 2020/4/6 11:12
* @Description: 新增節點
*/
public class ZKCuratorCreate {
String zkIP = "192.168.21.141:2181";
CuratorFramework client;
@Before
public void before(){
RetryPolicy retryPolicy = new ExponentialBackoffRetry(1000,3);
client = CuratorFrameworkFactory.builder()
.connectString(zkIP)
//會話超時時間
.sessionTimeoutMs(10000)
//重連機制
.retryPolicy(retryPolicy)
//命名空間
.namespace("create")
.build();
client.start();
}
public void after(){
client.close();
}
@Test
public void test1() throws Exception {
byte[] data = "node1".getBytes();
client.create()
//節點類型
// CreateMode:
// PERSISTENT(0, false, false),
// PERSISTENT_SEQUENTIAL(2, false, true),
// EPHEMERAL(1, true, false),
// EPHEMERAL_SEQUENTIAL(3, true, true);
.withMode(CreateMode.EPHEMERAL)
//節點的權限列表 world:anyone:cdrwa
.withACL(ZooDefs.Ids.OPEN_ACL_UNSAFE)
.forPath("/node",data);
System.out.println("結束");
}
// 異步方式創建節點
public void test2() throws Exception {
client.create()
// 遞歸節點的創建
.creatingParentsIfNeeded()
.withMode(CreateMode.PERSISTENT)
.withACL(ZooDefs.Ids.OPEN_ACL_UNSAFE)
// 異步回調接口
.inBackground(new BackgroundCallback() {
public void processResult(CuratorFramework curatorFramework, CuratorEvent curatorEvent) throws Exception {
// 節點的路徑
System.out.println(curatorEvent.getPath());
// 時間類型
System.out.println(curatorEvent.getType());
}
})
.forPath("/node4","node4".getBytes());
Thread.sleep(5000);
System.out.println("結束");
}
}
- 刪除節點
@Test
public void delete1() throws Exception {
// 刪除節點
client.delete()
// 節點的路徑
.forPath("/node1");
System.out.println("結束");
}
@Test
public void delete2() throws Exception {
client.delete()
// 版本號
.withVersion(0)
.forPath("/node1");
System.out.println("結束");
}
@Test
public void delete3() throws Exception {
//刪除包含字節點的節點
client.delete()
.deletingChildrenIfNeeded()
.withVersion(-1)
.forPath("/node1");
System.out.println("結束");
}
@Test
public void delete4() throws Exception {
// 異步方式刪除節點
client.delete()
.deletingChildrenIfNeeded()
.withVersion(-1)
.inBackground(new BackgroundCallback() {
public void processResult(CuratorFramework curatorFramework, CuratorEvent curatorEvent) throws Exception {
// 節點路徑
System.out.println(curatorEvent.getPath());
// 事件類型
System.out.println(curatorEvent.getType());
}
})
.forPath("/node1");
Thread.sleep(5000);
System.out.println("結束");
}
- 更新節點
@Test
public void set1() throws Exception {
// 更新節點
client.setData()
// arg1:節點的路徑
// arg2:節點的數據
.forPath("/node1", "node11".getBytes());
System.out.println("結束");
}
@Test
public void set2() throws Exception {
client.setData()
// 指定版本號
.withVersion(2)
.forPath("/node1", "node1111".getBytes());
System.out.println("結束");
}
@Test
public void set3() throws Exception {
// 異步方式修改節點數據
client.setData()
.withVersion(-1)
.inBackground(new BackgroundCallback() {
public void processResult(CuratorFramework curatorFramework, CuratorEvent curatorEvent) throws Exception {
// 節點的路徑
System.out.println(curatorEvent.getPath());
// 事件的類型
System.out.println(curatorEvent.getType());
}
}).forPath("/node1", "node1".getBytes());
Thread.sleep(5000);
System.out.println("結束");
}
- 查看節點
@Test
public void get1() throws Exception {
// 讀取節點數據
byte [] bys=client.getData()
// 節點的路徑
.forPath("/node1");
System.out.println(new String(bys));
}
@Test
public void get2() throws Exception {
// 讀取數據時讀取節點的屬性
Stat stat=new Stat();
byte [] bys=client.getData()
// 讀取屬性
.storingStatIn(stat)
.forPath("/node1");
System.out.println(new String(bys));
System.out.println(stat.getVersion());
}
@Test
public void get3() throws Exception {
// 異步方式讀取節點的數據
client.getData()
.inBackground(new BackgroundCallback() {
public void processResult(CuratorFramework curatorFramework, CuratorEvent curatorEvent) throws Exception {
// 節點的路徑
System.out.println(curatorEvent.getPath());
// 事件類型
System.out.println(curatorEvent.getType());
// 數據
System.out.println(new String(curatorEvent.getData()));
}
})
.forPath("/node1");
Thread.sleep(5000);
System.out.println("結束");
}
- 查看子幾點
@Test
public void getChild1() throws Exception {
// 讀取子節點數據
List<String> list = client.getChildren()
// 節點路徑
.forPath("/get");
for (String str : list) {
System.out.println(str);
}
}
@Test
public void getChild2() throws Exception {
// 異步方式讀取子節點數據
client.getChildren()
.inBackground(new BackgroundCallback() {
public void processResult(CuratorFramework curatorFramework, CuratorEvent curatorEvent) throws Exception {
// 節點路徑
System.out.println(curatorEvent.getPath());
// 事件類型
System.out.println(curatorEvent.getType());
// 讀取子節點數據
List<String> list=curatorEvent.getChildren();
for (String str : list) {
System.out.println(str);
}
}
})
.forPath("/get");
Thread.sleep(5000);
System.out.println("結束");
}
- 檢查節點是否存在
@Test
public void exists1() throws Exception {
// 判斷節點是否存在
Stat stat= client.checkExists()
// 節點路徑
.forPath("/node2");
System.out.println(stat.getVersion());
}
@Test
public void exists2() throws Exception {
// 異步方式判斷節點是否存在
client.checkExists()
.inBackground(new BackgroundCallback() {
public void processResult(CuratorFramework curatorFramework, CuratorEvent curatorEvent) throws Exception {
// 節點路徑
System.out.println(curatorEvent.getPath());
// 事件類型
System.out.println(curatorEvent.getType());
System.out.println(curatorEvent.getStat().getVersion());
}
})
.forPath("/node2");
Thread.sleep(5000);
System.out.println("結束");
}
-
watcher
curator 提供了兩種watcher來監聽節點的變化
- NodeCache:只是監聽某一種特定的節點,監聽節點的新增和修改
- PathChildrenCache:監控一個znode的子節點,當一個子節點刪除,更新,刪除時,Path Cache 會改變它的狀態,會包含最新的子節點,子節點的數據和狀態
@Test
public void watcher1() throws Exception {
// 監視某個節點的數據變化
// arg1:連接對象
// arg2:監視的節點路徑
//watcher是可以使用多次的
final NodeCache nodeCache=new NodeCache(client,"/watcher1");
// 啓動監視器對象
nodeCache.start();
nodeCache.getListenable().addListener(new NodeCacheListener() {
// 節點變化時回調的方法
public void nodeChanged() throws Exception {
System.out.println(nodeCache.getCurrentData().getPath());
System.out.println(new String(nodeCache.getCurrentData().getData()));
}
});
Thread.sleep(100000);
System.out.println("結束");
//關閉監視器對象
nodeCache.close();
}
@Test
public void watcher2() throws Exception {
// 監視子節點的變化
// arg1:連接對象
// arg2:監視的節點路徑
// arg3:事件中是否可以獲取節點的數據
PathChildrenCache pathChildrenCache=new PathChildrenCache(client,"/watcher1",true);
// 啓動監聽
pathChildrenCache.start();
pathChildrenCache.getListenable().addListener(new PathChildrenCacheListener() {
// 當子節點方法變化時回調的方法
public void childEvent(CuratorFramework curatorFramework, PathChildrenCacheEvent pathChildrenCacheEvent) throws Exception {
// 節點的事件類型
System.out.println(pathChildrenCacheEvent.getType());
// 節點的路徑
System.out.println(pathChildrenCacheEvent.getData().getPath());
// 節點數據
System.out.println(new String(pathChildrenCacheEvent.getData().getData()));
}
});
Thread.sleep(100000);
System.out.println("結束");
// 關閉監聽
pathChildrenCache.close();
}
- 事務
@Test
public void tra1() throws Exception {
// 開啓事務
client.inTransaction()
.create().forPath("/node1","node1".getBytes())
.and()
.create().forPath("/node2","node2".getBytes())
.and()
//事務提交
.commit();
}
- curator實現分佈式鎖
- InterProcessMutex: 分佈式可重入排他鎖
- InterProcessReadWriteLock:分佈式讀寫鎖
@Test
public void lock1() throws Exception {
// 排他鎖
// arg1:連接對象
// arg2:節點路徑
InterProcessLock interProcessLock = new InterProcessMutex(client, "/lock1");
System.out.println("等待獲取鎖對象!");
// 獲取鎖
interProcessLock.acquire();
for (int i = 1; i <= 10; i++) {
Thread.sleep(3000);
System.out.println(i);
}
// 釋放鎖
interProcessLock.release();
System.out.println("等待釋放鎖!");
}
//讀鎖
@Test
public void lock2() throws Exception {
// 讀寫鎖
InterProcessReadWriteLock interProcessReadWriteLock=new InterProcessReadWriteLock(client, "/lock1");
// 獲取讀鎖對象
InterProcessLock interProcessLock=interProcessReadWriteLock.readLock();
System.out.println("等待獲取鎖對象!");
// 獲取鎖
interProcessLock.acquire();
for (int i = 1; i <= 10; i++) {
Thread.sleep(3000);
System.out.println(i);
}
// 釋放鎖
interProcessLock.release();
System.out.println("等待釋放鎖!");
}
//寫鎖
@Test
public void lock3() throws Exception {
// 讀寫鎖
InterProcessReadWriteLock interProcessReadWriteLock=new InterProcessReadWriteLock(client, "/lock1");
// 獲取寫鎖對象
InterProcessLock interProcessLock=interProcessReadWriteLock.writeLock();
System.out.println("等待獲取鎖對象!");
// 獲取鎖
interProcessLock.acquire();
for (int i = 1; i <= 10; i++) {
Thread.sleep(3000);
System.out.println(i);
}
// 釋放鎖
interProcessLock.release();
System.out.println("等待釋放鎖!");
}