ZooKeeper架构

下图是 Zookeeper 的架构图,ZooKeeper 集群中包含 Leader、Follower 以及 Observer 三个角色:

  • Leader:负责进行投票的发起和决议,更新系统状态,Leader 是由选举产生;

  • Follower: 用于接受客户端请求并向客户端返回结果,在选主过程中参与投票;

  • Observer:可以接受客户端连接,接受读写请求,写请求转发给 Leader,但 Observer 不参加投票过程,只同步 Leader 的状态,Observer 的目的是为了扩展系统,提高读取速度。

Client 是 Zookeeper 的客户端,请求发起方。

Zookeeper架构

为什么引入了 Observer 节点?

Observer 能很好地对 Zookeeper 集群进行扩展,Observer 可以提供 Client 读写,但不参与投票。因此,Observer 节点对集群不影响投票耗时,也不影响集群选举。另外,加入 Observer 对读性能是一个很大的提升。

独立模式和仲裁模式

应用通过客户端库来对ZooKeeper实现了调用。客户端库负责与ZooKeeper服务器端进行交互。下展示了客户端与服务器端之间的关系。每一个客户端导入客户端库,之后便可以与任何ZooKeeper的节点进行通信。ZooKeeper服务器端运行于两种模式下:独立模式(standalone)仲裁模式(quorum)独立模式几乎与其术语所描述的一样:有一个单独的服务器,ZooKeeper状态无法复制仲裁模式下,具有一组ZooKeeper服务器,我们称为ZooKeeper集合(ZooKeeper ensemble),它们之前可以进行状态的复制,并同时为服务于客户端的请求。从这个角度出发,我们使用术语“ZooKeeper集合”来表示一个服务器设施,这一设施可以由独立模式的一个服务器组成,也可以仲裁模式下的多个服务器组成。

ZooKeeper架构总览

ZooKeeper高可用

Zookeeper 系统中只要集群中存在超过一半的节点(这里指的是投票节点即非 Observer 节点)能够正常工作,那么整个集群就能够正常对外服务

基于此,如果想搭建一个能够允许 N 台机器 down 掉的集群,那么就要部署一个由 2*N+1 台服务器构成的 ZooKeeper 集群。 因此,如果部署了 3 个 Zookeeper 节点(非 Observer),则如果至少有 2个节点可用则整个集群就可用,意味着 1 个节点故障,不影响 Zookeeper 集群对外提供服务;如果部署了 5 个节点,意味着 2 个节点同时故障,Zookeeper 集群依然能够正常对外提供服务。

Zookeeper 集群部署的节点(非 Observer)数一般为奇数个

部署的节点数一般为奇数个,这里不是说不能为偶数个。

通过以上可以发现,3台服务器和4台服务器都最多允许1台服务器挂掉,5台服务器和6台服务器都最多允许2台服务器挂掉,明显4台服务器成本高于3台服务器成本,6台服务器成本高于5服务器成本。这是由于半数以上投票通过决定的。

ZooKeeper会话

在对ZooKeeper集合执行任何请求前,一个客户端必须先与服务建立会话。会话的概念非常重要,对ZooKeeper的运行也非常关键。客户端提交给ZooKeeper的所有操作均关联在一个会话上。当一个会话因某种原因而中止时,在这个会话期间创建的临时节点将会消失。

会话提供了顺序保障,这就意味着同一个会话中的请求会以FIFO(先进先出)顺序执行。通常,一个客户端只打开一个会话,因此客户端请求将全部以FIFO顺序执行。如果客户端拥有多个并发的会话,FIFO顺序在多个会话之间未必能够保持。而即使一个客户端中连贯的会话并不重叠,也未必能够保证FIFO顺序。

会话的状态和声明周期

会话的生命周期(lifetime)是指会话从创建到结束的时期,无论会话正常关闭还是因超时而导致过期。一个会话的主要可能状态大多是简单明了的:CONNECTINGCONNECTEDCLOSEDNOT_CONNECTED。状态的转换依赖于发生在客户端与服务之间的各种事件(见下图)。

状态及状态的转换

  • 一个会话从状态开始,当ZooKeeper客户端初始化后转换到状态(箭头1)。

  • 正常情况下,成功与ZooKeeper服务器建立连接后,会话转换到状态(箭头2)。

  • 当客户端与ZooKeeper服务器断开连接或者无法收到服务器的响应式,它就会转换回CONNECTING状态(箭头3)并尝试发现其他ZooKeeper服务器。

  • 如果可以发现另一个服务器或重连到原来的服务器,当服务器确认会话有效后,状态又会转换回状态。

  • 否则,它将会声明会话过期,然后转换到状态(箭头4)。

  • 应用也可以显式地关闭会话(箭头4和箭头5)。

注意:发生网络分区时等待CONNECTING

如果一个客户端与服务器因超时而断开连接,客户端仍然保持CONNECTING状态。如果因网络分区问题导致客户端与ZooKeeper集合被隔离而发生连接断开,那么其状态将会一直保持,直到显式地关闭这个会话,或者分区问题修复后,客户端能够获悉ZooKeeper服务器发送的会话已经过期。发生这种行为是因为ZooKeeper集合对声明会话超时负责,而不是客户端负责。直到客户端获悉ZooKeeper会话过期,否则客户端不能声明自己的会话过期。然而,客户端可以选择关闭会话。

创建一个会话时,你需要设置会话超时这个重要的参数,这个参数设置了ZooKeeper服务允许会话被声明为超时之前存在的时间。如果经过时间t之后服务接收不到这个会话的任何消息,服务就会声明会话过期。而在客户端侧,如果经过t/3的时间未收到任何消息,客户端将向服务器发送心跳消息。在经过2t/3时间后,ZooKeeper客户端开始寻找其他的服务器,而此时它还有t/3时间去寻找。

注意:客户端会尝试连接哪一个服务器?

在仲裁模式下,客户端有多个服务器可以连接,而在独立模式下,客户端只能尝试重新连接单个服务器。在仲裁模式中,应用需要传递可用的服务器列表给客户端,告知客户端可以连接的服务器信息并选择一个进行连接。

当尝试连接到一个不同的服务器时,非常重要的是,这个服务器的ZooKeeper状态要与最后连接的服务器的ZooKeeper状态保持最新。ZooKeeper通过在服务中排序更新操作来决定状态是否最新。ZooKeeper确保每一个变化相对于所有其他已执行的更新是完全有序的。因此,如果一个客户端在位置i观察到一个更新,它就不能连接到只观察到i'<i的服务器上。在ZooKeeper实现中,系统根据每一个更新建立的顺序来分配给事务标识符。下图描述了在重连情况下事务标识符(zkid)的使用。当客户端因超时与s1 断开连接后,客户端开始尝试连接s2 ,但s2 延迟于客户端所知的变化。然而,s3 对这个变化的情况与客户端保持一致,所以s3 可以安全连接。

客户端重连的例子

参考文档

Zookeeper 集群高可用部署详解

举报/反馈

高级互联网专家

8.7万获赞 2.9万粉丝
互联网软件“卓越技术顾问”,顶级软件架构开发者(承接各类软件项目开发,欢迎合作)<网站、管理后台、app、小程序、服务系统、技术支持等>!
科技领域创作者
关注
0
0
收藏
分享