ZooKeeper是一个分布式的,开放源码的分布式应用程序协调服务,是Hadoop和Hbase的重要组件。它是一个为分布式应用提供一致性服务的软件,提供的功能包括:配置维护、域名服务、分布式同步、组服务等。
简单地说,zookeeper维护了一个类似于文件系统的树状结构,结构上的节点znode可以自由地增删,当节点发生变动时,zookeeper会通知客户端。
为了解释zookeeper的原理,下面先讲paxos算法和ZAB协议。
1、数据一致性的保证
数据一致性的依赖一个原则:在一个分布式数据库系统中,如果各节点的初始状态一致,每个节点都执行相同的操作序列,那么他们最后能得到一个一致的状态。
2、paxos算法简介
paxos算法是一种基于消息传递的一致性算法,是目前公认的解决分布式一致性问题最有效的算法之一,其解决的问题就是在分布式系统中如何就某个值(决议)达成一致。具体来说,上面讲的数据一致性原则,需要保证每个节点都执行相同的操作序列,也就需要一个”一致性算法”以保证每个节点看到的指令一致,paxos算法就是解决这个问题的一种算法。
3、paxos算法中3个的角色
Proposer:负责提出提案,提案的目的是为了得到一个经过决议的value,也就是得到这个分布式系统的一个整体结果;
Acceptor:负责裁决提案,即是否接受提案;
learner:接受提案结果;
一个进程或参与者可以同时是上述角色中的一个或几个。
4、paxos算法过程
阶段一,prepare阶段:
Proposer(可能是很多个)选择一个提案,会发送prepare请求给Acceptor。Acceptor收到提案后,判断prepare提案编号是否最新,如果这个提案编号大于所有已处理过的提案,则接受提案,否则拒绝提案,然后Acceptor响应请求。
阶段二,accept阶段:
Proposer收到半数以上Acceptor的响应后,会发送accept请求给Acceptor。Acceptor收到提案后,判断prepare提案编号是否最新,如果这个提案编号大于所有已处理过的提案,则接受提案,否则拒绝提案,然后不回应或响应error。如果Proposer没有收到超过半数的成功回应,会重新进入阶段一,同时递增提案号。
1、ZAB协议与paxos算法
Paxos算法应用到分布式系统中会有几个问题:
1)如果有多个Proposer,那么是保证不了多个提案被接受的先后顺序的;
2)多个Proposer还可能导致活锁问题,在第n个提案第二个阶段还未完成,第n+1个提案的prepare提案达到Acceptor,这时候第n个提案就被否了,同样第n+1个提案也可能被否,这样无限循环下去;
3)Paxos协议规定提案的值v只要被大多数Acceptor接受过,后续的所有提案不能修改值v,如果想要修改v值怎么办?
zookeeper的核心算法ZAB协议(zookeeper原子广播协议),通过一个简单的方法解决了上述前两个问题:所有的提案都先转发到Leader,由Leader来保证多个提案之间的先后顺序,同时也避免了多Proposer导致的活锁问题。ZAB没解决第三个问题。
ZAB协议包括两种基本模式:恢复模式(选主)和广播模式(同步)。当服务启动或者在Leader崩溃后,ZAB就进入了恢复模式,当Leader被选举出来,且大多数Server完成了和Leader的状态同步以后,恢复模式就结束了。状态同步保证了Leader和Server具有相同的系统状态。最终Leader将最新数据同步给所有Server,Leader数据一定是最新的,也可以说数据最新的Server才可以成为Leader。
2、zxid
为了保证事务的顺序一致性,zookeeper采用了全局递增的事务id号zxid来标识事务。所有的提议都在被提出的时候加上了zxid。
3、选主模式
1)选举线程由当前Server发起选举的线程担任,其主要功能是对投票结果进行统计,并选出推荐的Server;
2)选举线程首先向所有Server发起一次询问,包括自己;
3)选举线程收到回复后,验证是否是自己发起的询问(验证zxid是否一致),然后获取对方的id,并存储到当前询问对象列表中,最后获取对方提议的Leader相关信息,并将这些信息存储到当次选举的投票记录表中;
4)收到所有Server回复以后,就计算出zxid最大的那个Server,并将这个Server相关信息设置成下一次要投票的Server;
5)线程将当前zxid最大的Server设置为当前Server要推荐的Leader,如果此时获胜的Server获得超过半数,则设置当前推荐的Leader为获胜的Server,将根据获胜的Server相关信息设置自己的状态,否则,继续这个过程,直到Leader被选举出来。
4、同步模式
当通过选主流程选出leader之后,一定是集群中数据最完整最新的节点。因为所有znode的变更都需要通过Leader,Leader会为所有follower和observer创建learner handler线程用于接收同步数据请求,当follower和observer收到Leader发过来的信息,比较zxid的大小,如果zxid小于Leader的zxid,则把节点最大的zxid发送给Leader,Leader会将大于该zxid的所有数据同步到该follower,完成同步后,通知改follower进入uptedate状态,follower接收到uptedate消息后,就可以接收client的请求了。
先讲一下zookeeper中所有服务器的角色:
1)领导者(leader),负责进行投票的发起和决议,更新系统状态;
2)学习者(learner),包括跟随者(follower)和观察者(observer),follower用于接受客户端请求并想客户端返回结果,在选主过程中参与投票。observer可以接受客户端连接,将写请求转发给leader,但observer不参加投票过程,只同步leader的状态,observer的目的是为了扩展系统,提高读取速度;
3)客户端(client),请求发起方。
从zookeeper读数据没什么好讲,任意可用节点都一样,向zookeeper写数据的流程如下:
1)Client向zk的server1上写数据,发送一个写的请求;
2)如果server1不是leader,那么server1会把接收的请求转发给leader。这个leader会将写请求广播给各个server,比如server1和server2,各个server写成功之后就会通知leader;
3)当leader收到大多数server写成功的消息,那么就说明数据写成功了。之后leader会告诉server1数据写成功了;
4)server1会通知Client数据写成功了。这时就认为整个写操作成功。
1)命名服务:在zookeeper系统创建一个目录,可以上下游机器约定好目录,通过这个目录互相探索发现。
2)配置管理:如果程序分散在多台机器上,将配置放在zookeeper上,一旦配置信息变化,将收到zookeeper通知。
3)集群管理:所谓集群管理无外乎两点,是否有机器退出和加入、选举master,这两点就是zookeeper主要做的事。
4)分布式锁:借助zookeeper 可以实现分布式锁,不同参与者都尝试创建目录节点,创建最小编号节点的参与方,可以认为是锁的持有者,锁的释放,也就是节点的删除。
参考资料:
https://blog.csdn.net/gs80140/article/details/51496925
https://blog.csdn.net/u013679744/article/details/79222103