先前的章节讨论了分布式系统的特点,并且最大的特点莫过于协调。在上述中,我们也用一个最常见的例子主从模式来介绍了zookeeper的一些基本情况,下面让我们来深入的了解一下zookeeper吧!
Zookeeper基本特点
一些常用于协调的语义通常都是在多个应用之间是共享的。一种方式是创建这种语义的实例并且操作这些实例。例如我们可以说,分布式锁构成了重要的语义,并且暴漏出接口去创建、获取和释放锁
这样来设计的话,也会有很多的缺点。首先我们在使用之前需要把所有的语义都搞清楚或者以后能够在API上扩展新的需求;其次它并不提供灵活的应用程序,使用该服务来创建语义。
因此我们对zookeeper采取了不用的路径区分。Zookeeper并不直接的暴漏自己的语法,
相反相反,它公开了一个文件系统API,并且让应用程序的调用的时候才来实现自己的原语。我们通过用食谱来描述这些语法,食谱包括zookeeper操作节点信息,我们用专业术语称作znodes。Znodes组织了整个的文件系统结构。下面的这张图就说了znodes的信息。Root节点包含了4个节点。其中三个都有自己的子节点,他们的子节点中都包含了需要的数据信息。
空节点常常携带了一些描述该节点本身属性的信息。例如在上面的主从模式结构中,空节点代表目前并没有master当选为主节点。上图中其他的节点在主从模式中可以携带一些有用的配置信息。
1./worker节点是父节点,代表了目前可用的worker的信息。如果worker不可用的话,将会在/worker中被移除
2./task代表了目前被创建等待被执行的任务信息。主从模式的客户端可以来添加新的任务来作为/task的子节点,等待worker去执行。
3./assign节点是所有分配了任务worker的父节点。当一个master给worker分配了一个任务后,就会在该节点下添加一个子节点 。API浏览
Znodes可以包含数据信息,如果znodes包含数据的话,那么数据会以字节数组的形式来存储。字节数组的格式是针对每一个应用程序来说的,zookeeper并不负责解析它。
Zookeeper的api暴漏了一下的方法
Create /path data
创建一个名字是/path并且包含了数据data的节点
Delete /path
删除节点/path
Exists /path
判断是否存在/path
Setdata /path data
把数据data存储在节点/path上
Getdata /path
返回/path节点上的数据
getChildren /path
返回节点/path的所有子节点信息
需要注意的是zookeeper不允许部分读和写操作,上面的getdata和setdata方法,读写的都是全部操作。
Zookeeper客户端连接到zookeeper服务端并且通过调用zookeeper的API来创建一个回话。
节点类型
当创建一个节点的时候,需要明确节点的类型。
永久性节点和临时节点
节点分为永久节点和临时节点,永久节点只能通过调用delete命令来删除;相反,当客户单崩溃或者失去与服务端连接的时候,临时节点会自动的删除。另外临时节点不可以有子节点。
当节点需要存储一些应用的信息,及时当客户端失去联系后,也需要保存的应用信息,这时永久节点就很管用。例如在主从模式的机构中,我们需要维护任务的分配信息,即使主master崩溃了
临时节点保存了整个回话之间的应用的状态信息。例如在主从模式中,主节点是临时节点,代表着目前主节点正在运行。如果当主节点崩溃了,而主node仍然存在的话,那么系统将不能够检测到主机崩溃了。因此主节点跟主master必须信息一致。我们有时也把worker作为临时节点,如果woker崩溃了,那么他的回话以及他的节点信息将会一起消失。
一个临时的节点在以下场景中能够被删除。
1. 当客户单创建的回话结束或者过期时,临时节点自动删除
2. 客户端也可以手动删除
由于当创建者的回话到期后,临时节点会被删除,因此我们不允许临时节点有子节点。
顺序节点
一个节点也可以被设置为顺序节点。顺序节点会被分配一个单独的单调递增的整数。这个序列号被分配到路径中,用来创建节点。例如,如果client端创建了一个节点名称为/task/task-,zookeeper会分配一个1的序列号添加到路径中,序列号的节点很容易被创建,并且是唯一的。同时能够很容易的看到节点的创建顺序信息。
监视和通知
因为zookeeper通常访问远程服务,每一次的访问znode,客户单都需要了解目前znodes的节点信息,如果这样做的话,会很耗时。考虑下图中的示例。第二个调用getChildren /任务返回相同的值,空集,因此是不必要的。
常见的问题就是轮询的调用,去获取相应的状态信息。为了代替客户端轮询,我们已经选择了一种基于通知的机制。客户端去zookeeper注册,然后通过通知来获取znode的状态信息。这在zookeeper中成为watch,即为监视。监视是一个一次性的操作,这意味着它通过触发一个通知来获取一次状态信息。如果想获取多个通知的话,客户端必须设置一个新的监视再次接收通知。情况如图2 - 3所示,客户端从zookeeper读取新值只有当它收到一个通知时,才表明/task的值发生了变化。
当用监视的,我们需要注意一些注意事项。由于监视是一个一次性的操作,因此可能当获取zode信息时,新的改变同样发生在该节点上,导致读到的信息不一致,也就是我们常说的脏数据。不过你不用担心,下面是整个过程的介绍信息。
1. 客户端C1对节点/tasks设置了一个监视
2. 客户端C2过来,并且在/tasks上添加了一个新的任务
3. 客户端时候到了通知
4. 客户端C1设置了一个新的监视,但是在这之前,第三个客户端C3过来,同样在/tasks中添加了一个任务。
最终客户端设置了监听,但是并没有收到来自客户端C3的任务通知操作。为了观察这一变化,c1在设置监视之前必须读取来自/task的状态信息,如果信息不一致的话,将不会对/task进行任何操作,因此c1不会错误任何的改变。这会在下面提到,nodes也会有版本的控制。
Zookeeper根据监视的类型,提供了不同类型的通知。例如有对节点数据的监视、对子节点的监视、对节点增删的监视。
版本
每个znode都有一个与之相关联的版本号,每次数据变化都会增加它的版本号。两个API可以有条件地执行操作:setData和delete操作。每一次的调用版本号都会作为输入参数,只有客户端版本匹配服务器上的最新版本时,操作才会成功。使用版本很重要,尤其是多个zookeeper客户端可能会试图在同一znode执行操作。例如,假设一个客户端c1向节点 /config中添加了一些配置。如果另一个客户端c 2同时更新节点c1时,版本号将不会统一,因此会执行失败。使用版本可以避免这种情况。在这种情况下,版本c1使用写作时不匹配,操作失败。这种情况如图2 - 4所示。
原文:http://blog.csdn.net/luckyzhoustar/article/details/50527975