ZooKeeper--动物园管理员,哈哈,管大象(Hadoop)、小猪(Pig)、蜂房(Hive)等的管理员。
ZooKeeper是一个协同工作(或称协作支持)系统,分布式应用可以使用ZooKeeper来存储和协调关键共享状态。
ZooKeeper保证用户读取的数据是最新的;当用户正在查看的数据被修改时,保证用户会被即时通知;保证来自一个用户的所有请求会被按顺序处理;保证所有用户得到的数据是一致的。
下面这个例子是在UDC(会员数据中心,即诺亚方舟项目)项目中真实代码,此时为说明的清楚些,添加了大量的注释。
/**
* @author zirou
* 注意ZooKeeper的Watcher由读操作(exists/getData/getChildren)来注册,由写操作(create/delete/setData)来触发。
*/
@Component("zookeeperCacheSynchronizer")
public class ZookeeperCacheSynchronizer implements Watcher,CacheSynchronizer {
private static finalLogger logger = LoggerFactory.getLogger(ZookeeperCacheSynchronizer.class);
private static finalString HOSTS_KEy = "cache.zookeeper.hosts";
private static finalString SESSION_TIMEOUT_KEy = "cache.zookeeper.sessionTimeout";
private volatile booleanconnected = false;
protected ZooKeeper zookeeper;
private Map<String,CacheReader> readers = new ConcurrentHashMap<String, CacheReader>();
private CountDownLatchconnectedSignal;
@Resource
private Map<String,String> configProperties;
private String hosts;
private intsessionTimeout;
/**
* 初始化,建立连接
* @throwsKeeperException
* @throwsInterruptedException
*/
@PostConstruct
public void initialize()throws KeeperException, InterruptedException {
hosts =configProperties.get(HOSTS_KEy);
sessionTimeout =Integer.valueOf(configProperties.get(SESSION_TIMEOUT_KEy));
if (!connected) {
connect();
}
}
/**
*建立连接:实例化一个新的ZooKeeper对象,且维护着客户端与ZooKeeper服务的链接。
* @throwsKeeperException
* @throwsInterruptedException
*/
public synchronized voidconnect() {
logger.info("ZookeeperCacheSynchronizer:connect");
if (!connected) {
try {
connectedSignal = new CountDownLatch(1);
//ZooKeeper构造函数有三个参数:1.是ZooKeeper服务的主机地址包括端口2.是会话超时时长
//3.是Watcher对象的实例。Watcher对象接受ZooKeeper的响应,并通知它各种事件。
// ZooKeeper客户端正是通过注册Watcher的方法来获取状态变化的信息。
zookeeper =new ZooKeeper(hosts, sessionTimeout, new DefaultWatcher());
//在使用zookeeper对象前,等待连接建立。这里利用Java的CountDownLatch类//(java.util.concurrent.CountDownLatch)来阻塞,直到zookeeper实例准备好。
connectedSignal.await();
connected =true;
connectedSignal = null;
} catch(Exception e) {
throw newRuntimeException(e);
}
}
}
public void ensurePathExists(finalString path) {
try {
if (!connected){
connect();
}
Stat stat =zookeeper.exists(path, false);
if (stat !=null) {
return;
}
zookeeper.create(path,new byte[]{1}, Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT);
} catch(KeeperException e) {
throw newRuntimeException(e);
} catch(InterruptedException e) {
throw newRuntimeException(e);
}
}
/**
*客户端连接到ZooKeeper服务之后,Watcher的process方法会被调用,并收到一个事件。
*
*
*/
@Override
public voidprocess(WatchedEvent event) {
logger.info("ZookeeperCacheSynchronizer:process, path:" +event.getPath());
//如果客户端收到的事件类型是NodeDataChanged,即被通知znode有改变,此时客户端就可执行具体的业务操作了。
if (event.getType()== EventType.NodeDataChanged) {
try {
byte[] b =zookeeper.getData(event.getPath(), this, null/* stat */);
if(this.readers != null && this.readers.containsKey(event.getPath())) {
readers.get(event.getPath()).onRead(b);
logger.info("reader was found, path:" + event.getPath());
} else {
logger.info("no reader found, path:" + event.getPath());
}
} catch(Exception e) {
throw newRuntimeException(e);
}
}
}
@Override
public voidregister(String path, CacheReader cachedReader) {
try {
ensurePathExists(path);
//注册watcher
zookeeper.getData(path, this, null/*stat*/);
} catch (Exceptione) {
throw newRuntimeException(e);
}
readers.put(path,cachedReader);
}
@Override
public voidsyncReloadCache(String path, byte[] data) {
logger.info("ZookeeperCacheSynchronizer:writeToZook