Zookeeper 分布式服务框架是 Apache Hadoop 的一个子项目,
主要是用来解决分布式应用中经常遇到的一些数据管理问题,
如:集群管理、统一命名服务、分布式配置管理、分布式消息队列jmq active amq、分布式锁、分布式通知协调等。
越来越多的分布式计算开始强依赖ZK,比如Storm、Hbase
=====================================================================================================
ZooKeeper数据模型的结构与Unix文件系统很类似,整体上可以看作是一棵树,每个节点称做一个ZNode。每个ZNode都可以通过其路径唯一标识,在每个ZNode上可存储少量数据(默认是1M, 可以通过配置修改, 通常不建议在ZNode上存储大量的数据)。
1 文件树的形式 节点唯一标识 2每个节点上可以挂数据
ZNode根据其本身的特性,可以分为下面两类:
Ephemeral ZNode: 临时型ZNode, 用户创建它之后,可以显式的删除,也可以在创建它的Session结束后,由ZooKeeper Server自动删除
znode -s -e 创建命令一一致
Zookeeper这种数据结构有如下这些特点:
1)每个子目录项如NameService都被称作为znode,这个znode是被它所在的路径唯一标识,如Server1这个znode的标识为/NameService/Server1。
(理解:圣诞树上挂很小的纸条)
2)znode可以有子节点目录,并且每个znode可以存储数据,注意EPHEMERAL(临时的)类型的目录节点不能有子节点目录。ZNode一个Sequential(带顺序的)的特性,如果创建的时候指定的话,该ZNode的名字后面会自动Append一个不断增加的SequenceNo(不断增加序列号) -s
3)znode是有版本的(version),每个znode中存储的数据可以有多个版本(可以存储多份小量数据),也就是一个访问路径中可以存储多份数据,version号自动增加。(联想事务)
czxid:事务编号 ----》
Zookeeper集群:分布式的数据管理---》
Zookeeper这种数据结构有如下这些特点:
1)每个子目录项如NameService都被称作为znode,这个znode是被它所在的路径唯一标识,如Server1这个znode的标识为/NameService/Server1。
(理解:圣诞树上挂很小的纸条)
2)znode可以有子节点目录,并且每个znode可以存储数据,注意EPHEMERAL(临时的)类型的目录节点不能有子节点目录。ZNode一个Sequential(带顺序的)的特性,如果创建的时候指定的话,该ZNode的名字后面会自动Append一个不断增加的SequenceNo(不断增加序列号) -s
3)znode是有版本的(version),每个znode中存储的数据可以有多个版本(可以存储多份小量数据),也就是一个访问路径中可以存储多份数据,version号自动增加。(联想事务)
czxid:事务编号 ----》
Zookeeper集群:分布式的数据管理---》
7)ZXID:每次对Zookeeper的状态的改变都会产生一个zxid(ZooKeeper Transaction Id),zxid是全局有序的,如果zxid1小于zxid2,则zxid1在zxid2之前发生。
8)Session: Client与ZooKeeper之间的通信,需要创建一个Session,这个Session会有一个超时时间。因为ZooKeeper集群会把Client的Session信息持久化,所以在Session没超时之前,Client与ZooKeeper Server的连接可以在各个ZooKeeper Server之间透明地移动。在实际的应用中,如果Client与Server之间的通信足够频繁,Session的维护就不需要其它额外的消息了。否则,ZooKeeper Client会每t/3 ms发一次心跳给Server,如果Client 2t/3 ms没收到来自Server的心跳回应,就会换到一个新的ZooKeeper Server上。这里t是用户配置的Session的超时时间。
Date --->date ---》myid 1 2 3 4 ---->
(client不论连接到哪个Server,展示给它都是同一个视图,这是zookeeper最重要的性能。)
在ZooKeeper集群中,读可以从任意一个ZooKeeper Server读 ls /,这一点是保证ZooKeeper比较好的读性能的关键;写的请求会先Forwarder到Leader,然后由Leader来通过ZooKeeper中的原子广播协议,将请求广播给所有的Follower,Leader收到一半以上的写成功的Ack后,就认为该写成功了,就会将该写进行持久化,并告诉客户端写成功了。
Zookeeper写入过程:election投票功能
正常情况下:集群中,形成读写分离的状态,读可以从任何一台机器进行读取,写只能通过一个机器。写入数据只能从主机写入。
Zk里面在写入数据的时候有独特的算法:
F1(zxid 0) f2 f3
Client -- f1 f2 f3
client提交请求,set /zhangsan 3
F1提议修改数据 - f2 - f3
F1 f2 f3 如果要进行文件修改,那么就会对应一个zxid这个zxid1是最新的,
F1提议修改数据,那么f1提议的数据一定要是大于0,f1 f2 f3只能接受最新的提议
F2 f3 f1 三个人都要判决,如果投票大于半数以上,那么这个提议就生效,三台机器将数据修改
集群中机器比较多:冲突
F1 zhangsan 3 zxid 1 f2 zhangan 4 zxid 2
争夺,f1 f2同时到达,那么就应该进行投票,如果其中一个提议投票大于半数,那么将要执行提议,另一个提议因为他的zxid和刚才执行完毕的zxid一样,这个提议属于过期提议,紧接着可以发送第二次的提议
Poxas:选举投票协议 fast poxas
因为当前的提议人数较多:
出现leader的角色,因为leader的出现,使得于这个提议的功能只能有leader执行,client ---leader那么你的这次请求会直接被提议
Client---follower---leader,因为leader的存在,使得所有的提议都交给leader,那么leader就会形成一个队列,所以所有的修改都是全局有序的
WAL和Snapshot
Edits (wal)
fsImage(snapshot)
Edits+fsimage ---->磁盘 ----》
快照 = secondaryNamenode的日志合并
Edits日志文件保存的是全部的操作信息 zk---->内存
Zk定期的将内存中的数据(metadata)----1h snapshot --- 磁盘保存的数据和内存中的数据小于等于一个小时的 snapshot进行加载到内存中 + edits日志文件中确实部分replay
和大多数分布式系统一样,ZooKeeper也有WAL(Write-Ahead-Log)edits,对于每一个更新操作,ZooKeeper都会先写WAL, 然后再对内存中的数据做更新,然后向Client通知更新结果。另外,ZooKeeper还会定期将内存中的目录树进行Snapshot fsimage,落地到磁盘上,这个跟HDFS中的FSImage是比较类似的。这么做的主要目的,一当然是数据的持久化,二是加快重启之后的恢复速度,如果全部通过Replay WAL的形式恢复的话,会比较慢。
Zk------>1---->Snapshot(复制) ---》wal
Zk-------》wal ------> 重新加载 (10) -----》10
对于每一个ZooKeeper客户端而言,所有的操作都是遵循FIFO顺序的,这一特性是由下面两个基本特性来保证的:一是ZooKeeper Client与Server之间的网络通信是基于TCP,TCP保证了Client/Server之间传输包的顺序;二是ZooKeeper Server执行客户端请求也是严格按照FIFO顺序的。Leader 队列 zxid
Client和Zookeeper集群建立连接,整个session状态变化如图所示:
如果Client因为Timeout 3和Zookeeper Server失去连接,client处在CONNECTING状态,会自动尝试再去连接Server,如果在session有效期内再次成功连接到某个Server,则回到CONNECTED状态。
注意:如果因为网络状态不好,client和Server失去联系,client会停留在当前状态,会尝试主动再次连接Zookeeper Server。client不能宣称自己的session expired(超时),session expired是由Zookeeper Server来决定的,client可以选择自己主动关闭session。 (session是 server端的连接)
Zookeeper watch是一种监听通知机制。Zookeeper所有的读操作getData(), getChildren(获取子节点)和 exists()都可以设置监视(watch),监视事件可以理解为一次性的触发器
*(一次性触发)One-time trigger
当设置监视的数据发生改变时,该监视事件会被发送到客户端,例如,如果客户端调用了getData("/znode1", true) 并且稍后 /znode1 节点上的数据发生了改变或者被删除了,客户端将会获取到 /znode1 发生变化的监视事件,而如果 /znode1 再一次发生了变化,除非客户端再次对/znode1 设置监视,否则客户端不会收到事件通知。
*(发送至客户端)Sent to the client
Zookeeper客户端和服务端是通过 socket 进行通信的,由于网络存在故障,所以监视事件很有可能不会成功地到达客户端,监视事件是异步发送至监视者的,Zookeeper 本身提供了顺序保证(ordering guarantee):即客户端只有首先看到了监视事件后,才会感知到它所设置监视的znode发生了变化(a client will never see a change for which it has set a watch until it first sees the watch event)。网络延迟或者其他因素可能导致不同的客户端在不同的时刻感知某一监视事件,但是不同的客户端所看到的一切具有一致的顺序。
在zookeeper的集群中,各个节点共有下面3种角色和4种状态:
Zookeeper的核心是原子广播(leader进行广播说明),这个机制保证了各个Server之间的同步。实现这个机制的协议叫做Zab协议(ZooKeeper Atomic Broadcast protocol)。Zab协议有两种模式,它们分别是恢复模式(Recovery选主)和广播模式(Broadcast同步)。当服务启动(leader每次都是从新选举的)或者在领导者崩溃后,Zab就进入了恢复模式(safemode),当领导者被选举出来,且大多数Server完成了和leader的状态同步以后(内存信息加载),恢复模式就结束了。状态同步保证了leader和Server具有相同的系统状态。
为了保证事务的顺序一致性,zookeeper采用了递增的事务id号(zxid)来标识事务。所有的提议(proposal)都在被提出的时候加上了zxid
每个Server在工作过程中有4种状态:(leader挂掉)
LOOKING:当前Server不知道leader是谁,正在搜寻。恢复模式
LEADING:当前Server即为选举出来的leader。选举完毕有leader
FOLLOWING:leader已经选举出来,当前Server与之同步。
OBSERVING:observer的行为在大多数情况下与follower完全一致,但是他们不参加选举和投票,而仅仅接受(observing)选举和投票的结果。
Leader Election
当leader崩溃或者leader失去大多数的follower,这时候zk进入恢复模式,恢复模式需要重新选举出一个新的leader,让所有的Server都恢复到一个正确的状态。
1.选举线程(组织者)由当前Server发起选举的线程担任,其主要功能是对投票结果进行统计,并选出推荐的Server;
2.选举线程首先向所有Server发起一次询问(包括自己);
3.选举线程收到回复后,验证是否是自己发起的询问(验证zxid是否一致)
,然后获取对方的id(myid(每一个server在集群中的编号)),并存储到当前询问对象列表中,最后获取对方提议的leader相关信息(id,zxid),并将这些信息存储到当次选举的投票记录表中;
4.收到所有Server回复以后,就计算出zxid最大的那个Server,并将这个Server相关信息设置成下一次要投票的Server;
5.线程将当前zxid最大的Server设置为当前Server要推荐的Leader,如果此时获胜的Server获得n/2 + 1的Server票数,设置当前推荐的leader为获胜的Server,将根据获胜的Server相关信息设置自己的状态,否则,继续这个过程,直到leader被选举出来。
通过流程分析我们可以得出:要使Leader获得多数Server的支持,则Server总数必须是奇数2n+1,且存活的Server的数目不得少于n+1.
奇数:1.因为奇数台机器,永远都不会两个leader拥有同样的follower
如果是三台机器 只有一台死去 3 1----2
如果是四台机器 只有一台死去 4 13
资源浪费,对于容错,容灾能力
每个Server启动后都会重复以上流程。在恢复模式下,如果是刚从崩溃状态恢复的或者刚启动的server还会从磁盘快照中恢复数据和会话信息,zk会记录事务日志并定期进行快照,方便在恢复时进行状态恢复。(dataLogDir)
当前leader的选举过程是fast paxos
Leader主要有三个功能:
1.恢复数据;
2.维持与Learner(follower observer)的心跳,接收Learner请求并判断Learner的请求消息类型;都需要有leader进行提议proposal
3.Learner的消息类型主要有PING消息、REQUEST消息、acknowlage消息、REVALIDATE消息,根据不同的消息类型,进行不同的处理。
PING消息是指Learner的心跳信息;REQUEST消息是Follower发送的提议信息,包括写请求及同步请求;
ACK消息是Follower的对提议的回复,超过半数的Follower通过,则commit该提议;REVALIDATE消息是用来延长SESSION有效时间。
,然后获取对方的id(myid(每一个server在集群中的编号)),并存储到当前询问对象列表中,最后获取对方提议的leader相关信息(id,zxid),并将这些信息存储到当次选举的投票记录表中;
4.收到所有Server回复以后,就计算出zxid最大的那个Server,并将这个Server相关信息设置成下一次要投票的Server;
5.线程将当前zxid最大的Server设置为当前Server要推荐的Leader,如果此时获胜的Server获得n/2 + 1的Server票数,设置当前推荐的leader为获胜的Server,将根据获胜的Server相关信息设置自己的状态,否则,继续这个过程,直到leader被选举出来。
通过流程分析我们可以得出:要使Leader获得多数Server的支持,则Server总数必须是奇数2n+1,且存活的Server的数目不得少于n+1.
奇数:1.因为奇数台机器,永远都不会两个leader拥有同样的follower
如果是三台机器 只有一台死去 3 1----2
如果是四台机器 只有一台死去 4 13
资源浪费,对于容错,容灾能力
每个Server启动后都会重复以上流程。在恢复模式下,如果是刚从崩溃状态恢复的或者刚启动的server还会从磁盘快照中恢复数据和会话信息,zk会记录事务日志并定期进行快照,方便在恢复时进行状态恢复。(dataLogDir)
当前leader的选举过程是fast paxos
Leader主要有三个功能:
1.恢复数据;
2.维持与Learner(follower observer)的心跳,接收Learner请求并判断Learner的请求消息类型;都需要有leader进行提议proposal
3.Learner的消息类型主要有PING消息、REQUEST消息、acknowlage消息、REVALIDATE消息,根据不同的消息类型,进行不同的处理。
PING消息是指Learner的心跳信息;REQUEST消息是Follower发送的提议信息,包括写请求及同步请求;
ACK消息是Follower的对提议的回复,超过半数的Follower通过,则commit该提议;
REVALIDATE消息是用来延长SESSION有效时间。
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结果到客户端,这个消息最初由客户端发起,用来强制得到最新的更新。
Zab: Broadcasting State Updates(事务)
Zookeeper Server接收到一次request,如果是follower,会转发给leader,Leader执行请求并通过Transaction的形式广播这次执行。
Zookeeper集群如何决定一个Transaction是否被commit执行?
通过“两段提交协议”(a two-phase commit):
Zab协议保证:
1) 如果leader以T1和T2的顺序广播,那么所有的Server必须先执行T1,再执行T2。
2) 如果任意一个Server以T1、T2的顺序commit执行,其他所有的Server也必须以T1、T2的顺序执行。
“两段提交协议”最大的问题是如果Leader发送了PROPOSAL消息后crash或暂时失去连接,会导致整个集群处在一种不确定的状态(follower不知道该放弃这次提交还是执行提交)。Zookeeper这时会选出新的leader,请求处理也会移到新的leader上,不同的leader由不同的epoch标识。
切换Leader时,需要解决下面两个问题:
Never forget delivered messages
Leader在commit投递到任何一台follower之前crash,只有它自己commit了。新Leader必须保证这个事务也必须commit。
Let go of messages that are skipped
Leader产生某个proposal,但是在crash之前,没有follower看到这个proposal。该server恢复时,必须丢弃这个proposal。
Zookeeper会尽量保证不会同时有2个活动的Leader,因为2个不同的Leader会导致集群处在一种不一致的状态,所以Zab协议同时保证:
1) 在新的leader广播Transaction之前,先前Leader commit的Transaction都会先执行。
2) 在任意时刻,都不会有2个Server同时有法定人数(quorum)的支持者。
这里的quorum是一半以上的Server数目,确切的说是有投票权力的Server(不包括Observer)。
原文:https://www.cnblogs.com/JBLi/p/10719530.html