都说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));
}
既然是单线程,也算好理解,但顺序为什么那么乱?