wjy0 2019-07-01
具体将在后续的文章中给出具体的应用介绍。
在介绍数据节点之前,先给大家说明一下zk中事务的概念。zk中的事务指的是能够改变zk服务器状态的操作,包括
zk中还有一个事务id的概念,会为每次事务请求分配一个全局唯一的id,关于事务id的特点简要说明如下:
zk中的数据节点是有生命周期的概念的,根据生命周期的不同可以划分为两种类型的节点
最常见的一种节点类型,也叫做regular节点。数据节点一旦被创建,就会一直存在于zk服务器上,直到有删除事务操作主动清除该节点
临时节点的生命周期是和客户端会话绑定在一起的,只要客户端会话失效,那么临时节点就会被清除。这里的客户端会话失效和客户端tcp连接断开是不一样的。
临时节点只能是leaf节点
zk会给创建的节点自动加上一个数字后缀,作为一个完整的节点名称,这种方式可以维护节点之间的一种顺序性
数据节点的类结构代码如下:
public class DataNode implements Record {
byte data[]; //节点上存储的数据
Long acl; //权限控制列表版本号
public StatPersisted stat; //节点状态信息
private Set<String> children = null; //节点的子节点列表
}StatPersisted stat是该节点的状态信息类,类结构代码如下:
public class StatPersisted implements Record {
private long czxid; //创建该节点的事务id
private long mzxid; //最后一次修改节点的事务id
private long ctime; //节点的创建时间
private long mtime; //最后一次更新节点内容的时间
private int version; //数据节点的版本号,version=0表示该节点被创建之后,更新过0次,在实现乐观锁的时候有用
private int cversion; //子节点的版本号,只有当子节点列表被更改后,才会+1
private int aversion; //子节点的acl列表版本号
private long ephemeralOwner; //如果是临时节点,该值表示创建该节点的临时会话的sessionID,如果是持久节点的话,该值为0
private long pzxid; //子节点列表最后一次被修改时的事务id,一定是子节点列表被修改,子节点的内容被修改是不会改变这个属性的值的
}zk中的事件监听机制由三部分组成:
客户端线程在zk服务器上注册事件监听之后,会将这个watcher对象存储在WatcherManager中,当zk服务器触发这个事件之后,会向客户端发送通知,客户端线程会从WatcherManager中取出对应的Watcher对象来执行回调逻辑。
public interface Watcher{
public interface Event{
public enum KeeperState{
Disconnected(0), //断开连接
SyncConnected(3), //此时客户端与zk服务器处于连接状态
AuthFailed(4), //权限检查失败
ConnectedReadOnly(5) //客户端和一台只读server处于连接状态,what is readonly server? 就是只和集群中的一小部分服务器处于连接的服务器
Expired(-122) //会话超时
}
public enum EventType{
None (-1),
NodeCreated (1), //watcher监听的数据节点被创建
NodeDeleted (2), //watcher监听的数据节点被删除
NodeDataChanged (3), //watcher监听的数据节点内容被更新
NodeChildrenChanged (4), //watcher监听的数据节点的子节点列表被更新了
DataWatchRemoved (5),
ChildWatchRemoved (6);
}
}
public enum WatcherType{
Children (1),
Data (2),
Any (3);
}
abstract public void process(WatchedEvent event);
}主要有以下几个部分组成
在处理监听事件的回调函数process中,参数event是一个org.apache.zookeeper.WatchedEvent类型的参数。WatchedEvent说明如下
public class WatchedEvent {
final private KeeperState keeperState; //通知的状态
final private EventType eventType; //事件类型
private String path; //参与该事件的节点路径
/**
*实现WatchedEvent到WatcherEvent的转换
*/
public WatcherEvent getWrapper() {
return new WatcherEvent(eventType.getIntValue(),
keeperState.getIntValue(),
path);
}
/**
*实现WatcherEvent到WatchedEvent的转换
*/
public WatchedEvent(WatcherEvent eventMessage) {
keeperState = KeeperState.fromInt(eventMessage.getState());
eventType = EventType.fromInt(eventMessage.getType());
path = eventMessage.getPath();
}
}从WatchedEvent的代码中可以看出一个监听事件由三个部分组成的:
并且,与WatchedEvent对应的还有一个类WatcherEvent,这个WatcherEvent和WatchedEvent相比,只是实现了序列化,方便通过网络在服务端和客户端之间传输。
序列化使用的是jute
客户端接受到的服务器传送过来的监听事件的格式如下:
KeeperState:SyncConnected EventType:NodeDataChanged Path: /zk-book
显然,从接收到的事件中,客户端是无法获取到该节点在更新前后的数据的,因此客户端是要主动再向服务器获取数据。因此,使用zk的监听机制实现的发布订阅系统使用的"推拉"结合的方式。
ZooKeeper支持某些特定的四字命令字母与其的交互。它们大多是查询命令,用来获取ZooKeeper服务的当前状态及相关信息。用户在客户端可以通过telnet或nc向ZooKeeper提交相应的命令