zookeeper的坑(一)

都说zookeeper是保证顺序,但是保证啥顺序?

博文http://blog.csdn.net/kobejayandy/article/details/12432137中有句话

【但ZooKeeper保证了一个顺序:一个客户端在收到watch事件之前,一定不会看到它设置过watch的值的变动】

是不是只保证了这个顺序,这个顺序又该如何理解?

以前一会以为watcher是有序的,今天无意发现了一个奇怪现象。测试结果更令人诧异。源码在读。无赖水平有限,先做记录。


import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.curator.framework.CuratorFramework;
import org.apache.curator.framework.CuratorFrameworkFactory;
import org.apache.curator.framework.recipes.cache.PathChildrenCache;
import org.apache.curator.framework.recipes.cache.PathChildrenCache.StartMode;
import org.apache.curator.framework.recipes.cache.PathChildrenCacheEvent;
import org.apache.curator.framework.recipes.cache.PathChildrenCacheListener;
import org.apache.curator.retry.ExponentialBackoffRetry;
import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.service.AbstractService;

import com.suning.cybertron.superion.alarm.common.Const;

//避免zookeeper,state状态的时候,已经被删除了。
public class ZkTest extends AbstractService {

	private static final Log LOG = LogFactory.getLog(ZkTest.class);

	private CuratorFramework client = null;

	private PathChildrenCache cache = null;

	public ZkTest(String name) {
		super(name);
	}

	public CuratorFramework getClient() {
		return client;
	}

	@Override
	protected void serviceInit(Configuration conf) throws Exception {
		//Thread.sleep(5*60*1000);
		//等待内存信息同步,否则CHILD_ADDED 无法改变jsm状态,造成CHILD_REMOVED 后台Error Invalid event: JOBINSTANCE_xxxx at NEW
		//就算如此也会有其他bug,eg:用户添加一组监控信息,你CHILD_ADDED已经执行,只能监控到CHILD_REMOVED事件了,一样会有上面异常
		client = CuratorFrameworkFactory.newClient(Const.ZK_MONITOR_ADDR,
				new ExponentialBackoffRetry(1000, 3));
		client.start();
		cache = new PathChildrenCache(client, "/t", true);
		addRootDirListener(cache);
		cache.start(StartMode.NORMAL);// 开始为空,监听所有znode
		// cache.start(StartMode.POST_INITIALIZED_EVENT);//原有和后更新之间插入INITIALIZED,貌似INITIALIZED不是每次都提交
		// cache.start(StartMode.BUILD_INITIAL_CACHE);//只监听初始化不存在的(后更新)的znode
		super.serviceInit(conf);
	}

	@Override
	protected void serviceStop() throws Exception {
		cache.close();
		client.close();
		super.serviceStop();
	}

	private void addRootDirListener(PathChildrenCache cache) {
		PathChildrenCacheListener listener = new PathChildrenCacheListener() {
			@Override
			public void childEvent(CuratorFramework client,
					PathChildrenCacheEvent event) throws Exception {
				String zkPath = event.getData().getPath();
				switch (event.getType()) {
					case CHILD_ADDED: {
						LOG.info("zk:[path] ADD_WATCHER:" + zkPath); //*********我在这里debug***********
						return;
					}
					case CHILD_REMOVED: {
						LOG.info("zk:[path] REMOVE_WATCHER:" + zkPath );
						return;
					}
					default:{
						return;
					}
				}
			}
		};
		cache.getListenable().addListener(listener);
	}

	
	public static void main(String[] args) {
		ZkTest zkTest = new ZkTest("ZkTest");
		try {
			zkTest.serviceInit(new Configuration());
			Thread.sleep(Integer.MAX_VALUE);
		} catch (Exception e) {
			e.printStackTrace();
		}
	}
}

zkCli.sh执行

[zk: localhost:2181(CONNECTED) 61] ls /t
[]
[zk: localhost:2181(CONNECTED) 62] create /t/1 "1"
Created /t/1
[zk: localhost:2181(CONNECTED) 63] create /t/2 "1"
Created /t/2
[zk: localhost:2181(CONNECTED) 64] create /t/3 "1"
Created /t/3
[zk: localhost:2181(CONNECTED) 65] create /t/4 "1"
Created /t/4
[zk: localhost:2181(CONNECTED) 66] create /t/5 "1"
Created /t/5
[zk: localhost:2181(CONNECTED) 67] create /t/6 "1"
Created /t/6
[zk: localhost:2181(CONNECTED) 68] create /t/7 "1"
Created /t/7
[zk: localhost:2181(CONNECTED) 69] create /t/8 "1"
Created /t/8
[zk: localhost:2181(CONNECTED) 70] ls /t
[3, 2, 1, 7, 6, 5, 4, 8]

放开debug,Console输出:

2016-04-14 16:03:18,474 INFO  [PathChildrenCache-0] alarm.ZkTest (ZkTest.java:childEvent(65)) - zk:[path] ADD_WATCHER:/t/3
2016-04-14 16:03:18,672 INFO  [PathChildrenCache-0] alarm.ZkTest (ZkTest.java:childEvent(65)) - zk:[path] ADD_WATCHER:/t/2
2016-04-14 16:03:19,345 INFO  [PathChildrenCache-0] alarm.ZkTest (ZkTest.java:childEvent(65)) - zk:[path] ADD_WATCHER:/t/1
2016-04-14 16:03:19,549 INFO  [PathChildrenCache-0] alarm.ZkTest (ZkTest.java:childEvent(65)) - zk:[path] ADD_WATCHER:/t/7
2016-04-14 16:03:19,735 INFO  [PathChildrenCache-0] alarm.ZkTest (ZkTest.java:childEvent(65)) - zk:[path] ADD_WATCHER:/t/6
2016-04-14 16:03:19,929 INFO  [PathChildrenCache-0] alarm.ZkTest (ZkTest.java:childEvent(65)) - zk:[path] ADD_WATCHER:/t/5
2016-04-14 16:03:20,102 INFO  [PathChildrenCache-0] alarm.ZkTest (ZkTest.java:childEvent(65)) - zk:[path] ADD_WATCHER:/t/4
2016-04-14 16:03:20,300 INFO  [PathChildrenCache-0] alarm.ZkTest (ZkTest.java:childEvent(65)) - zk:[path] ADD_WATCHER:/t/8

本来debug阻塞别的watcher就很奇怪,看了源码中存在:

    public PathChildrenCache(CuratorFramework client, String path, boolean cacheData)
    {
        this(client, path, cacheData, false, new CloseableExecutorService(Executors.newSingleThreadExecutor(defaultThreadFactory), true));
    }

既然是单线程,也算好理解,但顺序为什么那么乱?





评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值