CuratorFramework
Framework
是ZooKeeper Client更高的抽象API
自动连接管理:
1. 当ZooKeeper客户端内部出现异常, 将自动进行重连或重试, 该过程对外几乎完全透明
2. 监控节点数据变化事件NodeDataChanged,需要时调用updateServerList()方法
3. Curator recipes自动移除监控

更清晰的API: 简化了ZooKeeper原生的方法, 事件等, 提供流式fluent的接口
提供Recipes实现 : 选举,共享锁, 路径cache, 分布式队列,分布式优先队列等

CuratorFrameworkFactory类提供了两个方法, 一个工厂方法newClient, 一个构建方法build. 使用工厂方法newClient可以创建一个默认的实例, 而build构建方法可以对实例进行定制. 当CuratorFramework实例构建完成, 紧接着调用start()方法, 在应用结束的时候, 需要调用close()方法. CuratorFramework是线程安全的. 在一个应用中可以共享同一个zk集群的CuratorFramework.

CuratorFramework API采用了连贯风格的接口(Fluent Interface). 所有的操作一律返回构建器, 当所有元素加在一起之后, 整个方法看起来就像一个完整的句子. 比如下面的操作:

client.create().forPath("/head")
client.delete().inBackground().forPath("/head")
client.create().withMode(CreateMode.EPHEMERAL_SEQUENTIAL).forPath("/head/child")
client.getData().watched().inBackground().forPath("/test")

方法说明:
create(): 发起一个create操作. 可以组合其他方法 (比如mode 或background) 最后以forPath()方法结尾
delete(): 发起一个删除操作. 可以组合其他方法(version 或background) 最后以forPath()方法结尾
checkExists(): 发起一个检查ZNode 是否存在的操作. 可以组合其他方法(watch 或background) 最后以forPath()方法结尾
getData(): 发起一个获取ZNode数据的操作. 可以组合其他方法(watch, background 或get stat) 最后以forPath()方法结尾
setData(): 发起一个设置ZNode数据的操作. 可以组合其他方法(version 或background) 最后以forPath()方法结尾
getChildren(): 发起一个获取ZNode子节点的操作. 可以组合其他方法(watch, background 或get stat) 最后以forPath()方法结尾
inTransaction(): 发起一个ZooKeeper事务. 可以组合create, setData, check, 和/或delete 为一个操作, 然后commit() 提交

通知(Notification)
通过ClientListener实现。 通过CuratorFramework实例里的addListener()注册listener. listener实现以下方法:
- eventReceived() 当一个后台操作完成或者指定的watch被触发时该方法被调用

CuratorEvent
CuratorEvent(在以前版本为ClientEvent)是对各种操作触发相关事件对象(POJO)的一个完整封装, 而事件对象的内容跟事件类型相关, 事件类型可通过getType()获得。下面是对应关系:

名称空间(Namespace)

因为一个zk集群会被多个应用共享, 为了避免各个应用的zk patch冲突, Curator Framework内部会给每一个Curator Framework实例分配一个namespace(可选). 这样你在create ZNode的时候都会自动加上这个namespace作为这个node path的root. 使用代码如下:

CuratorFramework client = CuratorFrameworkFactory.builder().namespace("MyApp") ... build();

client.create().forPath("/test", data);
// 实际上节点路径为: "/MyApp/test"

临时连接
Curator还提供了临时的CuratorFramework: CuratorTempFramework,意思是在一个容易失败的网络如WAN中,向zooKeeper的单一请求。 一定时间不活动后连接会被关闭,只提供了有限的api. 临时 CuratorFramework基于Camille Fournier的一篇文章:http://whilefalse.blogspot.com/2012/12/building-global-highly-available.html.

创建builder时不是调用build()而是调用buildTemp()。 3分钟不活动连接就被关闭,也可以指定不活动的时间。 它只提供了下面几个方法:

/**
* Stop the client
*/
public void close(); /**
* Start a transaction builder
*
* @return builder object
* @throws Exception errors
*/
public CuratorTransaction inTransaction() throws Exception; /**
* Start a get data builder
*
* @return builder object
* @throws Exception errors
*/
public TempGetDataBuilder getData() throws Exception;

创建实例
两种方法,newClient()或build(),实例如下,来自于官网

/**
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package framework; import org.apache.curator.RetryPolicy;
import org.apache.curator.framework.CuratorFramework;
import org.apache.curator.framework.CuratorFrameworkFactory;
import org.apache.curator.retry.ExponentialBackoffRetry; public class CreateClientExamples
{
public static CuratorFramework createSimple(String connectionString)
{
// these are reasonable arguments for the ExponentialBackoffRetry. The first
// retry will wait 1 second - the second will wait up to 2 seconds - the
// third will wait up to 4 seconds.
ExponentialBackoffRetry retryPolicy = new ExponentialBackoffRetry(1000, 3); // The simplest way to get a CuratorFramework instance. This will use default values.
// The only required arguments are the connection string and the retry policy
return CuratorFrameworkFactory.newClient(connectionString, retryPolicy);
} public static CuratorFramework createWithOptions(String connectionString, RetryPolicy retryPolicy, int connectionTimeoutMs, int sessionTimeoutMs)
{
// using the CuratorFrameworkFactory.builder() gives fine grained control
// over creation options. See the CuratorFrameworkFactory.Builder javadoc
// details
return CuratorFrameworkFactory.builder()
.connectString(connectionString)
.retryPolicy(retryPolicy)
.connectionTimeoutMs(connectionTimeoutMs)
.sessionTimeoutMs(sessionTimeoutMs)
// etc. etc.
.build();
}
}

CRUD操作,来自于官网

package com.colobu.zkrecipe.framework;

import java.util.List;

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.CuratorListener;
import org.apache.zookeeper.CreateMode;
import org.apache.zookeeper.Watcher; public class CrudExample { public static void main(String[] args) { } public static void create(CuratorFramework client, String path, byte[] payload) throws Exception {
// this will create the given ZNode with the given data
client.create().forPath(path, payload);
} public static void createEphemeral(CuratorFramework client, String path, byte[] payload) throws Exception {
// this will create the given EPHEMERAL ZNode with the given data
client.create().withMode(CreateMode.EPHEMERAL).forPath(path, payload);
} public static String createEphemeralSequential(CuratorFramework client, String path, byte[] payload) throws Exception {
// this will create the given EPHEMERAL-SEQUENTIAL ZNode with the given
// data using Curator protection.
return client.create().withProtection().withMode(CreateMode.EPHEMERAL_SEQUENTIAL).forPath(path, payload);
} public static void setData(CuratorFramework client, String path, byte[] payload) throws Exception {
// set data for the given node
client.setData().forPath(path, payload);
} public static void setDataAsync(CuratorFramework client, String path, byte[] payload) throws Exception {
// this is one method of getting event/async notifications
CuratorListener listener = new CuratorListener() {
@Override
public void eventReceived(CuratorFramework client, CuratorEvent event) throws Exception {
// examine event for details
}
};
client.getCuratorListenable().addListener(listener);
// set data for the given node asynchronously. The completion
// notification
// is done via the CuratorListener.
client.setData().inBackground().forPath(path, payload);
} public static void setDataAsyncWithCallback(CuratorFramework client, BackgroundCallback callback, String path, byte[] payload) throws Exception {
// this is another method of getting notification of an async completion
client.setData().inBackground(callback).forPath(path, payload);
} public static void delete(CuratorFramework client, String path) throws Exception {
// delete the given node
client.delete().forPath(path);
} public static void guaranteedDelete(CuratorFramework client, String path) throws Exception {
// delete the given node and guarantee that it completes
client.delete().guaranteed().forPath(path);
} public static List<String> watchedGetChildren(CuratorFramework client, String path) throws Exception {
/**
* Get children and set a watcher on the node. The watcher notification
* will come through the CuratorListener (see setDataAsync() above).
*/
return client.getChildren().watched().forPath(path);
} public static List<String> watchedGetChildren(CuratorFramework client, String path, Watcher watcher) throws Exception {
/**
* Get children and set the given watcher on the node.
*/
return client.getChildren().usingWatcher(watcher).forPath(path);
}
}

事务

package com.colobu.zkrecipe.framework;

import java.util.Collection;

import org.apache.curator.framework.CuratorFramework;
import org.apache.curator.framework.api.transaction.CuratorTransaction;
import org.apache.curator.framework.api.transaction.CuratorTransactionFinal;
import org.apache.curator.framework.api.transaction.CuratorTransactionResult; public class TransactionExample { public static void main(String[] args) { } public static Collection<CuratorTransactionResult> transaction(CuratorFramework client) throws Exception {
// this example shows how to use ZooKeeper's new transactions
Collection<CuratorTransactionResult> results = client.inTransaction().create().forPath("/a/path", "some data".getBytes())
.and().setData().forPath("/another/path", "other data".getBytes())
.and().delete().forPath("/yet/another/path")
.and().commit(); // IMPORTANT! The transaction is not submitted until commit() is called for (CuratorTransactionResult result : results) {
System.out.println(result.getForPath() + " - " + result.getType());
}
return results;
} /*
* These next four methods show how to use Curator's transaction APIs in a
* more traditional - one-at-a-time - manner
*/
public static CuratorTransaction startTransaction(CuratorFramework client) {
// start the transaction builder
return client.inTransaction();
} public static CuratorTransactionFinal addCreateToTransaction(CuratorTransaction transaction) throws Exception {
// add a create operation
return transaction.create().forPath("/a/path", "some data".getBytes()).and();
} public static CuratorTransactionFinal addDeleteToTransaction(CuratorTransaction transaction) throws Exception {
// add a delete operation
return transaction.delete().forPath("/another/path").and();
} public static void commitTransaction(CuratorTransactionFinal transaction) throws Exception {
// commit the transaction
transaction.commit();
}
}

自己写的练习
1) 新建 maven项目,添加依赖,添加curator-recipes即可

<dependency >
<groupId >org.apache.curator </ groupId>
<artifactId > curator-recipes</ artifactId >
<version >2.6.0 </ version>
</dependency >

2) 采用CuratorFrameworkFactory.newClient() 或者 build() 方式 创建CuratorFramework实例,如下所示:

RetryPolicy retryPolicy = new ExponentialBackoffRetry(1000, 3);
CuratorFramework client; // client= CuratorFrameworkFactory.newClient(CONNECTSTRING, retryPolicy); client=CuratorFrameworkFactory. builder().
connectString( CONNECTSTRING )
.connectionTimeoutMs(30000)
.sessionTimeoutMs(30000)
.canBeReadOnly( false ).retryPolicy(retryPolicy)
.namespace( NAMESPACE )
.defaultData( null )
.build();

3) client.start() 启动,结束时调用client.close() 关闭
4) 通过fluent方式进行相关操作,如下增删改查:

 client.create().forPath( PATH, "hello world" .getBytes());
byte [] bs=client.getData().forPath( PATH);
System. out.println( "新建的节点,data为: " + new String(bs)); client.setData().forPath( PATH ,"hello china".getBytes());
// 由于是在background模式下获取的data,此时的 bs可能为null
byte [] bs2=client.getData().watched().inBackground().forPath( PATH);
System. out.println( "新修改的节点,data为: " + new String(bs2!=null ? bs2 : new byte[0])); client.delete().forPath( PATH );

完整代码如下:

package curator;

import org.apache.curator.RetryPolicy;
import org.apache.curator.framework.CuratorFramework;
import org.apache.curator.framework.CuratorFrameworkFactory;
import org.apache.curator.retry.ExponentialBackoffRetry;
import org.apache.curator.utils.CloseableUtils;
import org.apache.zookeeper.data.Stat; public class CuratorClientExample {
public static String CONNECTSTRING= "127.0.0.1:2181";
public static String PATH= "/crud";
public static String NAMESPACE= "fortest";
public static void main(String[] args) { RetryPolicy retryPolicy = new ExponentialBackoffRetry(1000, 3);
CuratorFramework client; // client= CuratorFrameworkFactory.newClient(CONNECTSTRING, retryPolicy); client=CuratorFrameworkFactory. builder().
connectString( CONNECTSTRING )
.connectionTimeoutMs(30000)
.sessionTimeoutMs(30000)
.canBeReadOnly( false ).retryPolicy(retryPolicy)
.namespace( NAMESPACE )
.defaultData( null )
.build();
client.start(); try {
client.create().forPath( PATH ,"hello world".getBytes());
byte [] bs=client.getData().forPath( PATH);
System. out .println("新建的节点,data为: " + new String(bs)); client.setData().forPath( PATH ,"hello china".getBytes());
// 由于是在background模式下获取的data,此时的 bs可能为null
byte [] bs2=client.getData().watched().inBackground().forPath( PATH);
System. out .println("新修改的节点,data为: " + new String(bs2!=null ? bs2 : new byte[0])); client.delete().forPath( PATH );
Stat stat=client.checkExists().forPath( PATH );
// Stat 就是对zonde所有属性的一个映射, stat=null表示节点不存在!
System. out .println(stat);
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
} finally {
CloseableUtils. closeQuietly(client);
}
}
}

参考资料:
- http://curator.apache.org/curator-framework/index.html
- http://supben.iteye.com/blog/2094077
- http://macrochen.iteye.com/blog/1366136

CuratorFramework使用的更多相关文章

  1. Zookeeper客户端 CuratorFramework使用

    CuratorFramework使用 跟着实例学习ZooKeeper的用法: Curator框架应用 ZooKeeper客户端Curator使用一 创建连接

  2. CuratorFramework入门指南

    CuratorFramework入门指南 原文地址:https://github.com/Netflix/curator/wiki/Getting-Started CuratorFramework作为 ...

  3. 【分布式技术专题】「Zookeeper中间件」给大家学习一下Zookeeper的”开发伴侣”—Curator-Framework(基础篇)

    CuratorFramework基本介绍 CuratorFramework是Netflix公司开源的一套Zookeeper客户端框架,它作为一款优秀的ZooKeeper客户端开源工具,主要提供了对客户 ...

  4. [译]ZOOKEEPER RECIPES-Leader Election

    选主 使用ZooKeeper选主的一个简单方法是,在创建znode时使用Sequence和Ephemeral标志.主要思想是,使用一个znode,比如"/election",每个客 ...

  5. [译]ZOOKEEPER RECIPES-Locks

    锁 全局式分布式锁要求任何时刻没有两个客户端会获得同一个锁对象,这可以通过使用ZooKeeper实现.像优先级队列一样,首先需要定义一个锁节点. 在ZooKepeer的发布中src/recipes/l ...

  6. [译]ZOOKEEPER RECIPES-Queues

    队列 分布式队列是一种常见的数据结构.为了在ZooKepeer中实现分布式队列,第一步是要使用一个znode代表队列本身.分布式客户端通过create()方法将内容放入一个名叫"queue- ...

  7. [译]ZOOKEEPER RECIPES-Barriers

    Barrier 在分布式系统中常使用Barrier来阻塞进程,当满足一定条件后再恢复进行后续操作.Barrier在Zookeeper中可以通过设计一个Barrier节点来实现.Barrier 节点存在 ...

  8. 【分布式】Zookeeper使用--开源客户端

    一.前言 上一篇博客已经介绍了如何使用Zookeeper提供的原生态Java API进行操作,本篇博文主要讲解如何通过开源客户端来进行操作. 二.ZkClient ZkClient是在Zookeepe ...

  9. Curator框架的使用

    Curator框架的目的是减少用户的复杂度,毕竟原生的Zookeeper难以使用. 这里举一个使用例子. 第一步:建立连接 // 以下代码与192.168.1.101:2181建立了连接Curator ...

随机推荐

  1. 【轻松前端之旅】元素,标记,属性,<html>标签

    HTML文档是由HTML元素定义的. HTML元素(element)指的是从开始标签(start tag)到结束标签(end tag)的所有代码. 有些元素会使用简写记法,如<img src=' ...

  2. Java第3章笔记

    if基本语法: if(条件){// 表达式   // 代码块   } eg:    int a = 10;    if(a > 1){  System.out.println("内容& ...

  3. PHP字符串转实体函数

    与HTML实体相关的函数 htmlspecialchars函数 描述:预定义的字符转换为HTML实体 语法:string htmlspecialchars(string $string [,int $ ...

  4. mysql 表锁进程非常多的情况

    今天要说的是mysql 的 MYISAM引擎下的表锁问题. 通常来说,在MyISAM里读写操作是串行的,但当对同一个表进行查询和插入操作时,为了降低锁竞争的频率,根据concurrent_insert ...

  5. 2018.12.05 codeforces 948C. Producing Snow(堆)

    传送门 维护一个堆. 每次先算出一个都不弹掉的总贡献. 然后把要弹掉的弹掉,并减去它们对应的贡献. 代码: #include<bits/stdc++.h> #define ri regis ...

  6. Livelock

    Unlike deadlock, livelocked packets continue to move through the network, but never reach their dest ...

  7. Interrouter Signals

    summary of traditional NoC interrouter signals summary of SMART interrouter signals flit_valid and f ...

  8. Linux下启动tomcat报错,WARN org.apache.zookeeper.ClientCnxn - Session 0x0 for server null, unexpected error, closing socket connection and attempting reconnect java.net.ConnectException:

    tomcat启动完了之后,一直不停的打印这种错误信息,看表面上,应该是zk节点下的数据是空的,连接不上服务,所以一直在尝试连接,然后一直又连不上: 完整的错误信息: 407662 [usf-ZooKe ...

  9. Codeforces Round #536 (Div. 2) B. Lunar New Year and Food Ordering

    #include <bits/stdc++.h> #define N 300010 #define PII pair<int, int> using namespace std ...

  10. Java 理论与实践: 用弱引用堵住内存泄漏

    弱引用使得表达对象生命周期关系变得容易了 虽然用 Java™ 语言编写的程序在理论上是不会出现“内存泄漏”的,但是有时对象在不再作为程序的逻辑状态的一部分之后仍然不被垃圾收集.本月,负责保障应用程序健 ...