ZooKeeper是个集群,内部有多个server,每个server都可以连接多个client,每个client都可以修改server中的数据
ZooKeeper可以保证每个server内的数据完全一致,是如何实现的呢?
答:数据一致性是靠Paxos算法保证的,Paxos可以说是分布式一致性算法的鼻祖,是ZooKeeper的基础
Paxos的基本思路:( 深入解读zookeeper一致性原理 )
假设有一个社团,其中有团员、议员(决议小组成员)两个角色团员可以向议员申请提案来修改社团制度
议员坐在一起,拿出自己收到的提案,对每个提案进行投票表决,超过半数通过即可生效
为了秩序,规定每个提案都有编号ID,按顺序自增
每个议员都有一个社团制度笔记本,上面记着所有社团制度,和最近处理的提案编号,初始为0
投票通过的规则:
新提案ID 是否大于议员本中的ID,是议员举手赞同如果举手人数大于议员人数的半数,即让新提案生效
例如:
刚开始,每个议员本子上的ID都为0,现在有一个议员拿出一个提案:团费降为100元,这个提案的ID自增为1
每个议员都和自己ID对比,一看 1>0,举手赞同,同时修改自己本中的ID为1发出提案的议员一看超过半数同意,就宣布:1号提案生效然后所有议员都修改自己笔记本中的团费为100元
以后任何一个团员咨询任何一个议员:"团费是多少?",议员可以直接打开笔记本查看,并回答:团费为100元
可能会有极端的情况,就是多个议员一起发出了提案,就是并发的情况
例如
刚开始,每个议员本子上的编号都为0,现在有两个议员(A和B)同时发出了提案,那么根据自增规则,这两个提案的编号都为1,但只会有一个被先处理假设A的提案在B的上面,议员们先处理A提案并通过了,这时,议员们的本子上的ID已经变为了1,接下来处理B的提案,由于它的ID是1,不大于议员本子上的ID,B提案就被拒绝了,B议员需要重新发起提案上面就是Paxos的基本思路,对照ZooKeeper,
对应关系就是:
团员 -client
议员 -server
议员的笔记本 -server中的数据
提案 -变更数据的请求
提案编号 -zxid(ZooKeeper Transaction Id)
提案生效 -执行变更数据的操作
ZooKeeper中还有一个leader的概念,就是把发起提案的权利收紧了,以前是每个议员都可以发起提案,现在有了leader,大家就不要七嘴八舌了,先把提案都交给leader,由leader一个个发起提案
Paxos算法就是通过投票、全局编号机制,使同一时刻只有一个写操作被批准,同时并发的写操作要去争取选票,只有获得过半数选票的写操作才会被批准,所以永远只会有一个写操作得到批准,其他的写操作竞争失败只好再发起一轮投票
1)一致性保证
Zookeeper是一种高性能、可扩展的服务。Zookeeper的读写速度非常快,并且读的速度要比写的速度更快。另外,在进行读操作的时候,ZooKeeper依然能够为旧的数据提供服务。这些都是由于ZooKeepe所提供的一致性保证,它具有如下特点:
顺序一致性
客户端的更新顺序与它们被发送的顺序相一致。
原子性
更新操作要么成功要么失败,没有第三种结果。
单系统镜像
*无论客户端连接到哪一个服务器,客户端将看到相同的
ZooKeeper视图。*
可靠性
一旦一个更新操作被应用,那么在客户端再次更新它之前,它的值将不会改变。。这个保证将会产生下面两种结果:
*1
.如果客户端成功地获得了正确的返回代码,那么说明更新已经成果。如果不能够获得返回代码(由于通信错误、超时等等),那么客户端将不知道更新操作是否生效。*
2.当从故障恢复的时候,任何客户端能够看到的执行成功的更新操作将不会被回滚。
实时性
*在特定的一段时间内,客户端看到的系统需要被保证是实时的(在十几秒的时间里)。在此时间段内,任何系统的改变将被客户端看到,或者被客户端侦测到。
- 给予这些一致性保证,
ZooKeeper更高级功能的设计与实现将会变得非常容易,例如:leader选举、队列以及可撤销锁等机制的实现。
2)Leader选举
ZooKeeper需要在所有的服务(可以理解为服务器)中选举出一个Leader,然后让这个Leader来负责管理集群。此时,集群中的其它服务器则成为此Leader的Follower。并且,当Leader故障的时候,需要ZooKeeper能够快速地在Follower中选举出下一个Leader。这就是ZooKeeper的Leader机制,下面我们将简单介绍在ZooKeeper中,Leader选举(Leader Election)是如何实现的。此操作实现的核心思想是:首先创建一个EPHEMERAL目录节点,例如“/election”。然后。每一个ZooKeeper服务器在此目录下创建一个
SEQUENCE|<a target="_blank" name="OLE_LINK55" style="box-sizing: border-box; background: transparent; color: rgb(51, 102, 153); text-decoration: none; margin: 0px; padding: 0px; font-weight: normal; outline: none;"></a> <a target="_blank" name="OLE_LINK54" style="box-sizing: border-box; background: transparent; color: rgb(51, 102, 153); text-decoration: none; margin: 0px; padding: 0px; font-weight: normal; outline: none;">EPHEMERAL </a>
类型的节点,例如“/election/n_”。在SEQUENCE标志下,ZooKeeper将自动地为每一个ZooKeeper服务器分配一个比前一个分配的序号要大的序号。此时创建节点的ZooKeeper服务器中拥有最小序号编号的服务器将成为Leader。在实际的操作中,还需要保障:当Leader服务器发生故障的时候,系统能够快速地选出下一个ZooKeeper服务器作为Leader。一个简单的解决方案是,让所有的follower监视leader所对应的节点。当Leader发生故障时,Leader所对应的临时节点将会自动地被删除,此操作将会触发所有监视Leader的服务器的watch。这样这些服务器将会收到Leader故障的消息,并进而进行下一次的Leader选举操作。但是,这种操作将会导致“从众效应”的发生,尤其当集群中服务器众多并且带宽延迟比较大的时候,此种情况更为明显。在Zookeeper中,为了避免从众效应的发生,它是这样来实现的:每一个follower对follower
集群中对应的比自己节点序号小一号的节点(也就是所有序号比自己小的节点中的序号最大的节点)设置一个watch。只有当
follower所设置的watch被触发的时候,它才进行Leader选举操作,一般情况下它将成为集群中的下一个Leader。很明显,此
Leader选举操作的速度是很快的。因为,每一次Leader选举几乎只涉及单个follower的操作。