ZooKeeper技术内幕(一)

一、系统模型

1、数据模型

1)ZNode:是ZooKeeper中最小的数据单元,每个ZNode都可以保存数据和挂载子节点,构成一个层次化的命名空间,称为树。

2)事务ID:ZooKeeper中,事务指的是能够改变服务器状态的操作,,包括数据节点的创建与删除,数据节点内容变更等。对于每一个事务请求,ZooKeeper会为其分配一个全局唯一的事务ID,即ZXID,通常是一个64位的数字,每一个ZXID对应一次更新操作,从这些ZXID中可以间接地识别出ZooKeeper处理事务操作的全局顺序。

2、节点特性

1)节点类型:节点类型可以分为:持久节点、临时节点、顺序节点,可以通过组合使用,生成四种节点类型:持久节点、持久顺序节点、临时节点、临时顺序节点。

2)状态信息:每个数据节点除了存储数据内容之外,还存储了节点本身一些状态信息。ZooKeeper中Stat类包含了一个节点的所有状态信息,包括:czxid、mzxid、ctime、mtime、version、cversion、aversion、数据内容长度、子节点个数等。

3、版本--保证分布式数据原子性操作

ZooKeeper中的版本表示的是对数据节点的数据内容、子节点列表、ACL信息的修改次数,强调的是变更次数。每个数据节点都有三种类型的版本信息,对数据节点的任何更新操作都会引起版本号的变化。version指的是数据内容的版本号,cversion指的是子节点的版本号,aversion指的是ACL变更版本号。

ZooKeeper中version属性是用是基于乐观锁中的CAS来实现的。CAS指的是:对于值V,每次更新前都会对比其值是否是预期值A,只有符合预期值,才会将V原子化的更新到新值B,ZooKeeper中的version正是由CAS原理演化而来。ZooKeeper中每个节点都有数据版本的概念,在调用更新操作时,就可以添加version这个参数,该参数可以对应于CAS原理中的“预期值”,表明是针对该数据版本进行更新的。具体来说,假如一个客户端试图进行更新操作,他会携带上次获取到的version值进行更新。而如果在这段时间内,该数据被其他客户端更新了,那么它的数据版本也会被更新,因此与客户端携带的version不匹配,也就无法更新成功。所以这样可以避免一些分布式更新的并发问题。

4、Watcher--数据变更的通知

ZooKeeper允许客户端向服务端注册一个Watcher监听,当服务端的一些指定事件触发了这个Watcher,那么就会向指定客户端发送一个事件通知来实现分布式的通知功能。

Watcher机制包括:客户端线程、客户端WatchManager、服务器三部分。具体流程:客户端在向服务器注册Watcher的同时,会将Watcher对象存储在WatcherManager中。当服务端触发watcher事件后,会向客户端发送通知,客户端线程从WatcherManager中取出对应的Watcher对象执行回调逻辑。

Watcher接口类里有三个枚举类:KeeperState(通知状态)、EventType(事件类型)和WatcherType。KeeperState里有SyncConnected、Disconnected、Expired、AuthFailed等状态。EventType包括NodeCreated、NodeDeleted、NodeDataChanged、NodeChildrenChanged等事件类型。process()方法是一个回调方法,它的参数是WatchedEvent,WatchedEvent包含了每一个事件的三个基本属性:通知状态(keeperState)、事件类型(eventType)、节点路径(path)。服务端生成WatchedEvent事件后,调用它的getWrapper()方法将自己包装成一个可序列化的WatcherEvent事件,传输到客户端。客户端接收到之后,将WatcherEvent还原成WatchedEvent,并传递给process方法处理。

5、Watcher工作机制:

分为三个过程:客户端注册Watcher、服务端处理Watcher、客户端回调Watcher。

1)客户端注册Watcher:

创建ZooKeeper对象、getData、getChildren、exist时可以向服务端注册Watcher,这个Watcher保存在ZKwatchManager的defaultWatcher中。我以getData为例说明。getData接口注册Watcher后,会将Watcher和节点路径关系保存在WatchRegistration对象中。在ClientCnxn中,WatchRegistration被封装到Packet中,然后放到发送队列outgoingQueue中等待客户端发送。Packet是最小的通信协议单元,用于客户端与服务端之间网络传输,所有需要传输的对象都会被封装成一个Packet对象。之后,客户端发送这个请求,并等待服务端回应。

ClientCnxn的SendThead线程的readResponse方法接收来自服务端的响应,方法最后的finishPacket方法从Packet中取出对应的Watcher并注册到ZKWatchManager。在register方法中,将之前保存在WatchRegistration中Watcher和节点路径关系对应关系取出来,放到dataWatches中。

2)服务端处理Watcher

服务端接收到来自客户端的请求后,在FinalRequestProcessor的processRequest()中判断是否需要注册Watcher。如果需要,将ServerCnxn对象和路径传入getData方法中去,ServerCnxn可以看做是一个Watcher对象,ServerCnxn和数据节点路径最终被存储在WatchManager的watch2Paths和watchTable中。

WatchManager是服务端watcher的管理者。内部管理watchTable和watch2Paths两个存储结构,都是HashMap,watchTable从数据节点路径的角度来托管Watcher,watch2Paths从Watcher的力度控制时间触发需要触发的数据节点。还有,WatchManager还负责Watcher事件的触发,并移除那些已经被触发的Watcher。

Watcher触发在triggerWatch方法中进行,:①将EventType、节点路径、KeeperState封装成一个WatchedEvent对象;②根据节点路径从watchTable和watch2Path中取出watcher并删除;③调用process方法触发watcher,也就是之前ServerCnxn对应的process方法。

3)客户端回调Watcher

来自服务端的响应,由客户端的SendThread的readResponse()方法统一进行处理。

①反序列化,将字节流转换成WatcherEvent对象;②处理chrootPath,生成客户端的相对节点路径;③还原WatchedEvent,将watcherEvent转换成WatchedEvent对象;④回调Watcher,将WatchedEvent交给eventThread线程。

EventThread的queueEvent方法根据通知事件,识别事件类型,从ZKWatchManager中取出相关的Watcher,并删除,之后放入waitingEvents队列中,之后EventThread的run方法对该队列进行处理。

Watcher特性总结:

一次性:一旦一个Watcher被触发,ZooKeeper会将其从相应的存储中移除;

客户端串行执行:客户端watcher回调是一个串行同步的过程,保证顺序性;

轻量:WatchedEvent是整个Watcher通知机制的最小通知单元,只包含通知状态、事件类型、节点路径三部分。只告诉客户端发生了事件,不会说明事件的具体内容。

6、ACL--保障数据的安全

包含三个方面:权限模式(Scheme)、授权对象(ID)、权限(Permission)。

1)权限模式:Scheme

①IP:通过IP地址粒度进行权限控制

②Digest:最常用的权限控制模式

③World:最开放的权限控制模式

④Super:超级用户

2)授权对象:ID

3)权限:Permission

create、delete、read、write、admin

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值