zookeeper是hadoop下面的一个子项目, 用来协调跟hadoop相关的一些分布式的框架, 如hadoop, hive, pig等, 其实他们都是动物, 因此叫zookeeper(本人歪歪).

zookeeper实际上是集群中每一个节点都维护着一棵相同的树, 树的结构跟linux的目录结构的概念差很少, 以/为跟节点, 下边能够扩展任意的节点和叶子节点, 每一个节点均可以写入数据. 基于zookeeper的分布式锁的实现, 实际上是得益于zookeeper同步文件的强大性, 咱们相信每时每刻咱们访问zookeeper的树时, 相同节点返回的数据都是一致的. 这要靠zookeeper内部的一些算法来实现. 特别是leader的选举算法, 这里就不说了, 感兴趣的话能够去搜索一下看看.

咱们知道了zookeeper集群的每一个节点的数据都是一致的, 那么咱们能够经过这些节点来做为锁的标志.

首先给锁设置一下API, 至少要包含, lock(锁住), unlock(解锁), isLocked(是否锁住)三个方法

而后咱们能够建立一个工厂(LockFactory), 用来专门生产锁.

锁的建立过程以下描述:

前提:每一个锁都须要一个路径来指定(如:/jiacheo/lock)

1.根据指定的路径, 查找zookeeper集群下的这个节点是否存在.(说明已经有锁了)

2. 若是存在, 根据查询者的一些特征数据(如ip地址/hostname), 当前的锁是否是查询者的

3. 若是不是查询者的锁, 则返回null, 说明建立锁失败

4. 若是是查询者的锁, 则把这个锁返回给查询者

5. 若是这个节点不存在, 说明当前没有锁, 那么建立一个临时节点, 并将查询者的特征信息写入这个节点的数据中, 而后返回这个锁.

根据以上5部, 一个分布式的锁就能够建立了.

建立的锁有三种状态:

1. 建立失败(null), 说明该锁被其余查询者使用了.’

2. 建立成功, 但当前没有锁住(unlocked), 可使用

3. 建立成功, 但当前已经锁住(locked)了, 不能继续加锁.

如图, 若是咱们getLock(“/jiacheo/lock1″,”192.168.0.100″), 想要获取/jiacheo/lock1这个锁的话, 咱们先判断这个节点是否存在, 存在的话获取他的数据(data), 而后经过解析data, 咱们能够知道这个节点是否是咱们查询者建立的(经过ip地址写入节点数据中), 而后就能够返回一个锁了.

正确实现一个分布式锁是一件很是棘手的事情,由于很难对全部类型的故障进行正确的处理,ZooKeeper带有一个Java语言编写的生产级别的锁实现,名为WriteLock,客户端能够方便的使用它。

(b)zookeeper分布式锁

    link:http://www.searchtb.com/2011/01/zookeeper-research.html

 

        拥有了zookeeper如此强大的分布式协做系统后,咱们能够很容易的实现大量的分布式应用,包括了分布式锁,分布式队列,分布式Barrier,双阶段提交等等. 这些应用能够帮咱们改进不少复杂系统的协做方式,将这些系统的实现变得更加优雅而高效.鉴于篇幅,本文仅介绍分布式锁的实现.
利用了前文提到的sequence nodes能够很是容易的实现分布式锁. 实现分布式锁的基本步骤以下(这些步骤须要在全部须要锁的客户端执行):

  1. client调用create()建立名为”_locknode_/lock-”的节点,注意须要设置sequence和ephemeral属性
  2. client调用getChildren(“_locknode_”),注意不能设置watch,这样才能避免羊群效应
  3. 若是步骤1中建立的节点序号最低,则该client得到锁,开始执行其它程序
  4. client对lock-xxx中序号仅次于本身建立节点的那个节点调用exists(),并设置watch
  5. 若是exist()返回false(节点不存在)则回到步骤2,不然等待步骤4中的watch被触发并返回步骤2

分布式锁在zookeeper的源代码中已经有实现,能够参考org.apache.zookeeper.recipes.lock



六、ZooKeeper一致性协议-Zab

 

link:http://blog.csdn.net/chen77716/article/details/7309915

Zookeeper的一致性协议:Zab

分类: 分布式算法   2657人阅读  评论(3)  收藏  举报
 

目录(?)[+]

 

      Zookeeper使用了一种称为Zab(Zookeeper Atomic Broadcast)的协议做为其一致性复制的核心,据其做者说这是一种新发算法,其特色是充分考虑了Yahoo的具体状况:高吞吐量、低延迟、健壮、简单,但不过度要求其扩展性。下面将展现一些该协议的核心内容:

另,本文仅讨论Zookeeper使用的一致性协议而非讨论其源码实现

        Zookeeper的实现是有Client、Server构成,Server端提供了一个一致性复制、存储服务,Client端会提供一些具体的语义,好比分布式锁、选举算法、分布式互斥等。从存储内容来讲,Server端更多的是存储一些数据的状态,而非数据内容自己,所以Zookeeper能够做为一个小文件系统使用。数据状态的存储量相对不大,彻底能够所有加载到内存中,从而极大地消除了通讯延迟。

        Server能够Crash后重启,考虑到容错性,Server必须“记住”以前的数据状态,所以数据须要持久化,但吞吐量很高时,磁盘的IO便成为系统瓶颈,其解决办法是使用缓存,把随机写变为连续写。

考虑到Zookeeper主要操做数据的状态,为了保证状态的一致性,Zookeeper提出了两个安全属性(Safety Property)

 

  • 全序(Total order):若是消息a在消息b以前发送,则全部Server应该看到相同的结果
  • 因果顺序(Causal order):若是消息a在消息b以前发生(a致使了b),并被一块儿发送,则a始终在b以前被执行。
为了保证上述两个安全属性,Zookeeper使用了TCP协议和Leader。经过使用TCP协议保证了消息的全序特性(先发先到),经过Leader解决了因果顺序问题:先到Leader的先执行。由于有了Leader,Zookeeper的架构就变为:Master-Slave模式,但在该模式中Master(Leader)会Crash,所以,Zookeeper引入了Leader选举算法,以保证系统的健壮性。概括起来Zookeeper整个工做分两个阶段:
  • Atomic Broadcast
  • Leader选举

1. Atomic Broadcast

同一时刻存在一个Leader节点,其余节点称为“Follower”,若是是更新请求,若是客户端链接到Leader节点,则由Leader节点执行其请求;若是链接到Follower节点,则需转发请求到Leader节点执行。但对读请求,Client能够直接从Follower上读取数据,若是须要读到最新数据,则须要从Leader节点进行,Zookeeper设计的读写比例是2:1。
 
Leader经过一个简化版的二段提交模式向其余Follower发送请求,但与二段提交有两个明显的不一样之处:
  • 由于只有一个Leader,Leader提交到Follower的请求必定会被接受(没有其余Leader干扰)
  • 不须要全部的Follower都响应成功,只要一个多数派便可
通俗地说,若是有2f+1个节点,容许f个节点失败。由于任何两个多数派必有一个交集,当Leader切换时,经过这些交集节点能够得到当前系统的最新状态。若是没有一个多数派存在(存活节点数小于f+1)则,算法过程结束。但有一个特例:
若是有A、B、C三个节点,A是Leader,若是B Crash,则A、C能正常工做,由于A是Leader,A、C还构成多数派;若是A Crash则没法继续工做,由于Leader选举的多数派没法构成。

2. Leader Election

Leader选举主要是依赖Paxos算法,具体算法过程请参考其余博文,这里仅考虑Leader选举带来的一些问题。Leader选举遇到的最大问题是,”新老交互“的问题,新Leader是否要继续老Leader的状态。这里要按老Leader Crash的时机点分几种状况:
  1. 老Leader在COMMIT前Crash(已经提交到本地)
  2. 老Leader在COMMIT后Crash,但有部分Follower接收到了Commit请求
第一种状况,这些数据只有老Leader本身知道,当老Leader重启后,须要与新Leader同步并把这些数据从本地删除,以维持状态一致。
第二种状况,新Leader应该能经过一个多数派得到老Leader提交的最新数据
老Leader重启后,可能还会认为本身是Leader,可能会继续发送未完成的请求,从而由于两个Leader同时存在致使算法过程失败,解决办法是把Leader信息加入每条消息的id中,Zookeeper中称为zxid,zxid为一64位数字,高32位为leader信息又称为epoch,每次leader转换时递增;低32位为消息编号,Leader转换时应该从0从新开始编号。经过zxid,Follower能很容易发现请求是否来自老Leader,从而拒绝老Leader的请求。
 
由于在老Leader中存在着数据删除(状况1),所以Zookeeper的数据存储要支持补偿操做,这也就须要像数据库同样记录log。

3. Zab与Paxos

Zab的做者认为Zab与paxos并不相同,只因此没有采用Paxos是由于Paxos保证不了全序顺序:
Because multiple leaders can
propose a value for a given instance two problems arise.
First, proposals can conflict. Paxos uses ballots to detect and resolve conflicting proposals. 
Second, it is not enough to know that a given instance number has been committed, processes must also be able to figure out which value has been committed.
Paxos算法的确是不关系请求之间的逻辑顺序,而只考虑数据之间的全序,但不多有人直接使用paxos算法,都会通过必定的简化、优化。
通常Paxos都会有几种简化形式,其中之一即是,在存在Leader的状况下,能够简化为1个阶段(Phase2)。仅有一个阶段的场景须要有一个健壮的Leader,所以工做重点就变为Leader选举,在考虑到Learner的过程,还须要一个”学习“的阶段,经过这种方式,Paxos可简化为两个阶段:
  • 以前的Phase2
  • Learn
若是再考虑多数派要Learn成功,这其实就是Zab协议。Paxos算法着重是强调了选举过程的控制,对决议学习考虑的很少,Zab刚好对此进行了补充。
以前有人说,全部分布式算法都是Paxos的简化形式,虽然很绝对,但对不少状况的确如此,但不知Zab的做者是否定同这种说法?

4.结束

本文只是想从协议、算法的角度分析Zookeeper,而非分析其源码实现,由于Zookeeper版本的变化,文中描述的场景或许已找不到对应的实现。另,本文还试图揭露一个事实:Zab就是Paxos的一种简化形式。
【参考资料】
  • A simple totally ordered broadcast protocol
  • paxos


七、ZooKeeper选举和同步
 

zookeeper

  301人阅读  评论(0)  收藏  举报

http://stblog.baidu-tech.com/?p=1164

 

用于分布式下一致性相关问题的解决方案。能够理解为由集群组成的可靠的单master。可将传统方案中的master使用zookeeper代替,且不用担忧单点问题。

 

应用场景:树状结构的命名服务、节点数据变动的消息通知、分布式共享锁、配置数据的集中存放、集群中节点机器的状态管理及状态变动通知

zookeeper实现分布式锁:经过zookeeper的节点状态进行条件判断,若是不知足,则在客户端本地加锁等待Object.wait()。利用zookeeper的实时通知机制,当zookeeper的节点知足条件状态时,客户端会同步得到通知,而后在本地解锁Object.notifyAll()。从而实现了分布式加锁、阻塞、解锁。

 

三类角色: leader(处理写请求,单点)、follower(处理客户端请求,参与投票)、observer(不投票,只处理客户端请求)

恢复模式:服务重启或者leader宕机后,经过paxos算法,从follower中从新选出leader,并以leader为准,进行数据同步。此时服务不可用。

 

paxos选举算法:

一、每次选举,都是针对某个txid(transaction id)进行。

二、每一个follower首先广播询问,获取其它全部server的txid、提议value,txid必须相同,value存储到提议列表中

三、follower从提议列表中获取value,若是这个value被大于一半的follower支持,则直接使用此value,不然,继续发出广播询问。而且将此value做为回答其它follower轮训的提议。

四、循环执行3,直到收敛

paxos的精髓:解决了集群中,非全联通状况下的一致性问题。对于正常全联通状况,每台机器只须要广播获取其它各台机器的数据,而后比较获取最大值便可。这样各个节点获得的结论应该是同样的。问题在于,某些节点之间是不联通的。因而某个节点没法获知全局数据,只能经过paxos中循环投票,收敛至全局最优解。

 

同步流程:选举完成后,各个follower向leader发送同步请求,带上本身的最大zxid。leader经过zxid肯定同步点,将这以后的commit log交给follower进行同步。全部节点都保存一份系统状态数据,非强一致(getData不保证最新数据,能够先sync一下保证数据的同步状态),有同步延时。

 

多节点可读可写,部分节点延时同步,最终一致性。follower和observer负责监听客户请求和处理读请求。对于全部写请求,都一概转发至leader进行选举和数据同步。observer不参与投票,只作数据同步,提升写请求的效率。