众所周知,分布式协调服务很难正确无误的实现,它们很容易在竞争条件和死锁上犯错误。如何在这方面节省力气?Zookeeper是一个不错的选择。 Zookeeper背后的动机就是解除分布式应用在实现协调服务上的痛苦。这里在介绍Zookeeper的基本理论基础上,用Zookeeper实现了一 个配置管理中心,利用Zookeeper将配置信息分发到各个服务节点上,并保证信息的正确性和一致性。
引用官方的说法:“Zookeeper是一个高性能,分布式的,开源分布式应用协调服务。它提供了简单原始的功能,分布式应用可以基于它实现更高级 的服务,比如同步,配置管理,集群管理,名空间。它被设计为易于编程,使用文件系统目录树作为数据模型。服务端跑在java上,提供java和C的客户端 API”。
Zookeeper服务自身组成一个集群(2n+1个服务允许n个失效)。Zookeeper服务有两个角色,一个是leader,负责写服务和数据同步,剩下的是follower,提供读服务,leader失效后会在follower中重新选举新的leader。
逻辑图:
客户端可以连接到每个server,每个server的数据完全相同。每个follower都和leader有连接,接受leader的数据更新操作。Server记录事务日志和快照到持久存储。大多数server可用,整体服务就可用。数据模型:
Zookeeper表现为一个分层的文件系统目录树结构(不同于文件系统的是,节点可以有自己的数据,而文件系统中的目录节点只有子节点)。
Zookeeper维护者一个树形层次结构, 输的节点被称为 znode. znode 可以用户存储数据, 并且有一个与之相关的 ACL . Zookeeper 被设计用来实现协调服务(这类服务哦他那个厂使用小的数据文件),而不是用于大容量数据存储。
Zookeeper的数据访问具有原子性, 客户端在读取一个 znode 的数据时, 要么将读取到所有的内容, 要么读取失败, 不会只有部分数据被读取,同样, 一个写操作将替换znode中的所有内容,zookeeper会保证写操作不成功就失败, 不会只出现部分写的情况(不能追加操作)。
znode 分类: znode 分为两种, 短暂的和持久的。 ++znode 的类型在创建时被确定并且之后不能在被修改++。
短暂 znode 类型:
1. 在创建短暂znode的客户端会话结束时,此znode将被删除。 2. 短暂znode 不允许有子节点, 即使是一个短暂子节点。 3. 虽然每个短暂 znode 都会被绑定到一个客户端会话, 但它们对所有的客户端还是可见的(符合 acl 权限)。持久 znode :
持久znode 不依赖于客户端会,而且只有当客户端明确要删除该持久znode 时才会被删除。Sequence Nodes
Sequence Nodes 是指名称中包括Zookeeper 指定顺序号的znode 。如果在创建znode 时设置了顺序表示, 那么该znode 名称之后便会附加一个值, 这个值是由一个单调递增的计数器所添加的。
Watches:
ZooKeeper中的Watch是只能触发一次。也就是说,如果客户端在指定的ZNode设置了Watch,如果该ZNode数据发生变更,ZooKeeper会发送一个变更通知给客户端,同时触发设置的Watch事件。
如果ZNode数据又发生了变更,客户端在收到第一次通知后没有重新设置该ZNode的Watch,则ZooKeeper就不会发送一个变更通知给客户端。 ZooKeeper异步通知设置Watch的客户端。但是ZooKeeper能够保证在ZNode的变更生效之后才会异步地通知客户端,然后客户端才能够看到ZNode的数据变更。由于网络延迟,多个客户端可能会在不同的时间看到ZNode数据的变更,但是看到变更的顺序是能够保证有序一致的。
ZNode可以设置两类Watch,一个是Data Watches(该ZNode的数据变更导致触发Watch事件),另一个是Child Watches(该ZNode的孩子节点发生变更导致触发Watch事件)。调用getData()和exists() 方法可以设置Data Watches,调用getChildren()方法可以设置Child Watches。调用setData()方法触发在该ZNode的注册的Data Watches。调用create()方法创建一个ZNode,将触发该ZNode的Data Watches;调用create()方法创建ZNode的孩子节点,则触发ZNode的Child Watches。调用delete()方法删除ZNode,则同时触发Data Watches和Child Watches,如果该被删除的ZNode还有父节点,则父节点触发一个Child Watches。 另外,如果客户端与ZooKeeper Server断开连接,客户端就无法触发Watches,除非再次与ZooKeeper Server建立连接。。
schema:
world: 它下面只有一个id, 叫anyone, world:anyone代表任何人,zookeeper中对所有人有权限的结点就是属于world:anyone
auth: 它不需要id, 只要是通过authentication的user都有权限(zookeeper支持通过kerberos来进行authencation, 也支持username/password形式的authentication)
digest: 它对应的id为username:BASE64(SHA1(password)),它需要先通过username:password形式的authentication
ip: 它对应的id为客户机的IP地址,设置的时候可以设置一个ip段,比如ip:192.168.1.0/16, 表示匹配前16个bit的IP段
super: 在这种scheme情况下,对应的id拥有超级权限,可以做任何事情(cdrwa)
Permission :
CREATE(c): 创建权限,可以在在当前node下创建child node DELETE(d): 删除权限,可以删除当前的node READ(r): 读权限,可以获取当前node的数据,可以list当前node所有的child nodes WRITE(w): 写权限,可以向当前node写数据 ADMIN(a): 管理权限,可以设置当前node的permission名空间服务: 分布式命名服务,创建一个节点后,节点的路径就是全局唯一的,可以作为全局名称使用。
分布式锁: Zookeeper能保证数据的强一致性,用户任何时候都可以相信集群中每个节点的数据都是相同的。一个用户创建一个节点作为锁,另一个用户检测该节点,如果存在,代表别的用户已经锁住,如果不存在,则可以创建一个节点,代表拥有一个锁。
集群管理: 每个加入集群的机器都创建一个节点,写入自己的状态。监控父节点的用户会受到通知,进行相应的处理。离开时删除节点,监控父节点的用户同样会收到通知。
