目录
1、什么是Zookper
- ZooKeeper主要服务于分布式系统,可以用ZooKeeper来做:统一配置管理、统一命名服务、分布式锁、集群管理。
- 使用分布式系统就无法避免对节点管理的问题(需要实时感知节点的状态、对节点进行统一管理等等),而由于这些问题处理起来可能相对麻烦和提高了系统的复杂性,ZooKeeper作为一个能够通用解决这些问题的中间件就应运而生了。
- 简单的说,zookeeper=文件系统+通知机制。
2、使用场景
1、master节点选举:主节点挂了以后,从节点就会接手工作并且保证这个节点是唯一的,这也是所谓首脑模式,从而保证我们的集群是高可用的。
2、统一配置文件管理:即只需要部署一台服务器,则可以把相同的配置文件同步更新到其他所有服务器,此操作在云计算中用的特别多(假设修改了redis统-- 配置)。
3、发布与订阅:类似消息队列MQ (amqrmq... ) ,dubbo发布者把数据存在znode上,订阅者会读取这个数据。
4、分布式锁:分布式环境中不同进程之问争夺资源,类似于多线程中的锁。
5、集群管理:集群中保证数据的一致性。
3、架构原理
图中,绿色的是client,红色的是一个leader,蓝色的是其follower,红色和蓝色合称为Ensemble(合奏团)。
- Ensemble:zookeeper集群所有server构成一个Ensemble,要求必须至少3台server。
- Leader:负责改变zookeeper的状态ZooKeeper state: create, setData, and delete.
- Follower:负责执行leader的命令。
- Client:client和server之间有心跳保持连接,如果server挂了zookeeper会自动故障转移(failover)到别的server上去。Client连接后zookeeper都会有相应的session,session就是一次活动的时间段,session中可以有这次活动的变量,client的session从client建立连接开始一直到client断开连接为止。
- Quorum:集群中过半数的server的数量。比如集群中共有5台机器,那么quorum是5/2+1==3台。
一个zookeeper集群有一个leader,负责读写并把数据复制给follower,follower只负责读。是主从结构。当leader挂掉后zookper可以在200ms内重新选出新leader,可用性比较强。读操作会从当前连接的server读(但是因为write只需要quorum数量满足即可生效,所以有可能client读的是一台没同步的机器,所以这台机器需要先从leader 同步一下再返回)。
写操作需要集群里面大多数server都确认后才算ok,大多数指的是过半数。所以写性能随集群数量的增大而下降,读性能随集群数量增大而增加。所以,zookeeper有了监视(observer) server,他们不参与选举,不算大多数的一部分,但是可以同步leader的数据扩展读能力且不降低写能力,这样集群增大时不至于降低太多写能力。
可见,read和write都需要leader,所以leader挂了整个cluster不能对外提供任何服务。如果集群中不够quorum量,整个cluster也不能对外提供任何服务。
zookeeper由leader把数据复制到follower上,同传统数据库类似,zookeeper的每项操作也是有事务的,有事务id,叫做Zxid(zookeeper transaction id,是个递增的数值)。先来看看zookeeper的数据模型,是kv型,其中key是类似于linux的目录树:
zookeeper数据模型遵循分层命名空间,其中每个节点称为Znode,这是群集运行的系统的一部分。和目录不同的是即使中间的znode也能存数据,数据大小不超过1M,同redis一样,存放的数据也是二进制安全的。如下图:
zookeeper的znode节点有3种类型:
- persistence (持久性节点):
集合中的所有节点都将自己视为持久性Znode。即使在客户端断开连接后,这些节点仍会保持活动状态. - emphemeral(临时节点):
这些类型的节点将保持活动状态,直到客户端连接到它们为止。当客户端断开连接时,他们会死亡。这些类型的节点不允许有子节点。 - sequential(顺序节点):
它可以是持久性Znode或临时Znode。将节点创建为顺序Znode时,可以通过在原始名称上附加10位序列号来分配Znode的路径。
zookeeper如何选择leader呢?每个server启动后都是looking状态,它要么选举一个leader要么找到一个leader。有如下两种情况:
- 如果leader已经存在了,其他server就会通知它哪台server是leader,然后这台机必须和leader进行沟通以使得自己的state和leader的state保持一致。
- 如果leader不存在,也就是所有的server都是looking状态,那server必须相互沟通以选举出一个leader。一开始每台server都投票给自己,然后根据规则(voteZxid > myZxid) or (voteZxid = myZxid and voteSid > mySid)决定是否改变自己的投票(比如别人比自己更新那就投别人),当收到过半数投票后就会选一个胜出的,简单来说就是最新的那台server胜出。
写入原理:
zookeeper使用两步法来进行数据的写入。叫做zab协议,zookeeper atomic broadcast,即zookeeper原子广播协议。
具体步骤是这样:
- 客户端发起写请求给某台server,server如果不是leader再转给leader。
- Leader将客户端请求信息转化为事务Proposal(提议),同时为每个Proposal分配一个事务ID(Zxid)。
- Leader为每个Follower单独分配一个FIFO的队列,将需要广播的Proposal依次放入到队列中。
- Follower接收到Proposal后,首先将其以事务日志log的方式写入到本地磁盘中,写入成功后给Leader反馈一个ACK响应。
- Leader接收到半数以上Follower的ACK响应后,即认为消息发送成功,可以发送Commit消息。
- Leader向所有Follower广播Commit消息,同时自身也会完成事务提交。Follower接收到Commit消息后也会完成事务的提交,写入内存,commit后follower自身才有这时的zxid可用于leader挂掉后的leader选举,zookeeper同redis也是内存型的。
之所以分为两个阶段,是为了原子性。如果第一个步骤有过半的成功响应,则commit,否则不commit,不会存在中间状态。
另外,之所以要求过半的成功响应,是为了当集群挂掉后数据不会丢失。因为集群再次可用需要过半的server ok状态,因为之前有过半的成功响应,所以此时过半的server ok中必然存在log中保存有commit的数据,数据不会丢失。
4、工作原理
Zookeeper的核心是原子广播,这个机制保证了各个Server之间的同步。实现这个机制的协议叫做Zab协议。Zab协议有两种模式,它们分别是恢复模式(选主)和广播模式(同步)。当服务启动或者在领导者崩溃后,Zab就进入了恢复模式,当领导者被选举出来,且大多数Server完成了和leader的状态同步以后,恢复模式就结束了。状态同步保证了leader和Server具有相同的系统状态。
为了保证事务的顺序一致性,zookeeper采用了递增的事务id号(zxid)来标识事务。所有的提议(proposal)都在被提出的时候加上了zxid。实现中zxid是一个64位的数字,它高32位是epoch用来标识leader关系是否改变,每次一个leader被选出来,它都会有一个新的epoch,标识当前属于那个leader的统治时期。低32位用于递增计数。
在zookeeper集群中有三种角色和四种状态:
角色:leader,follower,observer
状态:leading,following,observing,looking
每个Server在工作过程中有4种状态:
LOOKING:当前Server不知道leader是谁,正在搜寻。
LEADING:当前Server即为选举出来的leader。
FOLLOWING:leader已经选举出来,当前Server与之同步。
OBSERVING:observer的行为在大多数情况下与follower完全一致,但是他们不参加选举和投票,而仅仅接受(observing)选举和投票的结果。
选举:
当leader崩溃或leader失去大多数的follower时,zookeeeper将进入恢复模式,恢复模式选举出新的leader让所有的server进入正确状态,选举算法包括两种:基于basic paxos和基于fast paxos,系统默认是fast paxos。
basic paxos
1.选举线程由当前Server发起选举的线程担任,其主要功能是对投票结果进行统计,并选出推荐的Server;
2 .选举线程首先向所有Server发起一次询问(包括自己);
3 .选举线程收到回复后,验证是否是自己发起的询问(验证zxid是否一致),然后获取对方的id(myid),并存储到当前询问对象列表中,最后获取对方提议的leader相关信息(id,zxid),并将这些信息存储到当次选举的投票记录表中;
4. 收到所有Server回复以后,就计算出zxid最大的那个Server,并将这个Server相关信息设置成下一次要投票的Server;
5. 线程将当前zxid最大的Server设置为当前Server要推荐的Leader,如果此时获胜的Server获得n/2 + 1的Server票数, 设置当前推荐的leader为获胜的Server,将根据获胜的Server相关信息设置自己的状态,否则,继续这个过程,直到leader被选举出来。
fast paxox
fast paxos流程是在选举过程中,某Server首先向所有Server提议自己要成为leader,当其它Server收到提议以后,解决epoch和zxid的冲突,并接受对方的提议,然后向对方发送接受提议完成的消息,重复这个流程,最后一定能选举出Leader。
5、同步流程
选完leader以后,zk就进入状态同步过程。
1. leader等待server连接;
2 .Follower连接leader,将最大的zxid发送给leader;
3 .Leader根据follower的zxid确定同步点;
4 .完成同步后通知follower 已经成为uptodate状态;
5 .Follower收到uptodate消息后,又可以重新接受client的请求进行服务了。
Zookeeper故障切换
ZooKeeper客户端可以自动地进行故障切换,切换至另一台ZooKeeper服务器。并且关键的一点是,在另一台服务器接替故障服务器之后,所有的会话和相关的短暂Znode仍然是有效的。在故障切换过程中,应用程序将收到断开连接和连接至服务的通知。当客户端断开连接时,观察通知将无法发送;但是当客户端成功恢复连接后,这些延迟的通知会被发送。当然,在客户端重新连接至另一台服务器的过程中,如果应用程序试图执行一个操作,这个操作将会失败。这充分体现了在真实的ZooKeeper应用中处理连接丢失异常的重要性。
为什么zookeeper集群的数目,一般为奇数个?
•Leader选举算法采用了Paxos协议;
•Paxos核心思想:当多数Server写成功,则任务数据写成功如果有3个Server,则两个写成功即可;如果有4或5个Server,则三个写成功即可。
•Server数目一般为奇数(3、5、7)如果有3个Server,则最多允许1个Server挂掉;如果有4个Server,则同样最多允许1个Server挂掉由此,
我们看出3台服务器和4台服务器的的容灾能力是一样的,所以为了节省服务器资源,一般我们采用奇数个数,作为服务器部署个数。
6、数据流程
1.在Client向Follwer发出一个写的请求
2.Follwer把请求发送给Leader
3.Leader接收到以后开始发起投票并通知Follwer进行投票
4.Follwer把投票结果发送给Leader
5.Leader将结果汇总后如果需要写入,则开始写入同时把写入操作通知给Leader,然后commit;
6.Follwer把请求结果返回给Client
Follower主要有四个功能:
• 1. 向Leader发送请求(PING消息、REQUEST消息、ACK消息、REVALIDATE消息);
• 2 .接收Leader消息并进行处理;
• 3 .接收Client的请求,如果为写请求,发送给Leader进行投票;
• 4 .返回Client结果。
Follower的消息循环处理如下几种来自Leader的消息:
• 1 .PING消息: 心跳消息;
• 2 .PROPOSAL消息:Leader发起的提案,要求Follower投票;
• 3 .COMMIT消息:服务器端最新一次提案的信息;
• 4 .UPTODATE消息:表明同步完成;
• 5 .REVALIDATE消息:根据Leader的REVALIDATE结果,关闭待revalidate的session还是允许其接受消息;
• 6 .SYNC消息:返回SYNC结果到客户端,这个消息最初由客户端发起,用来强制得到最新的更新。
leader 选举
半数通过
– 3台机器 挂一台 2>3/2
– 4台机器 挂2台 2!>4/2
1、A提案说,我要选自己,B你同意吗?C你同意吗?B说,我同意选A;C说,我同意选A。(注意,这里超过半数了,其实在现实世界选举已经成功了。
2、但是计算机世界是很严格,另外要理解算法,要继续模拟下去。
3、 接着B提案说,我要选自己,A你同意吗;A说,我已经超半数同意当选,你的提案无效;C说,A已经超半数同意当选,B提案无效。
4、 接着C提案说,我要选自己,A你同意吗;A说,我已经超半数同意当选,你的提案无效;B说,A已经超半数同意当选,C的提案无效。
5、选举已经产生了Leader,后面的都是follower,只能服从Leader的命令。而且这里还有个小细节,就是其实谁先启动谁当头。