Java操作Zookeeper原理及過程詳解
ZooKeeper 是一個(gè)典型的分布式數(shù)據(jù)一致性解決方案,分布式應(yīng)用程序可以基于 ZooKeeper 實(shí)現(xiàn)諸如數(shù)據(jù)發(fā)布/訂閱、負(fù)載均衡、命名服務(wù)、分布式協(xié)調(diào)/通知、集群管理、Master 選舉、分布式鎖和分布式隊(duì)列等功能。
Zookeeper 一個(gè)最常用的使用場(chǎng)景就是用于擔(dān)任服務(wù)生產(chǎn)者和服務(wù)消費(fèi)者的注冊(cè)中心。 服務(wù)生產(chǎn)者將自己提供的服務(wù)注冊(cè)到Zookeeper中心,服務(wù)的消費(fèi)者在進(jìn)行服務(wù)調(diào)用的時(shí)候先到Zookeeper中查找服務(wù),獲取到服務(wù)生產(chǎn)者的詳細(xì)信息之后,再去調(diào)用服務(wù)生產(chǎn)者的內(nèi)容與數(shù)據(jù)。如下圖所示,在 Dubbo架構(gòu)中 Zookeeper 就擔(dān)任了注冊(cè)中心這一角色。
maven依賴
<dependency> <groupId>org.apache.zookeeper</groupId> <artifactId>zookeeper</artifactId> <version>3.6.0</version></dependency>
程序其它依賴:
<!-- Logger(log4j2) --><dependency> <groupId>org.apache.logging.log4j</groupId> <artifactId>log4j-core</artifactId> <version>2.11.2</version></dependency><!-- Log4j 1.x API Bridge --><dependency> <groupId>org.apache.logging.log4j</groupId> <artifactId>log4j-1.2-api</artifactId> <version>2.11.2</version></dependency><!-- SLF4J Bridge --><dependency> <groupId>org.apache.logging.log4j</groupId> <artifactId>log4j-slf4j-impl</artifactId> <version>2.11.2</version></dependency><dependency> <groupId>org.apache.zookeeper</groupId> <artifactId>zookeeper</artifactId> <version>3.6.0</version> <exclusions> <exclusion> <groupId>org.slf4j</groupId> <artifactId>slf4j-log4j12</artifactId> </exclusion> </exclusions></dependency>
API操作代碼:
package com.zhi.test;import java.util.List;import org.apache.logging.log4j.LogManager;import org.apache.logging.log4j.Logger;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.data.Stat;import org.junit.jupiter.api.AfterAll;import org.junit.jupiter.api.BeforeAll;import org.junit.jupiter.api.MethodOrderer;import org.junit.jupiter.api.Order;import org.junit.jupiter.api.Test;import org.junit.jupiter.api.TestInstance;import org.junit.jupiter.api.TestInstance.Lifecycle;import org.junit.jupiter.api.TestMethodOrder;/** * Zookeeper操作測(cè)試 * * @author 張遠(yuǎn)志 * @since 2020年5月3日14:31:28 * */@TestInstance(Lifecycle.PER_CLASS)@TestMethodOrder(MethodOrderer.OrderAnnotation.class)public class ZookeeperTest { private final Logger logger = LogManager.getLogger(this.getClass()); private ZooKeeper zooKeeper; private final String path = '/test'; @BeforeAll public void init() throws Exception { zooKeeper = new ZooKeeper('192.168.59.131:2181', 60000, new Watcher() { public void process(WatchedEvent event) {logger.info('事件類型:{},路徑:{}', event.getType(), event.getPath()); } }); } /** * 添加數(shù)據(jù),當(dāng)路徑已經(jīng)存在時(shí)會(huì)報(bào)錯(cuò),初始版本號(hào)為0。第三個(gè)參數(shù)是權(quán)限控制。 <br> * 第四個(gè)參數(shù),CreateMode: * <li>PERSISTENT:持久化保存 * <li>PERSISTENT_SEQUENTIAL:持久化保存,并且路徑附加一個(gè)自動(dòng)增長(zhǎng)的序號(hào) * <li>EPHEMERAL:臨時(shí)數(shù)據(jù),客戶端斷開連接時(shí)自動(dòng)刪除數(shù)據(jù)(dubbo就是采用這種機(jī)制) * <li>EPHEMERAL_SEQUENTIAL:客戶端斷開連接時(shí)自動(dòng)刪除數(shù)據(jù),并且路徑會(huì)附加一個(gè)自動(dòng)增長(zhǎng)的序號(hào) * <li>CONTAINER: * <li>PERSISTENT_WITH_TTL:客戶端斷開連接時(shí)自動(dòng)刪除數(shù)據(jù),當(dāng)節(jié)點(diǎn)在指定時(shí)間沒有被修改且沒有子目錄時(shí),數(shù)據(jù)會(huì)被刪除 * <li>PERSISTENT_SEQUENTIAL_WITH_TTL:客戶端斷開連接時(shí)自動(dòng)刪除數(shù)據(jù),路徑會(huì)附加一個(gè)自動(dòng)增長(zhǎng)的序號(hào),且當(dāng)節(jié)點(diǎn)在指定時(shí)間沒有被修改且沒有子目錄時(shí),數(shù)據(jù)會(huì)被刪除 */ @Order(1) @Test public void create() { try { String back = zooKeeper.create(path, '這是一個(gè)測(cè)試'.getBytes(), Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT); logger.info('添加一條數(shù)據(jù)成功,實(shí)際路徑:{}', back); } catch (Exception e) { logger.error('調(diào)用create出錯(cuò)', e); } } /** * 判斷路徑是否存在,不存在時(shí)返回null */ @Order(2) @Test public void exists() { try { Stat stat = zooKeeper.exists(path, false); logger.info('路徑為{}的節(jié)點(diǎn){}存在', path, stat == null ? '不' : ''); } catch (Exception e) { logger.error('調(diào)用exists出錯(cuò)', e); } } /** * 查詢數(shù)據(jù),路徑不存在時(shí)會(huì)報(bào)錯(cuò) */ @Order(3) @Test public void find() { try { byte[] bits = zooKeeper.getData(path, false, new Stat()); // 路徑不存在時(shí)會(huì)報(bào)錯(cuò) String data = new String(bits); logger.info('路徑{}查詢到數(shù)據(jù):{}', path, data); } catch (Exception e) { logger.error('調(diào)用getData出錯(cuò)', e); } } /** * 獲取子目錄,結(jié)果為空時(shí)返回一個(gè)長(zhǎng)度為0的ArrayList */ @Order(3) @Test public void children() { try { List<String> list = zooKeeper.getChildren(path, false); logger.info('路徑{}的子目錄有:{}', path, String.join('、', list.toArray(new String[0]))); } catch (Exception e) { logger.error('調(diào)用getChildren出錯(cuò)', e); } } /** * 修改數(shù)據(jù),路徑不存在時(shí)會(huì)報(bào)錯(cuò),版本號(hào)與存儲(chǔ)中不一致時(shí)也報(bào)錯(cuò) */ @Order(4) @Test public void udpate() { try { Stat stat = zooKeeper.exists(path, false); if (stat != null) {stat = zooKeeper.setData(path, '這是一個(gè)修改測(cè)試'.getBytes(), stat.getVersion()); // 版本號(hào)為-1時(shí)不做版本校驗(yàn)logger.info('數(shù)據(jù)修改成功,原版本號(hào):{},新版本號(hào):{}', stat.getAversion(), stat.getVersion()); } } catch (Exception e) { logger.error('調(diào)用setData出錯(cuò)', e); } } /** * 刪除節(jié)點(diǎn),路徑不存在時(shí)報(bào)錯(cuò),版本號(hào)不一致時(shí)也會(huì)報(bào)錯(cuò) */ @Order(5) @Test public void delete() { try { zooKeeper.delete(path, -1); // -1表示不做版本校驗(yàn) logger.info('根據(jù)path刪除數(shù)據(jù)成功'); } catch (Exception e) { logger.error('調(diào)用delete出錯(cuò)', e); } } @AfterAll public void destory() throws Exception { if (zooKeeper != null) { zooKeeper.close(); } }}
以上就是本文的全部?jī)?nèi)容,希望對(duì)大家的學(xué)習(xí)有所幫助,也希望大家多多支持好吧啦網(wǎng)。
相關(guān)文章:
1. 使用python tkinter開發(fā)一個(gè)爬取B站直播彈幕工具的實(shí)現(xiàn)代碼2. Python 用NumPy創(chuàng)建二維數(shù)組的案例3. ThinkPHP6使用JWT+中間件實(shí)現(xiàn)Token驗(yàn)證實(shí)例詳解4. Python使用oslo.vmware管理ESXI虛擬機(jī)的示例參考5. 解決Python中報(bào)錯(cuò)TypeError: must be str, not bytes問題6. 不使用XMLHttpRequest對(duì)象實(shí)現(xiàn)Ajax效果的方法小結(jié)7. python安裝sklearn模塊的方法詳解8. Python如何解決secure_filename對(duì)中文不支持問題9. Python類成員繼承重寫的實(shí)現(xiàn)10. ASP基礎(chǔ)入門第二篇(ASP基礎(chǔ)知識(shí))
