Apache curator-client详解
Apache curator框架中curator-client组件可以作为zookeeper client来使用,它提供了zk实例创建/重连机制等,简单便捷.不过直接使用curator-client并不能减少太多的开发量,因为它相对比较底层,稍后我们继续了解curator-framework组件提供的更多的便捷特性.
一.核心API
1. CuratorZookeeperClient类: zookeeper客户端,根据指定的配置信息创建zookeeper实例.
2. RetryPolicy接口: 重连策略,当zookeeper失去链接时使用的"重连策略":
<> RetryOneTime: 只重连一次.
<> RetryNTime: 指定重连的次数N.
<> RetryUtilElapsed: 指定最大重连超时时间和重连时间间隔,间歇性重连直到超时或者链接成功.
<> ExponentialBackoffRetry: 基于"backoff"方式重连,和RetryUtilElapsed的区别是重连的时间间隔是动态的.
- 时间间隔 = baseSleepTimeMs * Math.max(1, random.nextInt(1 << (retryCount + 1))).
<> BoundedExponentialBackoffRetry: 同ExponentialBackoffRetry(最大重试次数的控制),增加了最大睡眠时间.
3. RetryLoop类: 操作重试,如果在执行一个操作时,遇到了zk链接异常,怎么办?RetryLoop可以不断重试,直到网络正常且操作执行成功为止.SessionFailRetryLoop类是一个特列,可以兼容当session失效时,如何进行操作重试.
4. EnsembleProvider: 配置提供者,创建zk客户端时,需要指定connectionString(例如:127.0.0.1:2181),在zookeeper API中只能显式的指定,curator在这个方面提供了更加灵活性的方式,你可以通过任何方式获取或者构建connectionString.
<> FixedEnsembleProvider: 使用固定的字符串作为connectionString.
<> ExhibitorEnsembleProvider: 动态的获取connectionString,可以指定一个URL用来提供connectionString的输出服务.此后此Provider将会间歇性的获取最新的connectionString字符串,并保存.事实上,ExhibitorEnsembleProvider只是一个样例,展示了一种动态获取connectionString的方式,如果在真正的开发中,你可能需要参考它,来定制自己的Provider.
二. 通用客户端代码示例
- public class ZooKeeperClient extends Thread{
- protected final CuratorZookeeperClient zkClient;
- protected String parent;
- public static final Charset charset = Charset.forName("utf-8");
- private ZNodeWatcher zNodeWatcher = new ZNodeWatcher();//自定义watcher
- public ZooKeeperClient(String connectString, int sessionTimeout, String parent) throws Exception {
- this.parent = parent;
- zkClient = new CuratorZookeeperClient(connectString, sessionTimeout, sessionTimeout, zNodeWatcher, new ExponentialBackoffRetry(1000, Integer.MAX_VALUE));
- zkClient.start();//must,but anytime before zookeeper operation
- zkClient.blockUntilConnectedOrTimedOut(); //first connection should be successful
- }
- public boolean exist(String path,boolean watched) throws Exception{
- return zkClient.getZooKeeper().exists(path,watched) == null ? false : true;
- }
- /**
- * 此path必须存在,如果不存在则立即创建
- * @param path
- * @return
- */
- public boolean ensurePath(final String path) throws Exception{
- PathUtils.validatePath(path);
- return RetryLoop.callWithRetry(zkClient, new Callable<Boolean>(){
- @Override
- public Boolean call() throws Exception {
- EnsurePath ensure = new EnsurePath(path);
- ensure.ensure(zkClient);
- return true;
- }
- });
- }
- /**
- *
- * @param path
- * @param data
- * @return 如果path已经存在或者创建成功,则返回true,否则返回false。
- * @throws Exception
- */
- public boolean create(final String path, final String data) throws Exception {
- PathUtils.validatePath(path);//if bad format,here will throw some Exception;
- return RetryLoop.callWithRetry(zkClient, new Callable<Boolean>() {
- @Override
- public Boolean call() throws Exception {
- int _current = 0;
- while (_current < 3) {
- _current++;
- try {
- //zkClient.blockUntilConnectedOrTimedOut();
- //确保父节点存在
- EnsurePath ensure = new EnsurePath(path).excludingLast();
- //parent path should be existed.
- //EnsurePath: retry + block
- ensure.ensure(zkClient); //ugly API
- zkClient.getZooKeeper().create(path, data.getBytes(charset), ZooDefs.Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT);
- return true;
- } catch (KeeperException.NodeExistsException e) {
- return true;
- }
- //retry only for KeeperException,not for other runtimeException。
- //other exception will be thrown,and stop retry!!
- //if no Exception thrown,retry will be stopped and return successfully.
- }
- return false;
- }
- }) ;
- }
- public class ZNodeWatcher implements Watcher{
- @Override
- public void process(WatchedEvent event) {
- Event.EventType eventType = event.getType();
- Event.KeeperState keeperState = event.getState();
- String path = event.getPath();
- switch(event.getType()) {
- case None:
- //connection Error:会自动重连
- logger.info("[Watcher],Connecting...");
- if(keeperState == Event.KeeperState.SyncConnected){
- logger.info("[Watcher],Connected...");
- //检测临时节点是否失效等。
- }
- break;
- case NodeCreated:
- logger.info("[Watcher],NodeCreated:" + path);
- break;
- case NodeDeleted:
- logger.info("[Watcher],NodeDeleted:" + path);
- break;
- default:
- //
- }
- }
- }
- }
三. Provider代码实例
本实例展示了如何使用curator-client开发简单的API,展示了RetryPolicy,RetryLoop的使用方式;实例中使用Curator自带的ExhibitorEnsembleProvider动态获取zookeeper服务器列表信息.
1. pom.xml
- <dependency>
- <groupId>org.apache.zookeeper</groupId>
- <artifactId>zookeeper</artifactId>
- <version>3.4.5</version>
- </dependency>
- <dependency>
- <groupId>org.apache.curator</groupId>
- <artifactId>curator-recipes</artifactId>
- <version>2.3.0</version>
- </dependency>
2. curator-config.propeties
- host.rest.servers=127.0.0.1,localhost
- host.rest.port=8080
- host.backup=127.0.0.1:2181
- host.rest.path=/servers/zk
- host.rest.period=180000
3. IZkClient.java
- package com.test.demo.curator;
- import java.util.*;
- import java.util.concurrent.Callable;
- import java.util.concurrent.TimeUnit;
- import org.apache.curator.CuratorZookeeperClient;
- import org.apache.curator.RetryLoop;
- import org.apache.curator.RetryPolicy;
- import org.apache.curator.TimeTrace;
- import org.apache.curator.drivers.TracerDriver;
- import org.apache.curator.ensemble.EnsembleProvider;
- import org.apache.curator.ensemble.exhibitor.DefaultExhibitorRestClient;
- import org.apache.curator.ensemble.exhibitor.ExhibitorEnsembleProvider;
- import org.apache.curator.ensemble.exhibitor.ExhibitorRestClient;
- import org.apache.curator.ensemble.exhibitor.Exhibitors;
- import org.apache.curator.retry.ExponentialBackoffRetry;
- import org.apache.curator.retry.RetryNTimes;
- import org.apache.curator.utils.EnsurePath;
- import org.apache.curator.utils.PathUtils;
- import org.apache.curator.utils.ZKPaths;
- import org.apache.zookeeper.CreateMode;
- import org.apache.zookeeper.KeeperException;
- import org.apache.zookeeper.Transaction;
- import org.apache.zookeeper.ZooDefs;
- import org.apache.zookeeper.data.ACL;
- public class IZkClient {
- private final CuratorZookeeperClient zkClient;
- public IZkClient(String configLocation) throws Exception {
- Properties properties = new Properties();
- properties.load(ClassLoader.getSystemResourceAsStream(configLocation));
- EnsembleProvider provider = buildProvider(properties);
- String pTimeout = properties.getProperty("zk.timeout");
- Integer timeout = 30000;
- if (pTimeout != null) {
- timeout = Integer.valueOf(pTimeout);
- }
- zkClient = new CuratorZookeeperClient(provider, timeout, timeout, null, new ExponentialBackoffRetry(1000, Integer.MAX_VALUE));
- zkClient.setTracerDriver(new PrintTraceDrive());
- zkClient.start();//must,but anytime before zookeeper operation
- zkClient.blockUntilConnectedOrTimedOut(); //first connection should be successful
- }
- /**
- * build provider,all of params from config-file
- * @param properties
- * @return
- */
- private EnsembleProvider buildProvider(Properties properties) {
- String servers = properties.getProperty("host.rest.servers"); //hosts.servers = 127.0.0.1,127.0.0.2
- if (servers == null || servers.isEmpty()) {
- throw new IllegalArgumentException("host.servers cant be empty");
- }
- List<String> hostnames = Arrays.asList(servers.split(","));
- String port = properties.getProperty("host.rest.port");
- Integer restPort = 80; //default
- if (port != null) {
- restPort = Integer.valueOf(port);
- }
- final String backupAddress = properties.getProperty("host.backup");//127.0.0.1:2181
- //if network is error,you should sepcify a backup zk-connectString
- Exhibitors exhibitors = new Exhibitors(hostnames, restPort, new Exhibitors.BackupConnectionStringProvider() {
- @Override
- public String getBackupConnectionString() throws Exception {
- return backupAddress;
- }
- });
- //rest,as meaning of getting fresh zk-connectString list.
- ExhibitorRestClient restClient = new DefaultExhibitorRestClient();
- String restUriPath = properties.getProperty("host.rest.path");
- String period = properties.getProperty("host.rest.period");
- Integer pollingMs = 180000; //3 min
- if (period != null) {
- pollingMs = Integer.valueOf(period);
- }
- return new ExhibitorEnsembleProvider(exhibitors, restClient, restUriPath, pollingMs, new RetryNTimes(10, 1000));
- }
- public CuratorZookeeperClient getZkClient() {
- return zkClient;
- }
- /**
- * how to use RtryLoop ,another style
- * if Znode has been existed,will delete it,and create it again.
- *
- */
- public boolean replace(final String path,final byte[] value){
- PathUtils.validatePath(path);
- boolean result = false;
- try{
- result = RetryLoop.callWithRetry(zkClient,new Callable<Boolean>() {
- @Override
- public Boolean call() throws Exception {
- int _current = 0;
- while(_current < 3){
- _current++;
- try{
- zkClient.blockUntilConnectedOrTimedOut();
- Transaction tx = zkClient.getZooKeeper().transaction();
- tx.delete(path, -1);
- tx.create(path,value,ZooDefs.Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT);
- tx.commit();
- return true;
- } catch (KeeperException.NoNodeException e){
- //
- } catch (KeeperException.NodeExistsException e){
- //
- }
- }
- return false; //To change body of implemented methods use File | Settings | File Templates.
- }
- }) ;
- }catch (Exception e){
- e.printStackTrace();
- }
- return result;
- }
- //API : on for test
- public String createPath(String path, byte[] value) throws Exception {
- PathUtils.validatePath(path);//if bad format,here will throw some Exception;
- EnsurePath ensure = new EnsurePath(path).excludingLast();
- //parent path should be existed.
- //EnsurePath: retry + block
- ensure.ensure(zkClient); //ugly API
- return zkClient.getZooKeeper().create(path, value, ZooDefs.Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT);
- }
- //API: on for test
- public boolean createPath(String path, byte[] value,int blockTimes){
- if (!zkClient.isConnected() && blockTimes == 0) {
- return false;
- }
- TimeTrace trace = zkClient.startTracer("createPath:" + path);//log message
- try{
- EnsurePath ensure = new EnsurePath(path).excludingLast();
- ensure.ensure(zkClient);//only for persistent node
- RetryLoop loop = zkClient.newRetryLoop();
- int _current = 0;
- while(loop.shouldContinue()){
- try{
- if(_current >= blockTimes){
- loop.markComplete(); //stop here.
- continue;
- }
- //blocking
- boolean isConnected = zkClient.blockUntilConnectedOrTimedOut();
- if(!isConnected){
- _current++;
- continue;
- }
- zkClient.getZooKeeper().create(path, value, ZooDefs.Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT);
- loop.markComplete();
- } catch (KeeperException.NodeExistsException e){
- loop.markComplete();//exist ,stop here
- } catch (Exception e){
- loop.takeException(e);
- }
- }
- } catch (Exception e){
- e.printStackTrace();
- return false; //cant create path
- } finally{
- trace.commit();
- }
- return true;
- }
- public byte[] getData(String path) throws Exception{
- PathUtils.validatePath(path);
- return zkClient.getZooKeeper().getData(path,false,null);
- }
- public void close(){
- zkClient.close();
- }
- class PrintTraceDrive implements TracerDriver {
- @Override
- public void addTrace(String name, long time, TimeUnit unit) {
- System.out.println("<Trace>" + name + ";time:" + TimeUnit.MILLISECONDS.convert(time, unit) + " ms");
- }
- @Override
- public void addCount(String name, int increment) {
- }
- }
- }
4. IZkClientMain.java(for testing)
- public class IZkClientMain {
- public static void main(String[] args) throws Exception {
- String configLocation = "curator-config.properties";
- IZkClient iZkClient = new IZkClient(configLocation);
- String value = "curator-demo";
- String path = "/curator/child/0";
- iZkClient.replace(path, value.getBytes("utf-8"));
- //simple method;
- String nodeName = ZKPaths.getNodeFromPath(path);
- System.out.print(nodeName);
- //value
- byte[] bytes = iZkClient.getData(path);
- System.out.println(new String(bytes, "utf-8"));
- Thread.sleep(180000 * 2);
- iZkClient.close();
- }
- }
5. ExhibitorEnsembleProvider需要使用远端的一个REST风格的Url来提供zookeeper服务器列表,如下为Spring方式:
- @Controller
- @RequestMapping("/servers")
- public class ServersController {
- @RequestMapping(value = "/zk",headers="Accept=application/x-www-form-urlencoded")
- public void zk(HttpServletResponse response) throws Exception{
- FormHttpMessageConverter converter = new FormHttpMessageConverter();
- converter.setCharset(Charset.forName("utf-8"));
- HttpOutputMessage output = new ServletServerHttpResponse(response);
- converter.write(buildServers(), MediaType.APPLICATION_FORM_URLENCODED,output);
- //String servers = "count=2&port=2181&server0=127.0.0.1&server1=localhost";
- }
- private MultiValueMap<String,Object> buildServers(){
- MultiValueMap<String,Object> map = new LinkedMultiValueMap<String, Object>();
- map.add("count","2");
- map.add("port","2181");
- map.add("server0","127.0.0.1");
- map.add("server1","localhost");
- return map;
- }
- }
备注:Curator-client可以帮助我们进行链接重连操作,重连过程中,我们不需要关注太多,不过你仍然可以通过注册Watcher的手段来活的通知.如果在操作过程中,zk的链接有异常,你可以通过RetryLoop的方式实现阻塞.
Apache curator-client详解的更多相关文章
- Zookeeper客户端Curator使用详解
Zookeeper客户端Curator使用详解 前提 最近刚好用到了zookeeper,做了一个基于SpringBoot.Curator.Bootstrap写了一个可视化的Web应用: zookeep ...
- 转:Zookeeper客户端Curator使用详解
原文:https://www.jianshu.com/p/70151fc0ef5d Zookeeper客户端Curator使用详解 前提 最近刚好用到了zookeeper,做了一个基于SpringBo ...
- Apache Rewrite 规则详解
在开篇之前: 我想说这篇文章其实是我刚刚接触Rewrite的时候学习的文档,应属转载,但是在这里我不想写明原地址,原因是文章中大多数给出的配置命令经实验都是错误的.需要原文的可以在谷歌上搜索一下&qu ...
- org.apache.log4j.Logger详解
org.apache.log4j.Logger 详解 1. 概述 1.1. 背景 在应用程序中添加日志记录总的来说基于三个目的 :监视代码中变量的变化情况,周期性的记录到文件中供其他应用进行统计分析工 ...
- Apache POI使用详解
Apache POI使用详解 1.POI结构与常用类 (1)POI介绍 Apache POI是Apache软件基金会的开源项目,POI提供API给Java程序对Microsoft Office格式档案 ...
- org.apache.common.io-FileUtils详解
org.apache.common.io---FileUtils详解 getTempDirectoryPath():返回临时目录路径; public static String getTempDire ...
- org.apache.log4j.Logger 详解
org.apache.log4j.Logger 详解 1. 概述 1.1. 背景 在应用程序中添加日志记录总的来说基于三个目的 :监视代码中变量的变化情况,周期性的记录到文件中供其他应用进行统计 ...
- Apache 工作模式详解
Apache 工作模式详解 Apache 2.X 支持插入式并行处理模块,称为多路处理模块(MPM).在编译apache时必须选择也只能选择一个MPM,对类UNIX系统,有几个不同的MPM可供选择, ...
- Hadoop3.1.1源码Client详解 : 入队前数据写入
该系列总览: Hadoop3.1.1架构体系——设计原理阐述与Client源码图文详解 : 总览 紧接着上一篇: Hadoop3.1.1源码Client详解 : 写入准备-RPC调用与流的建立 先给出 ...
- Hadoop3.1.1源码Client详解 : Packet入队后消息系统运作之DataStreamer(Packet发送) : 主干
该系列总览: Hadoop3.1.1架构体系——设计原理阐述与Client源码图文详解 : 总览 在上一章(Hadoop3.1.1源码Client详解 : 写入准备-RPC调用与流的建立) 我们提到, ...
随机推荐
- MathType for mac 能够实现在Word里面双击公式编辑的方法
最近我遇到了一个问题,在使用Word编辑公式时遇到了阻碍. 问题: 我为了顺应潮流呢,用的是office for mac2016版本,在发现MathType安装好后,不能连接到Word里面,从Math ...
- 十分钟轻松让你认识ASP.NET 5(MVC6)
ASP.NET 5差不多快发布了.自己也学习了有两个月了.今天给没有接触asp.net 5的同学写一个简单地十分钟教程,教你认识一下asp.net 5. 1.安装kvm 首先,你需要以管理员权限打开c ...
- Golang友团无闻Go语言Web基础视频教程
教程内容:GO语言资料Golang友团无闻Go语言编程基础Golang友团无闻Go语言Web基础教程 Go语言Web基础教程列表:[Go Web基础]12Go Web 扩展学习.mp4[Go Web基 ...
- iframe异步加载技术及性能
我们会经常使用iframes来加载第三方的内容.广告或者插件.使用iframe是因为它可以和主页面并行加载,不会阻塞主页面.当然使用iframe也是有利有弊的:Steve Souders在他的blog ...
- C#基础系列——反射笔记
前言:使用反射也有几年了,但是一直觉得,反这个概念很抽象,今天有时间就来总结下这个知识点. 1.为什么需要反射: 最初使用反射的时候,作为小菜总是不理解,既然可以通过new 一个对象的方式得到对象,然 ...
- Centos6.4 本地yum源配置
由于单位的服务器均使用的是内网,而安装一些软件如Git,需要很多的依赖包,使用yum安装相对简单,由于不能联网故配置本地yum源配置. 1.首先将需要rpm库添加到系统中: 1).虚拟机中安装的lin ...
- JS组件系列——Bootstrap寒冬暖身篇:弹出框和提示框效果以及代码展示
前言:对于Web开发人员,弹出框和提示框的使用肯定不会陌生,比如常见的表格新增和编辑功能,一般常见的主要有两种处理方式:行内编辑和弹出框编辑.在增加用户体验方面,弹出框和提示框起着重要的作用,如果你的 ...
- kuangbin专题总结一 简单搜索
A - 棋盘问题:在一个给定形状的棋盘(形状可能是不规则的)上面摆放棋子,棋子没有区别.要求摆放时任意的两个棋子不能放在棋盘中的同一行或者同一列,请编程求解对于给定形状和大小的棋盘,摆放k个棋子的所有 ...
- add添加
s = {1,2,3,4,5,6,} 进行添加数据! s = {1,2,3,4,5,6,} s.add('s')#添加字符串's' s.add('3')#添加字符串'3' s.add(3)#添加3和字 ...
- XStream简单入门
简单的讲,XStream 涉及的就五个知识点:详情参考 官网 混叠,注解,转换器,对象流和操作json! 下面就用几个简单的例子来实现上述五个知识点! 基本步骤: 第1步:创建XStream对象. 通 ...