Zookeeper ---- Curator 框架应用


CuratorFramework

     Curator框架提供了一套高级的API, 简化了ZooKeeper的操作。 它增加了很多使用ZooKeeper开发的特性,可以处理ZooKeeper集群复杂的连接管理和重试机制。 这些特性包括:

     1. 自动化的连接管理: 重新建立到ZooKeeper的连接和重试机制存在一些潜在的错误case。 Curator帮助你处理这些事情,对你来说是透明的。
     2. 清理API:
* 简化了原生的ZooKeeper的方法,事件等
* 提供了一个现代的流式接口

     3. 提供了Recipes实现,基于这些Recipes可以创建很多复杂的分布式应用

     Zookeeper在实际生产环境中应用比较广泛, 比如SOA的服务监控系统, hadoop, spark的分布式调度系统. Curator框架提供的优秀特性可以使得我们更加便捷的开发zookeeper应用.


CuratorFramework 实例创建

     Curator框架通过CuratorFrameworkFactory以工厂模式和builder模式创建CuratorFramework实例.
CuratorFramework实例都是线程安全的, 我们应该当在Zookeeper Cluster中共享同一个CuratorFramework实例. 工厂方法newClient()提供了简便创建client实例方式,而Builder提供了更多的参数控制。一旦你创建了一个CuratorFramework实例,你必须调用它的start()启动,在应用退出时调用close()方法关闭.

本实例所执行代码有maven进行包依赖管理.
pom.xml如下
<!-- zk framework curator start-->	
<!-- https://mvnrepository.com/artifact/org.apache.curator/curator-recipes -->
<dependency>
    <groupId>org.apache.curator</groupId>
    <artifactId>curator-recipes</artifactId>
    <version>2.8.0</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.apache.curator/curator-client -->
<dependency>
    <groupId>org.apache.curator</groupId>
    <artifactId>curator-client</artifactId>
    <version>2.8.0</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.apache.curator/curator-framework -->
<dependency>
    <groupId>org.apache.curator</groupId>
    <artifactId>curator-framework</artifactId>
    <version>2.8.0</version>
</dependency>
<!-- zk framework curator end-->	


下面演示了两种创建Curator的方法:
//第一种方法: 工厂模式
//arg1: 重试时间间隔, arg2: 重试最大次数
RetryPolicy retryPolicy = new ExponentialBackoffRetry(1000,3);
CuratorFramework client = CuratorFrameworkFactory.newClient("localhost:2181",retryPolicy);
client.start();

//第二种方法: builder模式
CuratorFramework client =  CuratorFrameworkFactory.builder().connectString(zkAddress)
        .retryPolicy(new ExponentialBackoffRetry(1000, 3))
        .connectionTimeoutMs(1000)
        .sessionTimeoutMs(1000)
        // etc. etc.
        .build();
	    client.start();

完整代码
package com.nxcjh.hadoop.examples.zookeeper.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;

public class CreateClientExample {
    private static final String PATH = "/example/basic";
    private static final String ZKADDRESS = "10.17.110.25:2181,10.17.110.32:2181,10.17.110.36:2181";

    public static void main(String[] args) throws Exception {

        CuratorFramework client = null;
        try {
        	//1. 工厂模式
            client = createSimple(ZKADDRESS);
            client.start();
            client.create().creatingParentsIfNeeded().forPath(PATH, "test".getBytes());
            CloseableUtils.closeQuietly(client);

            //2. builer模式
            client = createWithOptions(ZKADDRESS, new ExponentialBackoffRetry(1000, 3), 1000, 1000);
            client.start();
            System.out.println(new String(client.getData().forPath(PATH)));
            
        } catch (Exception ex) {
            ex.printStackTrace();
        } finally {
            CloseableUtils.closeQuietly(client);
            CloseableUtils.closeQuietly(client);
        }

    }

    /**
     * 工厂方法
     * @param connectionString
     * @return
     */
    public static CuratorFramework createSimple(String connectionString) {
        ExponentialBackoffRetry retryPolicy = new ExponentialBackoffRetry(1000, 3);
        return CuratorFrameworkFactory.newClient(connectionString, retryPolicy);
    }
    
    
    /**
     * builder 模式
     * @param connectionString
     * @param retryPolicy
     * @param connectionTimeoutMs
     * @param sessionTimeoutMs
     * @return
     */
    public static CuratorFramework createWithOptions(String connectionString, RetryPolicy retryPolicy, int connectionTimeoutMs, int sessionTimeoutMs) {
        return CuratorFrameworkFactory.builder().connectString(connectionString)
                .retryPolicy(retryPolicy)
                .connectionTimeoutMs(connectionTimeoutMs)
                .sessionTimeoutMs(sessionTimeoutMs)
                // etc. etc.
                .build();
    }
}

操作数据节点

      zookeeper中, 节点的组织类似于linux的文件系统, 使用path来标识每个节点(znode), znode作为保存数据的容器, 数据量限制在1M以内, 这部分介绍如何使用curator框架创建, 获取, 更新一集删除节点.Curator框架提供了一种流式接口. 操作通过builder串联起来, 这样方法调用类似语句如下:
client.create().forPath("/head", new byte[0]);
client.delete().inBackground().forPath("/head");
client.create().withMode(CreateMode.EPHEMERAL_SEQUENTIAL).forPath("/head/child", new byte[0]);
client.getData().watched().inBackground().forPath("/test");


CuratorFramework提供的方法

方法名 描述
create()开始创建操作, 可以调用额外的方法(比如方式mode 或者后台执行background) 并在最后调用forPath()指定要操作的ZNode
delete()开始删除操作. 可以调用额外的方法(版本或者后台处理version or background)并在最后调用 forPath()指定要操作的ZNode
checkExists()                                  开始检查ZNode是否存在的操作. 可以调用额外的方法(监控或者后台处理)并在最后调用forPath()指定要操作的ZNode
getData()开始获得ZNode节点数据的操作. 可以调用额外的方法(监控、后台处理或者获取状态watch, background or get stat) 并在最后调用forPath()指定要操作的ZNode
setData()开始设置ZNode节点数据的操作. 可以调用额外的方法(版本或者后台处理) 并在最后调用forPath()指定要操作的ZNode
getChildren() 开始获得ZNode的子节点列表。 以调用额外的方法(监控、后台处理或者获取状态watch, background or get stat) 并在最后调用forPath()指定要操作的ZNode
inTransaction()                 开始是原子ZooKeeper事务. 可以复合create, setData, check, and/or delete 等操作然后调用commit()作为一个原子操作提交


具体实现代码如下
package com.nxcjh.hadoop.examples.zookeeper.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.zookeeper.CreateMode;

/**
 * 
 * zk 客户端框架测试
 * @author 
 *
 */
public class CuratorTest {

	 private static final String zkAddress = "10.17.110.25:2181,10.17.110.32:2181,10.17.110.36:2181";
	 private static CuratorFramework client = null;

	 
	 /**
	  * 初始化客户端连接
	  */
	 public void setup(){
		 RetryPolicy retryPolicy = new ExponentialBackoffRetry(1000, 3);
		 client = CuratorFrameworkFactory.newClient(zkAddress, retryPolicy);
		 client.start();
		 System.out.println("客户端连接成功...");
	 }
	 
	 public void init(){
        client =  CuratorFrameworkFactory.builder().connectString(zkAddress)
            .retryPolicy(new ExponentialBackoffRetry(1000, 3))
            .connectionTimeoutMs(1000)
            .sessionTimeoutMs(1000)
            // etc. etc.
            .build();
        client.start();
	 }
	 
	 /**
	  * 创建节点
	  * @param client
	  * @param path
	  * @param createMode
	  * @param data
	  */
	 public void createNode(String path,CreateMode createMode,String data){
		 try {
			String res = client.create().withMode(createMode).forPath(path,data.getBytes());
			System.out.println("创建'"+res+"'节点成功!");
		} catch (Exception e) {
			System.out.println("创建节点失败,elog="+e.getMessage());
		}
	 }
	 
	 /**
	  * 获取节点数据
	  * @param client
	  * @param path
	  * @return
	  */
	 public String getNodeData(String path){
		String res = null;
		try {
			res =  new String(client.getData().forPath(path));
			System.out.println("获取节点数据成功:"+res);
		} catch (Exception e) {
			System.out.println("获取数据失败,elog="+e.getMessage());
		}
		return res;
	 }
	 
	 
	 /**
	  * 更新节点数据
	  * @param path
	  * @param data
	  */
	 public void updateNodeDate(String path,String data){
		 try {
			client.setData().forPath(path,data.getBytes());
			System.out.println("更新节点数据成功!");
		} catch (Exception e) {
			System.out.println("更新数据失败,elog="+e.getMessage());
		}
	 }
	 
	 
	 /**
	  * 删除节点
	  * @param client
	  * @param path
	  */
	  public void delNode(String path){
		  try {
			client.delete().forPath(path);
			System.out.println("删除节点成功!");
		} catch (Exception e) {
			System.out.println("删除节点失败,elog="+e.getMessage());
		}
	  }
	  
	  /**
	   * 关闭客户端
	   */
	  public void close(){
		  client.close();
		  System.out.println("客户端关闭....");
	  }
	  
	  
	  public static void main(String[] args) throws Exception {
		  CuratorTest curator = new CuratorTest();
		  //工厂模式创建
		  curator.setup();
		  //builder模式创建
//		  curator.init();
//		  //创建节点
//		  curator.createNode("/my/zktest", CreateMode.PERSISTENT, "hello curator");
//		  //获取节点
//		  System.out.println(curator.getNodeData("/my/zktest"));
//		  //更新节点
//		  curator.updateNodeDate("/my/zktest", "hello tx");
//		  System.out.println(curator.getNodeData("/my/zktest"));
//		  //删除节点
		  curator.delNode("/my/zktest");
		  curator.close();
		  
	  }
}


zookeeper中节点有两种类型, 临时节点和永久节点, CreateMode类用于指定创建节点的类型, 用户可以选择以下几个参数:
    1. CreateMode.PERSISTENT: 创建节点后, 不删除就永久存在;
    2. CreateMode.PERSISTENT_SEQUENTIAL: 节点path末尾会追加一个10位数的单调递增的序列;
    3. CreateMode.EPHEMERAL: 创建后, 会话结束后会自动删除;
    4. CreateMode.EPHEMERAL_EQUENTAIL: 节点path末尾会追加一个10位数的单调递增的序列.

    forPath函数指定创建节点的path和保存的数据,path的指定遵循linux文件path格式,创建node时指定的path,父path节点需要存在,否则创建节点失败,比如创建"/parent/child"节点,若不存在节点"parent",那么创建节点会失败。在znode中保存的数据需要进行序列化,用户可以选择使用JSON,XML,java内置的序列化机制,或者Hession以及Google的protocal Buffer等,为方便讲解,节点存储字符串数据。

    后台操作的通知和监控可以通过ClientListener接口发布, 你可以在CuratorFramework实例上通过addListener()注册listener, Listener实现了下面的方法:
    * eventReceived(): 一个后台操作完成或者一个监控被触发.
事件类型以及事件的方法如下
Event Type Event Methods
CREATEgetResultCode() and getPath()
DELETEgetResultCode() and getPath()
EXISTSgetResultCode(), getPath() and getStat()
GETDATAgetResultCode(), getPath(), getStat() and getData()
SETDATAgetResultCode(), getPath() and getStat()
CHILDRENgetResultCode(), getPath(), getStat(), getChildren()
WATCHEDgetWatchedEvent()

还可以通过ConnectionStationStateListener接口监控连接的状态. 强烈推荐增加这个监控器.

你还可以使用命名空间NameSpace避免多个应用的节点的名称冲突. CuratorFramework提供了命名空间的概念, 这样CuratorFramework会为它的API调用的path加上命名空间.
CuratorFramework    client = CuratorFrameworkFactory.builder().namespace("MyApp") ... build();
 ...
client.create().forPath("/test", data);
// node was actually written to: "/MyApp/test"

Curator还提供了临时的CuratorFramework: CuratorTempFramework, 一定时间不活动后连接会被关闭.
创建builder时不是调用build(), 而是调用buildTemp(). 3分钟不活动连接就被关闭, 你也可以指定不活动的时间, 它提供了下面几个方法:
public void close();
public CuratorTransaction inTransaction() throws Exception;
public TempGetDataBuilder getData() throws Exception;

事物

CuratorFramework提供了事务的概念, 可以将一组操作放在一个原子事物中. 什么叫事物? 事物是原子的, 一组操作要么都成功, 要么都失败.
下面的例子演示了事物的操作:
package com.nxcjh.hadoop.examples.zookeeper.curator;

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 {
        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!

        for (CuratorTransactionResult result : results) {
            System.out.println(result.getForPath() + " - " + result.getType());
        }
        return results;
    }

    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();
    }
}





评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

小狼躲藏

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值