操作 Operations
下面的表格中列出了9种ZooKeeper的操作。
操作 | 说明 |
---|---|
create | Creates a znode (the parent znode must already exist) |
delete | Deletes a znode (the znode must not have any children) |
exists | Tests whether a znode exists and retrieves its metadata |
getACL, setACL | Gets/sets the ACL for a znode |
getChildren | Gets a list of the children of a znode |
getData, setData | Gets/sets the data associated with a znode |
sync | Synchronizes a client’s view of a znode with ZooKeeper |
调用delete
和setData
操作时,我们必须指定一个znode版本号(version number),即我们必须指定我们要删除或者更新znode数据的哪个版本。如果版本号不匹配,操作将会失败。失败的原因可能是在我们提交之前,该znode已经被修改过了,版本号发生了增量变化。那么我们该怎么办呢?我可以考虑重试,或者调用其他的操作。例如,我们提交更新失败后,可以重新获取znode当前的数据,看看当前的版本号是什么,再做更新操作。
ZooKeeper虽然可以被看作是一个文件系统,但是由于ZooKeeper文件很小,所以没有提供像一般文件系统所提供的open
、close
或者seek
操作。
注意 |
---|
这里的sync 操作与POSIX文件系统的fsync() 操作是不同的。就像我们早前讲过的,ZooKeeper的写操作是原子性的,一个成功的写操作只保证数据被持久化到大多数ZooKeeper的服务器存储上。所以读操作可能会读取不到最新状态的数据,sync 操作用来让client强制所访问的ZooKeeper服务器上的数据状态更新到最新状态。我们会在《一致性 Consistentcy》一节中详细介绍。 |
批量更新 Multiupdate
ZooKeeper支持将一些原始的操作组合成一个操作单元,然后执行这些操作。那么这种批量操作也是具有原子性的,只可能有两种执行结果,成功和失败。批量操作单元中的操作,不会出现一些操作执行成功,一些操作执行失败的情况,即要么都成功,要么都失败。
Multiupdate对于绑定一些结构化的全局变量很有用处。例如绑定一个无向图(undirected graph)。无向图的顶点(vertex)由znode来表示。添加和删除边(edge)的操作,由修改边的两个关联znode来实现。如果我们使用ZooKeeper的原始的操作来实现对边(edge)的操作,那么就有可能产生两个znode修改不一致的情况(一个修改成功,一个修改失败)。那么我们将修改两个znode的操作放入到一个Multi修改单元中,就能够保证两个znode,要么都修改成功,要么都修改失败。这样就能够避免修改无向图的边时产生修改不一致的现象。
APIs
ZooKeeper客户端使用的核心编程语言有JAVA和C;同时也支持Perl、Python和REST。执行操作的方式呢,分为同步执行和异步执行。我们之前已经见识过了同步的Java API中的exists
。
public Stat exists(String path, Watcher watcher) throws KeeperException,
InterruptedException
下面代码则是异步方式的exists
:
public void exists(String path, Watcher watcher, StatCallback cb, Object ctx)
Java API中,异步的方法的返回类型都是void
,而操作的返回的结果将传递到回调对象的回调函数中。回调对象将实现StatCallback
接口中的一个回调函数,来接收操作返回的结果。函数接口如下:
public void processResult(int rc, String path, Object ctx, Stat stat);
参数rc
表示返回码,请参考KeeperException
中的定义。在stat
参数为null的情况下,非0的值表示一种异常。参数path
和ctx
与客户端调用的exists
方法中的参数相等,这两个参数通常用来确定回调中获得的响应是来至于哪个请求的。参数ctx
可以是任意对象,只有当path
参数不能消灭请求的歧义时才会用到。如果不需要参数ctx
,可以设置为null。
应该使用同步API还是异步API呢? |
---|
两种API提供了相同的功能,需要使用哪种API取决于你程序的模式。例如,你设计的程序模式是一个事件驱动模式的程序,那么你最好使用异步API。异步API也可以被用在追求一个比较好的数据吞吐量的场景。想象一下,如果你需要得去大量的znode数据,并且依靠独立的进程来处理他们。如果使用同步API,每次读取操作都会被阻塞住,直到返回结果。不如使用异步API,读取操作可以不必等待返回结果,继续执行。而使用另外的线程来处理返回结果。 |
观察模式触发器 Watch triggers
读操作,例如:exists
、getChildren
、getData
会在znode上开启观察模式,并且写操作会触发观察模式事件,例如:create
、delete
和setData
。ACL(Access Control List)操作不会启动观察模式。观察模式被触发时,会生成一个事件,这个事件的类型取决于触发他的操作:
exists
启动的观察模式,由创建znode,删除znode和更新znode操作来触发。getData
启动的观察模式,由删除znode和更新znode操作触发。创建znode不会触发,是因为getData
操作成功的前提是znode必须已经存在。getChildren
启动的观察模式,由子节点创建和删除,或者本节点被删除时才会被触发。我们可以通过事件的类型来判断是本节点被删除还是子节点被删除:NodeChildrenChanged
表示子节点被删除,而NodeDeleted
表示本节点删除。
—- | Watch trigger | ||||
---|---|---|---|---|---|
Watch creation | create znode | create child | delete znode | delete child | setData |
exists | NodeCreated | - | NodeDeleted | - | NodeDataChanged |
getData | - | - | NodeDeleted | - | NodeDataChanged |
getChildren | - | getChildren | NodeDeleted | NodeChildrenChanged | - |
事件包含了触发事件的znode的path,所以我们通过NodeCreated
和NodeDeleted
事件就可以知道哪个znode被创建了或者删除了。如果我们需要在NodeChildrenChanged
事件发生后知道哪个子节点被改变了,我们就需要再调用一次getChildren
来获得一个新的子节点列表。与之类似,在NodeDataChanged
事件发生后,我们需要调用getData
来获得新的数据。我们在编写程序时,会在接收到事件通知后改变znode的状态,所以我们一定要清楚的记住znode的状态变化。
ACLs 访问控制操作
znode的创建时,我们会给他一个ACL(Access Control List),来决定谁可以对znode做哪些操作。
ZooKeeper通过鉴权来获得客户端的身份,然后通过ACL来控制客户端的访问。鉴权方式有如下几种:
- digest
使用用户名和密码方式
- sasl
使用Kerberos鉴权
- ip
使用客户端的IP来鉴权
客户端可以在与ZooKeeper建立会话连接后,自己给自己授权。授权是并不是必须的,虽然znode的ACL要求客户端必须是身份合法的,在这种情况下,客户端可以自己授权来访问znode。下面的例子,客户端使用用户名和密码为自己授权:
zk.addAuthInfo("digest", "tom:secret".getBytes());
ACL是由鉴权方式、鉴权方式的ID和一个许可(permession)的集合组成。例如,我们想通过一个ip地址为10.0.0.1的客户端访问一个znode。那么,我们需要为znode设置一个ACL,鉴权方式使用IP鉴权方式,鉴权方式的ID为10.0.0.1,只允许读权限。使用JAVA我们将像如下方式创建一个ACL对象:
new ACL(Perms.READ,new Id("ip", "10.0.0.1"));
所有的许可权限将在下表中列出。请注意,exists
操作不受ACL的控制,所以任何一个客户端都可以通过exists
操作来获得任何znode的状态,从而得知znode是否真的存在。
ACL permission | Permitted operations |
---|---|
CREATE | create (a child znode) |
READ | getChildren,getData |
WRITE | setData |
DELETE | delete (a child znode) |
ADMIN | setACL |
在ZooDefs.Ids
类中,有一些ACL的预定义变量,包括OPEN_ACL_UNSAFE
,这个设置表示将赋予所有的许可给客户端(除了ADMIN的许可)。
另外,我们可以使用ZooKeeper鉴权的插件机制,来整合第三方的鉴权系统。