会话
Session是指客户端会话,在讲解客户端会话之前,我们先来了解下客户端连接。在ZooKeeper中,一个客户端连接是指客户端和ZooKeeper服务器之间的TCP长连接。ZooKeeper对外的服务端口默认是2181,客户端启动时,首先会与服务器建立一个TCP连接,从第一次连接建立开始,客户端会话的生命周期也开始了,通过这个连接,客户端能够通过心跳检测和服务器保持有效的会话,也能够向ZooKeeper服务器发送请求并接受响应,同时还能通过该连接接收来自服务器的Watch事件通知。Session的SessionTimeout值用来设置一个客户端会话的超时时间。当由于服务器压力太大、网络故障或是客户端主动断开连接等各种原因导致客户端连接断开时,只要在SessionTimeout规定的时间内能够重新连接上集群中任意一台服务器,那么之前创建的会话仍然有效。
zookeeper数据模型
zookeeper中主要是采用类似文件系统或者说树的结构模式作为数据模型,命名符合常规文件系统规范,每个目录称zNode节点,并且会有一个唯一的路径标识。
每个znode还可以包含数据和子节点znode,临时的节点不能有子节点。同时,znode中的数据还带有多个版本,所以查询的时候需要带上该版本号。 客户端还可以设置该节点是否设置watcher,来监视它。
关于watcher不清楚的可以看我的这篇文章:
//todo
节点类型与特性
zookeeper的节点是有生命周期的,因此节点的类型能决定不同的生命周期。其类型分为:
1.持久化节点(Persistent)
2.临时节点(EPHEMERAL)
3.顺序节点(SEQUENTIAL )
更具体地在节点地创建中,一般都会组合使用,所以能生成以下四种类型:
1.持久节点(PERSISTENT)
持久节点就是指节点创建后,无论客户端地会话是否还存在或失效就消失,除非主动删除。
2.持久顺序节点(PERSISTENT_SEQUENTIAL)
这种节点作为父节点都会为它的子节点维护一个时序,会记录每个子节点创建的先后顺序。客户端可以根据这个特性,在创建的时候设置这个属性,来作为新的节点名。这个数字的后缀的上限是整形的最大值。
3.临时节点(EPHEMERAL)
这个与持久化节点正好相反,生命周期是根据客户端的会话进行绑定的。如果会话失效,而不是连接断开,就会失效。另外临时节点不能创建子节点。
4.临时顺序节点(EPHEMERAL_SEQUENTIAL)
临时顺序节点的特性和临时节点一致,同时是在临时节点的基础上,添加了顺序的特性。
关于节点的状态
每个节点都是有状态的,zookeeper会为每个节点维护以下的一些状态信息,可以通过get来获得。
czxid:创建节点的事务的zxid
mzxid:对znode最近修改的zxid
ctime:以距离时间原点(epoch)的毫秒数表示的znode创建时间
mtime:以距离时间原点(epoch)的毫秒数表示的znode最近修改时间
version:znode数据的修改次数
cversion:znode子节点修改次数
aversion:znode的ACL修改次数
ephemeralOwner:如果znode是临时节点,则指示节点所有者的会话ID;如果不是临时节点,则为零。
dataLength:znode数据长度。
numChildren:znode子节点个数。
关于节点的版本===可以保证分布式数据的原子操作
Zookeeper会为每个Znode维护一个叫作Stat的数据结构,结构如图:存在三个版本信息:
version:znode数据的修改次数
cversion:znode子节点修改次数
aversion:znode的ACL修改次数
version是表示对数据节点数据内容的变更次数,强调的是变更次数,因此就算数据内容的值没有发生变化,version的值也会递增。
Zookeeper的版本作用就是类似于乐观锁机制,用于实现乐观锁机制的“写入校验”.看源码:
从上边的逻辑,我们可以看到,当对数据节点状态进行改变时,首先要进行数据节点版本检查,如果首先获得当前请求的版本,然后再从数据积累获取当前服务器上该数据的最新版本,如果version=-1,则客户端不要求使用乐观锁,可以忽略此版本检查,如果不是-1,就进行检查,匹配才进行数据变更,否则抛出异常。
总之在我看来就是使用乐观锁的写入校验,获取到的版本号跟自己的对比,相等就加一,有点类似CAS算法。