zookeeper之Curator
文章目录
- Curator客户端
- 创建会话
- 创建节点
- 获取节点和数据
- 更新数据
- 删除节点
- 事务
- 节点存在
- 事件监听
- 其他工具类
- 开发测试
Curator客户端
Curator
包含了几个包:curator-framework
:对zookeeper的底层api的一些封装curator-client
:提供一些客户端的操作,例如重试策略等curator-recipes
:封装了一些高级特性,如:Cache事件监听、选举、分布式锁、分布式计数器、分布式Barrier等
- 版本
- The are currently two released versions of Curator, 2.x.x and 3.x.x:
- Curator 2.x.x - compatible with both ZooKeeper 3.4.x and ZooKeeper 3.5.x
- Curator 3.x.x - compatible only with ZooKeeper 3.5.x and includes support for new features such as dynamic reconfiguration, etc.
Curator
主要解决了以下问题- 封装
ZooKeeper client
与ZooKeeper server
之间的连接处理 - 提供了一套
Fluent
风格的操作API - 提供
ZooKeeper
各种应用场景(recipe, 比如共享锁服务, 集群领导选举机制)的抽象封装
- 封装
- 这里使用的版本
- 服务端
Zookeeper
版本:3.4.6
Curator
版本:compile "org.apache.curator:curator-recipes:2.11.0"
- 服务端
创建会话
创建会话
@Testpublic void testCreateClient() throws Exception{String connectString = "zk-master:2180,zk-slave1:2182,zk-slave2:2183";int sessionTimeoutMs = 25000;int connectionTimeoutMs = 5000;/*** 失去连接重试策略* baseSleepTimeMs 初始sleep时间* maxRetries 最大重试次数* maxSleepMs 最大sleep时间* 当前sleep时间=baseSleepTimeMs*Math.mac(1,random.next(1)) << (retryCount+1)*/int baseSleepTimeMs;int maxRetries;int maxSleepMs;RetryPolicy retryPolicy = new ExponentialBackoffRetry(1000, 3);//第一种方式,使用Builder fluent风格的API方式创建CuratorFramework curatorFramework1 = CuratorFrameworkFactory.builder().connectString(connectString).sessionTimeoutMs(sessionTimeoutMs).connectionTimeoutMs(connectionTimeoutMs).retryPolicy(retryPolicy).build();CuratorFrameworkState state1 = curatorFramework1.getState();//zk-curator - LATENTlogger.info(state1.toString());//当连接状态变化时触发curatorFramework1.getConnectionStateListenable().addListener(new ConnectionStateListener() {@Overridepublic void stateChanged(CuratorFramework curatorFramework, ConnectionState connectionState) {//连接状态事件:truelogger.info("连接状态事件:{}",connectionState.isConnected());}});//完成会话的创建curatorFramework1.start();//第二种方式,使用静态工厂方式创建,此方式本质上还是通过第一种方式创建CuratorFramework curatorFramework2 =CuratorFrameworkFactory.newClient(connectString,sessionTimeoutMs,connectionTimeoutMs,retryPolicy);CuratorFrameworkState state2 = curatorFramework2.getState();//zk-curator - LATENTlogger.info(state2.toString());/*** 临时客户端:* 一定时间不活动后连接会被关闭,使用buildTemp()创建*/CuratorTempFramework curatorFramewor3 = CuratorFrameworkFactory.builder().connectString(connectString).sessionTimeoutMs(sessionTimeoutMs).connectionTimeoutMs(connectionTimeoutMs).retryPolicy(retryPolicy).buildTemp(2000,TimeUnit.SECONDS);//.buildTemp();TimeUnit.SECONDS.sleep(20);}
创建节点
创建节点
@Testpublic void testCreateZnode() throws Exception {String connectString = "zk-master:2180,zk-slave1:2182,zk-slave2:2183";int sessionTimeoutMs = 25000;int connectionTimeoutMs = 5000;String rootPath = "jannal-create";RetryPolicy retryPolicy = new ExponentialBackoffRetry(4000, 3);CuratorFramework curatorFramework = CuratorFrameworkFactory.builder().connectString(connectString).sessionTimeoutMs(sessionTimeoutMs).connectionTimeoutMs(connectionTimeoutMs).retryPolicy(retryPolicy).namespace(rootPath) //客户端对zk上的数据节点的操作都是基本此根节点进行的.build();//完成会话创建curatorFramework.start();//创建一个初始内容为空的znode,默认创建的是持久节点curatorFramework.create().forPath("/userEmpty");//创建一个附带内容的znodecuratorFramework.create().forPath("/userData", "我是jannal".getBytes(Charsets.UTF_8));//创建一个临时节点curatorFramework.create().withMode(CreateMode.EPHEMERAL).forPath("/userTemp", "jannal".getBytes(Charsets.UTF_8));//自动递归创建父节点creatingParentsIfNeeded()curatorFramework.create().creatingParentsIfNeeded().withMode(CreateMode.PERSISTENT).forPath("/user/password", "123456".getBytes(Charsets.UTF_8));curatorFramework.getCuratorListenable().addListener(new CuratorListener() {@Overridepublic void eventReceived(CuratorFramework curatorFramework, CuratorEvent curatorEvent) throws Exception {}});ExecutorService executorService = Executors.newFixedThreadPool(2);CountDownLatch countDownLatch = new CountDownLatch(1);/*** 在原生的zookeeper客户端中,所有异步通知事件处理都是通过EventThread这个* 线程处理的(串行处理所有事件的通知)。一旦发生复杂的处理单元就会消耗很长事件* 从而影响其他事件的处理,Curator可以使用线程池来处理,如果不指定线程池* 则默认使用EventThread来处理*/curatorFramework.create().creatingParentsIfNeeded().withMode(CreateMode.EPHEMERAL).inBackground(new BackgroundCallback() {@Overridepublic void processResult(CuratorFramework client, CuratorEvent event) throws Exception {logger.info(event.toString());countDownLatch.countDown();}},executorService).forPath("/user2","jannal2".getBytes(Charsets.UTF_8));countDownLatch.await();executorService.shutdown();}
获取节点和数据
获取节点和数据
@Testpublic void testGetZnode() throws Exception {String connectString = "zk-master:2180,zk-slave1:2182,zk-slave2:2183";int sessionTimeoutMs = 25000;int connectionTimeoutMs = 5000;String rootPath = "jannal-get";RetryPolicy retryPolicy = new ExponentialBackoffRetry(4000, 3);CuratorFramework client = CuratorFrameworkFactory.builder().connectString(connectString).sessionTimeoutMs(sessionTimeoutMs).connectionTimeoutMs(connectionTimeoutMs).retryPolicy(retryPolicy).namespace(rootPath).build();client.start();client.create().creatingParentsIfNeeded().forPath("/user/username/jannal", "jannal123".getBytes(Charsets.UTF_8));//获取数据byte[] bytes = client.getData().forPath("/user/username/jannal");Assert.assertEquals("jannal123", new String(bytes, Charsets.UTF_8));//读取一个节点的数据内容,同时获取到该节点的statStat stat = new Stat();bytes = client.getData().storingStatIn(stat).forPath("/user/username/jannal");logger.info(ToStringBuilder.reflectionToString(stat));client.create().creatingParentsIfNeeded().forPath("/user/username1", "abc".getBytes(Charsets.UTF_8));client.create().creatingParentsIfNeeded().forPath("/user/username2", "def".getBytes(Charsets.UTF_8));//获取节点的子节点路径List<String> strings = client.getChildren().forPath("/user");//[username2, username1, username]logger.info(strings.toString());}
更新数据
更新数据
@Testpublic void testSetZnode() throws Exception {String connectString = "zk-master:2180,zk-slave1:2182,zk-slave2:2183";int sessionTimeoutMs = 25000;int connectionTimeoutMs = 5000;String rootPath = "jannal-update";RetryPolicy retryPolicy = new ExponentialBackoffRetry(4000, 3);CuratorFramework curatorFramework = CuratorFrameworkFactory.builder().connectString(connectString).sessionTimeoutMs(sessionTimeoutMs).connectionTimeoutMs(connectionTimeoutMs).retryPolicy(retryPolicy).namespace(rootPath) //客户端对zk上的数据节点的操作都是基本此根节点进行的.build();curatorFramework.start();String path = "/user/password";curatorFramework.create().creatingParentsIfNeeded().withMode(CreateMode.PERSISTENT).forPath("/user/password", "123456".getBytes(Charsets.UTF_8));byte[] bytes = curatorFramework.getData().forPath(path);Assert.assertEquals("123456", new String(bytes, Charsets.UTF_8));Stat stat = curatorFramework.setData().forPath(path, "abcd".getBytes(Charsets.UTF_8));bytes = curatorFramework.getData().forPath(path);Assert.assertEquals("abcd", new String(bytes, Charsets.UTF_8));//更新一个节点的数据内容,强制指定版本进行更新curatorFramework.setData().withVersion(stat.getVersion()).forPath(path, "abcde".getBytes());}
删除节点
在删除一个节点时,由于网络原因,导致删除操作失败。这个异常在有些场景下是致命的,比如
Master
选举(先创建后删除),针对这个问题Curator
引入了一种重试机制,即如果我们调用了guaranteed()
,那么只要客户端有效,就会在后台反复重试,直到节点删除成功。删除节点示例
@Testpublic void testDeleteZnode() throws Exception {String connectString = "zk-master:2180,zk-slave1:2182,zk-slave2:2183";int sessionTimeoutMs = 25000;int connectionTimeoutMs = 5000;String rootPath = "jannal-delete";RetryPolicy retryPolicy = new ExponentialBackoffRetry(4000, 3);CuratorFramework client = CuratorFrameworkFactory.builder().connectString(connectString).sessionTimeoutMs(sessionTimeoutMs).connectionTimeoutMs(connectionTimeoutMs).retryPolicy(retryPolicy).namespace(rootPath).build();client.start();client.create().creatingParentsIfNeeded().forPath("/user/username/jannal", "jannal123".getBytes(Charsets.UTF_8));client.create().creatingParentsIfNeeded().forPath("/user2/username/jannal", "jannal123".getBytes(Charsets.UTF_8));client.create().creatingParentsIfNeeded().forPath("/user3/username/jannal", "jannal123".getBytes(Charsets.UTF_8));//删除节点且递归删除其所有的子节点client.delete().deletingChildrenIfNeeded().forPath("/user");//强制指定版本进行删除client.delete().deletingChildrenIfNeeded().withVersion(0).forPath("/user2");//强制保证删除,只要客户端有效,Curator会在后台持续进行删除操作,直到节点删除成功client.delete().guaranteed().forPath("/user3/username/jannal");}
事务
事务
/*** inTransaction()开启事务,可以复合create, setData, check, and/or delete* 等操作然后调用commit()作为一个原子操作提交** @throws Exception*/@Testpublic void testTransaction() throws Exception {String connectString = "zk-master:2180,zk-slave1:2182,zk-slave2:2183";int sessionTimeoutMs = 25000;int connectionTimeoutMs = 5000;String rootPath = "jannal-transaction";RetryPolicy retryPolicy = new ExponentialBackoffRetry(4000, 3);CuratorFramework client = CuratorFrameworkFactory.builder().connectString(connectString).sessionTimeoutMs(sessionTimeoutMs).connectionTimeoutMs(connectionTimeoutMs).retryPolicy(retryPolicy).namespace(rootPath).build();client.start();client.inTransaction().create().withMode(CreateMode.EPHEMERAL).forPath("/transaction", "事务".getBytes(Charsets.UTF_8)).and().delete().forPath("/transaction").and().commit();}
节点存在
判断节点是否存在
@Testpublic void testExist() throws Exception {String connectString = "zk-master:2180,zk-slave1:2182,zk-slave2:2183";int sessionTimeoutMs = 25000;int connectionTimeoutMs = 5000;String rootPath = "jannal-Exist";RetryPolicy retryPolicy = new ExponentialBackoffRetry(4000, 3);CuratorFramework client = CuratorFrameworkFactory.builder().connectString(connectString).sessionTimeoutMs(sessionTimeoutMs).connectionTimeoutMs(connectionTimeoutMs).retryPolicy(retryPolicy).namespace(rootPath).build();client.start();//节点不存在返回nullStat stat = client.checkExists().forPath("/jannal");Assert.assertEquals(null, stat);logger.info(ToStringBuilder.reflectionToString(stat));}
事件监听
原生客户端支持通过注册Watch来进行事件监听,但是收到事件通知后每次都需要手动再次注册Watch。
Curator
引入了Cache来实现对Zookeeper
服务端事件的监听,并且自动处理反复注册监听,简化了原生API的繁琐。Cache
分为两类监听- 节点监听
- 子节点监听
NodeCache
用于监听指定Zookeeper
数据节点本身的变化,数据内容发生变化时,就会回调此方法。@Testpublic void testNodeCacheEventListener() throws Exception {String connectString = "zk-master:2180,zk-slave1:2182,zk-slave2:2183";int sessionTimeoutMs = 25000;int connectionTimeoutMs = 5000;String rootPath = "jannal-listener";RetryPolicy retryPolicy = new ExponentialBackoffRetry(4000, 3);CuratorFramework client = CuratorFrameworkFactory.builder().connectString(connectString).sessionTimeoutMs(sessionTimeoutMs).connectionTimeoutMs(connectionTimeoutMs).retryPolicy(retryPolicy).namespace(rootPath).build();client.start();String path = "/user/username/jannal";client.create().creatingParentsIfNeeded().forPath(path, "jannal123".getBytes(Charsets.UTF_8));//是否进行数据压缩boolean dataIsCompressed = false;final NodeCache cache = new NodeCache(client, path, dataIsCompressed);cache.start(true);CountDownLatch countDownLatch = new CountDownLatch(2);cache.getListenable().addListener(new NodeCacheListener() {@Overridepublic void nodeChanged() throws Exception {ChildData currentData = cache.getCurrentData();if (currentData != null) {logger.info("数据发生变更,新数据:{}", new String(currentData.getData(), StandardCharsets.UTF_8));}else{logger.info("数据发生变更,新数据:{},节点可能被删除", currentData, StandardCharsets.UTF_8);}countDownLatch.countDown();}});client.setData().forPath(path, "jannal".getBytes(Charsets.UTF_8));client.delete().deletingChildrenIfNeeded().forPath(path);countDownLatch.await();}
PathChildrenCache
用于监听指定Zookeeper
数据节点的子节点变化情况。当指定节点的子节点发生变化时,就会回调Listener。Curator
无法对二级子节点触发变更事件。比如对/zk-jannal
子节点进行监听,当/zk-jannal/user/password
节点被创建或者删除的时候,无法触发子节点变更事件@Testpublic void testPathChildrenCacheEventListener() throws Exception {String connectString = "zk-master:2180,zk-slave1:2182,zk-slave2:2183";int sessionTimeoutMs = 25000;int connectionTimeoutMs = 5000;String rootPath = "jannal-parent-listener";RetryPolicy retryPolicy = new ExponentialBackoffRetry(4000, 3);CuratorFramework client = CuratorFrameworkFactory.builder().connectString(connectString).sessionTimeoutMs(sessionTimeoutMs).connectionTimeoutMs(connectionTimeoutMs).retryPolicy(retryPolicy).namespace(rootPath).build();client.start();String path = "/user";client.create().creatingParentsIfNeeded().forPath(path, "jannal123".getBytes(Charsets.UTF_8));//是否进行数据压缩boolean dataIsCompressed = false;/*** 是否把节点内容缓存起来,如果配置为true,则client在接收* 到节点列表变更的同时,也能够获取到节点的数据内容,如果为false* 则无法获取节点的数据内容*/boolean cacheData = true;ExecutorService executorService = Executors.newFixedThreadPool(2);CountDownLatch countDownLatch = new CountDownLatch(3);final PathChildrenCache cache = new PathChildrenCache(client, path, cacheData, dataIsCompressed, executorService);/*** BUILD_INITIAL_CACHE 同步初始化客户端的cache,及创建cache后,就从服务器端拉入对应的数据(这个是NodeCache使用的方式)* NORMAL 异步初始化cache* POST_INITIALIZED_EVENT 异步初始化,初始化完成触发事件PathChildrenCacheEvent.Type.INITIALIZED*/cache.start(PathChildrenCache.StartMode.BUILD_INITIAL_CACHE);cache.getListenable().addListener(new PathChildrenCacheListener() {@Overridepublic void childEvent(CuratorFramework curatorFramework, PathChildrenCacheEvent pathChildrenCacheEvent) throws Exception {ChildData currentData = pathChildrenCacheEvent.getData();//事件类型,可通过判断事件类型来做相应的处理PathChildrenCacheEvent.Type type = pathChildrenCacheEvent.getType();switch (type) {//初始化会触发这个事件case INITIALIZED:logger.info("子类缓存系统初始化完成");break;case CHILD_ADDED://新增子节点/user/usernamelogger.info("新增子节点{}", currentData.getPath());break;case CHILD_UPDATED:// 子节点数据变更[106, 97, 110, 110, 97, 108]logger.info("子节点数据变更{}", new String(currentData.getData(),Charsets.UTF_8));break;case CHILD_REMOVED://子节点数据删除/user/usernamelogger.info("子节点数据删除{}", currentData.getPath());break;}countDownLatch.countDown();}});client.create().creatingParentsIfNeeded().forPath(path+"/username", "jannal123".getBytes(Charsets.UTF_8));TimeUnit.SECONDS.sleep(1);client.setData().forPath(path+"/username", "jannal".getBytes(Charsets.UTF_8));TimeUnit.SECONDS.sleep(1);client.delete().deletingChildrenIfNeeded().forPath(path);countDownLatch.await();}
TreeCache
可以监听整个树上的所有节点。即可以监控节点的状态,还监控节点的子节点的状态@Testpublic void testTreeCache() throws Exception {String connectString = "zk-master:2180,zk-slave1:2182,zk-slave2:2183";int sessionTimeoutMs = 25000;int connectionTimeoutMs = 5000;String rootPath = "jannal-tree-listener";RetryPolicy retryPolicy = new ExponentialBackoffRetry(4000, 3);CuratorFramework client = CuratorFrameworkFactory.builder().connectString(connectString).sessionTimeoutMs(sessionTimeoutMs).connectionTimeoutMs(connectionTimeoutMs).retryPolicy(retryPolicy).namespace(rootPath).build();client.start();String path = "/user";client.create().creatingParentsIfNeeded().forPath(path, "jannal123".getBytes(Charsets.UTF_8));CountDownLatch countDownLatch = new CountDownLatch(1);TreeCache cache = new TreeCache(client, path);cache.getListenable().addListener(new TreeCacheListener() {@Overridepublic void childEvent(CuratorFramework curatorFramework, TreeCacheEvent treeCacheEvent) throws Exception {TreeCacheEvent.Type type = treeCacheEvent.getType();ChildData childData = treeCacheEvent.getData();switch (type) {//子类缓存系统初始化完成case INITIALIZED:logger.info("子类缓存系统初始化完成");break;case NODE_ADDED://新增子节点/user/usernamelogger.info("新增子节点{}", childData != null ? childData.getPath() : null);break;case NODE_UPDATED:// 子节点数据变更jannal// 子节点数据变更jannal2logger.info("子节点数据变更{}", childData != null ? new String(childData.getData(), Charsets.UTF_8) : null);break;case NODE_REMOVED://子节点数据删除/userlogger.info("子节点数据删除{}", childData != null ? childData.getPath() : null);break;}countDownLatch.countDown();}});cache.start();client.setData().forPath(path, "jannal".getBytes());Thread.sleep(1000);client.setData().forPath(path, "jannal2".getBytes());Thread.sleep(1000);client.delete().deletingChildrenIfNeeded().forPath(path);Thread.sleep(1000 * 2);countDownLatch.await();}
其他工具类
Curator
提供了一些工具类。比如ZKPaths
和EnsurePath
ZKPaths
提供更简单的API来构建Znode
路径、递归创建和删除节点。EnsurePath
提供了一种确保数据节点存在的机制。在分布式环境下,A和B机器都同时创建节点,由于并发操作的存在,可能抛出节点已经存在的异常
。EnsurePath
内部实现就是试图创建指定节点,如果节点存在,那么就不进行任何操作,也不抛出异常,否则正常创建节点。从Curator 2.9.0版本开始此类已经过时,首选CuratorFramework.create().creatingParentContainersIfNeeded()
orCuratorFramework.exists().creatingParentContainersIfNeeded()
代码示例
@Testpublic void testOther() throws Exception {String connectString = "zk-master:2180,zk-slave1:2182,zk-slave2:2183";int sessionTimeoutMs = 25000;int connectionTimeoutMs = 5000;String rootPath = "zk-other";RetryPolicy retryPolicy = new ExponentialBackoffRetry(4000, 3);CuratorFramework client = CuratorFrameworkFactory.builder().connectString(connectString).sessionTimeoutMs(sessionTimeoutMs).connectionTimeoutMs(connectionTimeoutMs).retryPolicy(retryPolicy).namespace(rootPath).build();client.start();String path = ZKPaths.fixForNamespace(rootPath, "/user");// 输出:/zk-other/userlogger.info(path);ZKPaths.PathAndNode pathAndNode = ZKPaths.getPathAndNode("/zk-other/user/username");// path:/zk-other/user,node:usernamelogger.info("path:{},node:{}", pathAndNode.getPath(), pathAndNode.getNode());CuratorZookeeperClient zookeeperClient = client.getZookeeperClient();//创建节点ZKPaths.mkdirs(zookeeperClient.getZooKeeper(), "/zk-other/user/password");//获取子节点List<String> sortedChildren = ZKPaths.getSortedChildren(zookeeperClient.getZooKeeper(), "/zk-other");logger.info(sortedChildren.toString());}
开发测试
为了便于开发人员进行zk的开发与测试,可以使用
curator-test
模块。依赖compile "org.apache.curator:curator-test:2.11.0"
单元测试
@Testpublic void testSingleServer() throws Exception {File dataDir = new File(".");TestingServer server = new TestingServer(2000, dataDir);server.start();CuratorFramework curatorFramework = CuratorFrameworkFactory.builder().connectString(server.getConnectString()).sessionTimeoutMs(1000).retryPolicy(new RetryNTimes(3, 1000)).build();curatorFramework.start();System.out.println(curatorFramework.getChildren().forPath("/"));curatorFramework.close();server.stop();}
集群测试
@Testpublic void testClusterServer() throws Exception {TestingCluster server = new TestingCluster(3);server.start();Thread.sleep(2000);TestingZooKeeperServer leader = null;for (TestingZooKeeperServer zs : server.getServers()) {logger.info(zs.getInstanceSpec().getServerId() + "-");logger.info(zs.getQuorumPeer().getServerState() + "-");logger.info(zs.getInstanceSpec().getDataDirectory().getAbsolutePath());if (zs.getQuorumPeer().getServerState().equals("leading")) {leader = zs;}}//模拟leader挂掉leader.kill();logger.info("leader 挂掉之后");for (TestingZooKeeperServer zs : server.getServers()) {logger.info(zs.getInstanceSpec().getServerId() + "-");logger.info(zs.getQuorumPeer().getServerState() + "-");logger.info(zs.getInstanceSpec().getDataDirectory().getAbsolutePath());}server.stop();}
zookeeper之Curator相关推荐
- Zookeeper客户端Curator使用详解
http://www.jianshu.com/p/70151fc0ef5d Zookeeper客户端Curator使用详解 简介 Curator是Netflix公司开源的一套zookeeper客户端框 ...
- 软件架构-zookeeper之curator详解
为了更好的实现java操作zookeeper服务器,后来出现Curator框架,非常的强大,目前已经是apache的顶级项目,里面提供了更多丰富的操作.例如:session超时重连,主从选举,分布式计 ...
- ZooKeeper客户端Curator的基本使用
前提:ZooKeeper版本:3.4.14 Curator版本:2.13.0 1.什么是Curator Curator是Netflix公司开源的一套zookeeper客户端框架,解决了很多Z ...
- Zookeeper框架Curator使用
原文内容: 文档:Zookeeper框架Curator使用.note 链接:http://note.youdao.com/noteshare?id=a5189de7d4f76a882ef52a6baa ...
- 【高级篇】详解Zookeeper客户端Curator
一.序言 之前分享过一篇关于Curotor的基本应用[基础篇]详解Zookeeper客户端Curator,如果对Curator没有了解的可以看看,本文分享关于Curator的一些高级特性,在监听和le ...
- 【基础篇】详解Zookeeper客户端Curator
一.前言 Zookeeper被广泛应用于分布式环境下各种应用程序的协调,而Curator无疑是Zookeeper客户端中的瑞士军刀,解决了很多Zookeeper客户端非常底层的细节开发工作,包括连接重 ...
- ZooKeeper : Curator框架Znode、ACL API介绍
ZooKeeper : Curator框架Znode.ACL API介绍 在之前的博客中,博主介绍了Curator框架的重试策略和Session API,并且对namespace进行了原理分析: Zo ...
- ZooKeeper : Curator框架之分布式锁InterProcessReadWriteLock
InterProcessReadWriteLock 跨JVM工作的可重入读/写互斥锁,使用Zookeeper来持有锁,所有JVM中使用相同锁路径的所有进程都将实现进程间临界区.这个互斥锁是公平的,每个 ...
- 聊聊、Zookeeper 客户端 Curator
[Curator] 和 ZkClient 一样,Curator 也是开源客户端,Curator 是 Netflix 公司开源的一套框架. <dependency><groupId ...
- Zookeeper、Curator
1. 初识Zookeeper 1.1 Zookeeper概念 Zookeeper是Apache Hadoop项目下的一个子项目,是一个树形目录服务 Zookeeper翻译过来就是动物园管理员,它是用来 ...
最新文章
- GDOI2018记录
- Haskell / GHC中的“ forall”关键字有什么作用?
- 风控特:关系网络特征工程入门实践
- 管理之道(三) - 不要吝惜赞美
- 三级pc技术_第十九周PC、笔电、数码周边新品汇总:AMD英特尔激战正酣
- CSS 小结笔记之滑动门技术
- php脚本来创建一个表,PHP - SQL脚本创建器
- java 排序算法面试题_面试题: java中常见的排序算法的实现及比较
- 排序算法合集 python
- 谁偷偷删了你的微信?别慌!一篇Python学习教程帮你都揪出来
- java 对象流 乱码,JAVA 中的 IO 流
- 转:施炜:铁军组织是怎样炼成的?高能组织=人×管理体系×数字标准
- 【新书推荐】【2017.07】创新的雷达技术与应用第一卷:实孔径阵列雷达、成像雷达与无源多基地雷达
- 浅墨博客《游戏编程模式》
- 2022软工K班结对编程作业
- 门诊地图导航怎么做,零成本的医院室内导航解决方案
- js通过Ajax传递数组
- 发生系统错误 5。拒绝访问。
- 飘易关键字排名批量查询工具分享!
- CC2540开发入门
热门文章
- 浏览器显示无法解析服务器的DNS地址,搜狗浏览器无法解析服务器的DNS地址怎么解决...
- 怎么复制黑苹果config配置_黑苹果主机(百分百成功硬件配置)
- spark while_while循环怎么理解
- 无限天空服务器,滚动的天空无限钻石无限金币版
- Android初试--了解和认识Android
- Linux简介,linux终端符号含义
- MATLAB面向对象_及_AppDesigner使用
- 计算机管理的磁盘管理简单卷,小编教你磁盘管理新建简单卷怎么做
- Wrapper中ge,gt,lt,le的含义
- AI创作教程之如何使用简单的 Web API 和 GPU 支持在 Docker 中运行 Stable Diffusion,在 45 秒内启动用于 Stable Diffusion的 Web API