Zookeeper工作原理

一 Zookeeper是什么

  ZooKeeper是一个分布式的,开放源码的分布式应用程序协调服务,是Google的Chubby一个开源的实现,它是集群的管理者,监视着集群中各个节点的状态根据节点提交的反馈进行下一步合理操作。最终,将简单易用的接口和性能高效、功能稳定的系统提供给用户,主要为了解决分布式架构下数据一致性问题,典型的应用场景有分布式配置中心、分布式注册中心、分布式锁、分布式队列、集群选举、分布式屏障、发布/订阅等场景。简单说zookeeper=文件系统+通知机制。

1,Zk的文件系统

每个子目录项如 NameService 都被称作为znode,和文件系统一样,我们能够自由的增加、删除znode,在一个znode下增加、删除子znode,唯一的不同在于znode是可以存储数据的。

  1. 持久化目录节点:客户端与zookeeper断开连接后,该节点依旧存在,只要不手动删除该节点,他将永远存在。
  2. 持久化顺序编号目录节点:客户端与zookeeper断开连接后,该节点依旧存在,只是zookeeper给该节点名称进行顺序编号。
  3. 临时目录节点:客户端与zookeeper断开连接后,该节点被删除。
  4. 临时顺序编号目录节点:客户端与zookeeper断开连接后,该节点被删除,只是zookeeper给该节点名称进行顺序编号。

Zookeeper工作原理_第1张图片

2,zk的通知机制

客户端注册监听它关心的目录节点,当目录节点发生变化(数据改变、被删除、子目录节点增加删除)时,zookeeper会通知客户端。监听事件如下:

1、None:连接建立事件
2、NodeCreated:节点创建
3、NodeDeleted:节点删除
4、NodeDataChanged:节点数据变化
5、NodeChildrenChanged:子节点列表变化
6、DataWatchRemoved:节点监听被移除
7、ChildWatchRemoved:子节点监听被移除

3,zk的角色

  • 领导者(leader),负责进行投票的发起和决议,更新系统状态
  • 学习者(learner),包括跟随者(follower)和观察者(observer),follower用于接受客户端请求并想客户端返回结果,在选主过程中参与投票
  • Observer可以接受客户端连接,将写请求转发给leader,但observer不参加投票过程,只同步leader的状态,observer的目的是为了扩展系统,提高读取速度。zoo.cfg中添加peerType=Observer,这表示这个server以observer角色运行,即不参与投票。再在所有 server的配置文件中,修改server.X配置项,在那些observer的节点上加上:observer后缀。例如,server.1对应的server要作为observer:Server.1=IP:2181:3181:observer
    这样配置后,ZooKeeper集群中的所有服务器节点都知道哪些节点扮演的是observer角色。
  • 客户端(client),请求发起方
    Zookeeper工作原理_第2张图片

4,CAP理论

zookeeper:满足数据的最终一致性,但是在leader选举过程中不可用。
Eureka:在任何时间都可用,但是可能有数据不一致的情况.

  • C是一致性,Consistency,就是各个节点保存的数据都是最新的。
  • A是Availability, 可用性,每次请求都可以获得响应,但是没法保证是最新的响应。
  • P是分区容错性(Partition tolerance),就是每个节点可能都存在于不同的子网络,也就是不同的分区,不同分区之间的通信总是有可能发生故障的,或者总是有可能存在一些节点挂了的情况。

可以认为P总是成立的,C和A是无法同时做到。所以一般对于数据一致性要求特别高的业务,例如支付,交易相关的业务,就是会优先保证一致性C和分区容错性P,就是保证数据一致性,例如让所有子节点都收到更新后才算提交成功,就像MySQL主从同步中的全同步模式一样。普通的业务是优先保证可用性A和分区容错性P,比如在MySQL主从同步时,默认就是异步的方式,我们执行一条更新SQL,只需要主节点更新成功就行就对事务进行提交,不需要等待从节点更新数据成功,主节点会异步把SQL发送给从节点。

二 zk的工作流程

Zookeeper的核心是原子广播,这个机制保证了各个Server之间的同步。实现这个机制的协议叫做Zab协议。Zab协议有两种模式,它们分别是恢复模式(选主)和广播模式(同步)。当服务启动或者在领导者崩溃后,Zab就进入了恢复模式,当领导者被选举出来,且大多数Server完成了和leader的状态同步以后 ,恢复模式就结束了。状态同步保证了leader和Server具有相同的系统状态。

为了保证事务的顺序一致性,zookeeper采用了递增的事务id号(zxid) 来标识事务。所有的提议(proposal)都在被提出的时候加上了zxid。实现中zxid是一个64位的数字,它高32位是epoch用来标识leader关系是否改变,每次一个leader被选出来,它都会有一个新的epoch,标识当前属于那个leader的统治时期。低32位用于递增计数。
每个Server在工作过程中有三种状态:

  1. LOOKING:当前Server不知道leader是谁,正在搜寻
  2. LEADING:当前Server即为选举出来的leader
  3. FOLLOWING:leader已经选举出来,当前Server与之同步

1,zk的选主流程

   当leader崩溃或者leader失去大多数的follower,这时候zk进入恢复模式,恢复模式需要重新选举出一个新的leader,让所有的 Server都恢复到一个正确的状态。Zk的选举算法有两种:一种是基于basic paxos实现的,另外一种是基于fast paxos算法实现的。系统默认的选举算法为fast paxos。

1)basic paxos流程:

  1. 选举线程由当前Server发起,其主要功能是对投票结果进行统计,并推选出Leader
  2. 选举线程首先向所有的server发次一次询问(包括自己)
  3. 选举线程收到回复后,验证是否是自己发起的询问(验证zxid),然后获取对方的id(myId),并存储到当前询问对象列表中,最后获取对方提议的leader相关信息(zxid和myid),并将这些信息存储到当次选举的投票记录中。
  4. 收到所有的server回复后,就计算出zxid最大的server,并将这个Server相关的信息设置成下次要投票成leader的server。
  5. 线程将当前最大zxid的server设置成推荐leader时,如果获得n/2+1的server同意,则zxid最大的server称为leader,然后将根据获胜的server相关的信息来设置自己的状态,否则继续当前流程,直到leader选出。

   通过流程分析我们可以得出:要使Leader获得多数Server的支持,则Server总数必须是奇数2n+1,且存活的Server的数目不得少于n+1。
   每个Server启动后都会重复以上流程。在恢复模式下,如果是刚从崩溃状态恢复的或者刚启动的server还会从磁盘快照中恢复数据和会话信息,zk会记录事务日志并定期进行快照,方便在恢复时进行状态恢复。选主的具体流程图如下所示:
Zookeeper工作原理_第3张图片

2)fast paxos流程
是在选举过程中,某Server首先向所有Server提议自己要成为leader,当其它Server收到提议以后,解决epoch和 zxid的冲突,并接受对方的提议,然后向对方发送接受提议完成的消息,重复这个流程,最后一定能选举出Leader。其流程图如下所示:
Zookeeper工作原理_第4张图片
如果还不明白可以参考:
https://blog.csdn.net/qq_35128600/article/details/104798113

2,zk的同步流程

选完leader以后,zk就进入状态同步过程。

  1. leader等待server连接;
  2. Follower连接leader,将最大的zxid发送给leader;
  3. Leader根据follower的zxid确定同步点;
  4. 完成同步后通知follower 已经成为uptodate状态;
  5. Follower收到uptodate消息后,又可以重新接受client的请求进行服务了。

流程图如下所示:
Zookeeper工作原理_第5张图片

3,zk的工作流程

ZooKeeper集群中的每个server都能为客户端提供读、写服务。对于客户端的读请求,server会直接从它本地的内存数据库中取出数据返回给客户端,这个过程不涉及其它任何操作,也不会联系leader。对于客户端的写请求,因为写操作会修改znode的数据、状态,所以必须要在ZooKeeper集群中进行协调。处理过程如下:
Zookeeper工作原理_第6张图片
如图所示:

  1. 收到写请求的那个server,首先将写请求发送给leader。
  2. leader收到来自follower(或observer)的写请求后,首先计算这次写操作之后的状态,然后将这个写请求转换成带有各种状态的事务(如版本号、zxid等等)。
  3. leader将这个事务以提议的方式广播出去(即发送proposal)。
  4. 所有follower收到proposal后,对这个提议进行投票,投票完成后返回ack给leader。follower的投票只有两种方式:(1)确认这次提议表示同意;(2)丢弃这次提议表示不同意。
  5. leader收集投票结果,只要投票数量达到了大多数的要求(例如,5个节点的集群,3个或3个以上的节点才算大多数),这次提议就通过。
  6. 提议通过后,leader向所有server发送一个提交通知。
  7. 所有节点将这次事务写入事务日志,并进行提交。
  8. 提交后,收到写请求的那个server向客户端返回成功信息。

上面只是简单的介绍了下zk的写流程,实际过程中,leader和foller还有好多其他的功能,具体如下。

1.Leader的工作流程

Leader的主要功能是:恢复数据和维持与foller的心跳,并接收foller的请求消息类型。leader接收的消息类型主要有

  • PING消息:指的是foller的心跳信息。
  • REQUEST消息:foller发送的提议信息,包括写请求和同步数据请求
  • ACK消息:foller对于提议信息的恢复,超过半数的foller同意,则该commit该提议。
  • REVALIDATE消息:是用来延长session的有效时间。

Leader的工作流程简图如下所示,在实际实现中,流程要比下图复杂得多,启动了三个线程来实现功能。

2.foller的工作流程

Follower主要有四个功能:

  1. 向Leader发送请求(PING消息、REQUEST消息、ACK消息、REVALIDATE消息)
  2. 接收Leader消息并进行处理;
  3. 接收Client的请求,如果为写请求,发送给Leader进行投票;
  4. 返回Client结果。

Follower的消息循环处理如下几种来自Leader的消息:

  • PING消息: 心跳消息;
  • PROPOSAL消息:Leader发起的提案,要求Follower投票;
  • COMMIT消息:服务器端最新一次提案的信息;
  • UPTODATE消息:表明同步完成;
  • REVALIDATE消息:根据Leader的REVALIDATE结果,关闭待revalidate的session还是允许其接受消息;
  • SYNC消息:返回SYNC结果到客户端,这个消息最初由客户端发起,用来强制得到最新的更新。

Follower的工作流程简图如下所示,在实际实现中,Follower是通过5个线程来实现功能的
Zookeeper工作原理_第7张图片

三 zk的常见应用场景

1,zk的命名服务

  命名服务是指通过指定的名字来获取资源或者服务的地址,提供者的信息。利用Zookeeper很容易创建一个全局的路径,而这个路径就可以作为一个名字,它可以指向集群中的集群,提供的服务的地址,远程对象等。简单来说使用Zookeeper做命名服务就是用路径作为名字,路径上的数据就是其名字指向的实体。
  例如:Dubbo中使用ZooKeeper来作为其命名服务,维护全局的服务地址列表。在Dubbo实现中:

  • 服务提供者在启动的时候,向ZK上的指定节点/dubbo/${serviceName}/providers目录下写入自己的URL地址,这个操作就完成了服务的发布。
  • 服务消费者启动的时候,订阅/dubbo/{serviceName}/providers目录下的提供者URL地址, 并向/dubbo/{serviceName} /consumers目录下写入自己的URL地址。

2,zk的配置管理

程序总是需要配置的,如果程序分散部署在多台机器上,要逐个改变配置就变得困难。现在把这些配置全部放到zookeeper上去,保存在 Zookeeper 的某个目录节点中,然后所有相关应用程序对这个目录节点进行监听,一旦配置信息发生变化,每个应用程序就会收到 Zookeeper 的通知,然后从 Zookeeper 获取新的配置信息应用到系统中就好
Zookeeper工作原理_第8张图片

3,zk的注册中心

所谓集群管理无在乎两点:是否有机器退出和加入、选举master。

  1. 对于第一点,所有机器约定在父目录GroupMembers下创建临时目录节点,然后监听父目录节点的子节点变化消息。一旦有机器挂掉,该机器与 zookeeper的连接断开,其所创建的临时目录节点被删除,所有其他机器都收到通知:某个兄弟目录被删除,于是,所有人都知道:它上船了。新机器加入也是类似,所有机器收到通知:新兄弟目录加入,highcount又有了
  2. 对于第二点,我们稍微改变一下,所有机器创建临时顺序编号目录节点,每次选取编号最小的机器作为master就好。

Zookeeper工作原理_第9张图片

4,zk的分布式锁

有了zookeeper的一致性文件系统,锁的问题变得容易。锁服务可以分为两类,一个是保持独占,另一个是控制时序。

  1. 对于第一类,我们将zookeeper上的一个znode看作是一把锁,通过createznode的方式来实现。所有客户端都去创建 /distribute_lock 节点,最终成功创建的那个客户端也即拥有了这把锁。用完删除掉自己创建的distribute_lock 节点就释放出锁。
  2. 对于第二类, /distribute_lock 已经预先存在,所有客户端在它下面创建临时顺序编号目录节点,和选master一样,编号最小的获得锁,用完删除,依次方便。

Zookeeper工作原理_第10张图片

5,zk的队列管理

两种类型的队列:

  1. 同步队列,当一个队列的成员都聚齐时,这个队列才可用,否则一直等待所有成员到达。在约定目录下创建临时目录节点,监听节点数目是否是我们要求的数目。
  2. 队列按照 FIFO 方式进行入队和出队操作。和分布式锁服务中的控制时序场景基本原理一致,入列有编号,出列按编号。

四 zk的常见问题

1,zk的节点信息

通过stat命令来查看主要信息,其中信息有:

1、cZxid:创建znode的事务id(Zxid的值)。
2、mZxid:最后修改znode的事务id。
3、pZxid:最后添加或删除子节点的事务id(子节点列表发生变化才会发生改变)。
4、ctime:znode创建时间。
5、mtime:znode最近修改时间。
6、dataVersion:znode的当前数据版本。
7、cversion:znode的子节点结果集版本(一个节点的子节点增加、删除都会影响这个版本)。
8、aclVersion:表示对此znode的acl版本。
9、ephemeralOwner:znode是临时znode时,表示znode所有者的sessionid,如果znode不是临时节点,则该字段设置为零。
10、dataLength:znode数据字段的长度。

2,zookeeper创建节点

1、创建持久节点:create /节点名称
2、创建持久顺序节点:create -s /节点名称
3、创建临时节点:create -e /节点名称
4、创建临时顺序节点:create -e -s /节点名称
5、监听节点:get -w /节点名称

3,zookeeper的权限控制

zookeeper有ACL( Access Control List )权限控制,可以控制节点的读写操作,保证数据的安全性。
ACL(Access Control List),分别由权限模式,授权对象和权限信息组成
1)权限模式:

  1. 范围验证:zookeeper可以通过对一个ip或者一段ip进行授权。
  2. 口令验证:用户名密码方式验证

2)授权对象: 就是把权限授予给谁,如果是范围验证方式,那么授权对象就是ip地址,如果是口令验证,授权对象就是用户名。

3)权限信息:

  1. 数据节点(c:create)创建权限,授予权限的对象可以在数据节点下创建子节点。
  2. 数据节点(w:wirte)更新权限,授予权限的对象可以更新该数据节点
  3. 数据节点(r:read)读取权限,授予权限的对象可以读取该节点的内容以及子节点的列表信息。
  4. 数据节点(d:delete)删除权限,授予权限的对象可以删除该数据节点的子节点。
  5. 数据节点(a:admin)管理者权限,授予权限的对象可以对该数据节点体进行ACL权限设置。

可以通过getAcl来获取某个节点的权限信息,通过setAcl来设置某个节点的权限信息。

4,zookeeper的数据持久化

zookeeper和redis很像,数据都是在内存中的,持久化也是两种方式,一种是记录事务日志,一种是快照方式。
记录事务日志磁盘会进行IO操作,事务日志的不断增多会触发磁盘为文件开辟新的磁盘块,所以为了提升磁盘的效率,可以在创建文件的时候
就向操作系统申请一块大一点的磁盘块,通过参数zookeeper.preAllocSize配置。事务日志的存放地址通过zoo.cfg配置文件中的dataDir来指定。


参考文献:
https://blog.csdn.net/u014374173/article/details/105173043
https://blog.csdn.net/weixin_38612401/article/details/125216821
leader选举:
https://blog.csdn.net/qq_35128600/article/details/104798113

你可能感兴趣的:(分布式,zookeeper,zk角色,选主流程,工作流程,基本原理)