zookeeper framework 之 Netflix curator

zookeeper framework 之 Netflix curator(完美支持永久监听)

介绍

curator是Netflix公司开源的zookeeper client library
官方地址:https://github.com/Netflix/curator/wiki/Recipes
详细介绍1:http://macrochen.iteye.com/blog/1366136/
详细介绍2:http://blog.csdn.net/alivetime/article/details/7101014
Curator主要解决了三类问题:

  • 封装ZooKeeper client与ZooKeeper server之间的连接处理;
  • 提供了一套Fluent风格的操作API;
  • 提供ZooKeeper各种应用场景(recipe, 比如共享锁服务, 集群领导选举机制)的抽象封装.

Curator几个组成部分

  • Client: 是ZooKeeper客户端的一个替代品, 提供了一些底层处理和相关的工具方法.
  • Framework: 用来简化ZooKeeper高级功能的使用, 并增加了一些新的功能, 比如管理到ZooKeeper集群的连接, 重试处理
  • Recipes: 实现了通用ZooKeeper的recipe, 该组件建立在Framework的基础之上
  • Utilities:各种ZooKeeper的工具类
  • Errors: 异常处理, 连接, 恢复等.
  • Extensions: recipe扩展

maven dependency

<dependency>
    <groupId>com.netflix.curator</groupId>
    <artifactId>curator-recipes</artifactId>
    <version>1.3.3</version>
</dependency>

curator framework 使用

String path = "/test_path";

CuratorFramework client = CuratorFrameworkFactory.builder()
        .connectString("test:2181").namespace("/test1")
        .retryPolicy(new RetryNTimes(Integer.MAX_VALUE, 1000))
        .connectionTimeoutMs(5000).build();

// start
client.start();

// create a node
client.create().forPath("/head", new byte[0]);

// delete a node in background
client.delete().inBackground().forPath("/head");

// create a EPHEMERAL_SEQUENTIAL
client.create().withMode(CreateMode.EPHEMERAL_SEQUENTIAL).forPath("/head/child", new byte[0]);

// get the data 
client.getData().watched().inBackground().forPath("/test");

// check the path exits
client.checkExists().forPath(path);

InterProcessMutex(进程间互斥锁)

String lockName = "/lock1";
InterProcessLock lock1 = new InterProcessMutex(this.curator, lockName);
InterProcessLock lock2 = new InterProcessMutex(this.curator, lockName);
lock1.acquire();
boolean result = lock2.acquire(1, TimeUnit.SECONDS);
assertFalse(result);
lock1.release();
result = lock2.acquire(1, TimeUnit.SECONDS);
assertTrue(result);

原理:每次调用acquire在lock1节点下使用createMode.EPHEMERAL_SEQUENTIAL创建的ephemeral节点,然后getChildren获取所有的children,判断刚刚创建的临时节点是否为第一个,如果是,则获取锁成功;如果不是则删除刚刚创建的临时节点。
注意:每次accquire操作,成功则请求zkserver 2次,一次写,一次getChildren;如果失败则请求zkserver三次(一次写,一次getChildren,一次删除)

InterProcessReadWriteLock(节点读写锁)

示例

	@Test
	public void testReadWriteLock() throws Exception{
		String readWriteLockPath = "/RWLock";
		InterProcessReadWriteLock readWriteLock1 = new InterProcessReadWriteLock(this.curator, readWriteLockPath);
		InterProcessMutex writeLock1 = readWriteLock1.writeLock();
		InterProcessMutex readLock1 = readWriteLock1.readLock();
		
		InterProcessReadWriteLock readWriteLock2 = new InterProcessReadWriteLock(this.curator, readWriteLockPath);
		InterProcessMutex writeLock2 = readWriteLock2.writeLock();
		InterProcessMutex readLock2 = readWriteLock2.readLock();
		writeLock1.acquire();
		
		// same with WriteLock, can read
		assertTrue(readLock1.acquire(1, TimeUnit.SECONDS));
		
		// different lock, can't read while writting
		assertFalse(readLock2.acquire(1, TimeUnit.SECONDS));
		
		// different write lock, can't write
		assertFalse(writeLock2.acquire(1, TimeUnit.SECONDS));
		
		// release the write lock
		writeLock1.release();
		
		//both read lock can read
		assertTrue(readLock1.acquire(1, TimeUnit.SECONDS));
		assertTrue(readLock2.acquire(1, TimeUnit.SECONDS));
	}

原理: 同InterProcessMutext,在ephemeral node的排序算法上做trick,write lock的排序在前。
注意: 同一个InterProcessReadWriteLock如果已经获取了write lock,则获取read lock也会成功

LeaderSelector(leader 选举)

	@Test
	public void testLeader() throws Exception{
		LeaderSelectorListener listener = new LeaderSelectorListener(){


			@Override
			public void takeLeadership(CuratorFramework client)
					throws Exception {
				System.out.println("i'm leader");
			}

			@Override
			public void handleException(CuratorFramework client,
					Exception exception) {
				
			}

			@Override
			public void notifyClientClosing(CuratorFramework client) {
				
			}};
		String leaderPath = "/leader";
		LeaderSelector selector1 = new LeaderSelector(this.curator, leaderPath, listener);
		selector1.start();
		LeaderSelector selector2 = new LeaderSelector(this.curator, leaderPath, listener);
		selector2.start();
		assertFalse(selector2.hasLeadership());
	}

原理:内部基于InterProcessMutex实现

NodeCache(监听节点数据)

/**
 * 在注册监听器的时候,如果传入此参数,当事件触发时,逻辑由线程池处理
 */
ExecutorService pool = Executors.newFixedThreadPool(2);

/**
 * 监听数据节点的变化情况
 */
final NodeCache nodeCache = new NodeCache(client, "/zk-huey/cnode", false);
nodeCache.start(true);
nodeCache.getListenable().addListener(
    new NodeCacheListener() {
        @Override
        public void nodeChanged() throws Exception {
            System.out.println("Node data is changed, new data: " + 
                new String(nodeCache.getCurrentData().getData()));
        }
    }, 
    pool
);

PathChildrenCache(监听子节点目录变化)

/**
 * 监听子节点的变化情况
 */
final PathChildrenCache childrenCache = new PathChildrenCache(client, "/zk-huey", true);
childrenCache.start(StartMode.POST_INITIALIZED_EVENT);
childrenCache.getListenable().addListener(
    new PathChildrenCacheListener() {
        @Override
        public void childEvent(CuratorFramework client, PathChildrenCacheEvent event)
                throws Exception {
                switch (event.getType()) {
                case CHILD_ADDED:
                    System.out.println("CHILD_ADDED: " + event.getData().getPath());
                    break;
                case CHILD_REMOVED:
                    System.out.println("CHILD_REMOVED: " + event.getData().getPath());
                    break;
                case CHILD_UPDATED:
                    System.out.println("CHILD_UPDATED: " + event.getData().getPath());
                    break;
                default:
                    break;
            }
        }
    },
    pool
);
posted @ 2016-06-01 19:13  逸新  阅读(2120)  评论(0编辑  收藏  举报