Zookeeper:基础

来自Wikioe
跳到导航 跳到搜索


架构(Architecture)

Zookeeper:架构图.png
  1. Leader: ZooKeeper 集群工作的核心。
    • 事务请求(写操作)的唯一调度和处理者,保证集群事务处理的顺序性;集群内部各个服务的调度者。
    • 对于 create,setData,delete 等有写操作的请求,则需要统一转发给 leader 处理,leader 需要决定编号、执行操作,这个过程称为一个事务
  2. Follower: 处理客户端非事务(读操作)请求。
    • 转发事务请求给 Leader;
    • 参与集群;
    • leader 选举投票 2n-1 台可以做集群投票。
  3. Observer: 观察者角色。
    • 观察 ZooKeeper 集群的最新状态变化并将这些状态同步过来,其对于非事务请求可以进行独立处理,对于事务请求,则会转发给Leader服务器处理。
    • 不会参与任何形式的投票只提供服务,通常用于在不影响集群事务处理能力的前提下提升集群的非事务处理能力。

ZooKeeper集群中的节点

ZooKeeper集合中可以有不同数量的节点。那么,让我们分析一下在ZooKeeper工作流中更改节点的效果:

  1. 如果我们有单个节点,那么当该节点失败时,ZooKeeper集群就会失效。这就是为什么不建议在生产环境中使用它,因为它会导致“单点故障”。
  2. 如果我们有两个节点和一个节点故障,我们就没有多数,因为两个节点中有一个不是多数节点。
  3. 如果我们有三个节点而一个节点故障,那么我们有大多数,因此,这是最低要求。ZooKeeper集群在实际生产环境中必须至少有三个节点。
  4. 如果我们有四个节点而两个节点故障,它将再次故障。类似于有三个节点,额外节点不用于任何目的,


因此,最好添加奇数的节点,例如 3,5,7。

“为什么推荐使用奇数个节点?”

因为:
   1、奇数和偶数个数的节点,对于故障转移的效果几乎是一样的;
   2、但是节点越多对于集群写入操作越低效(所有节点都要写入相同数据)。
所以应该使用奇数个数的节点。

工作流

下图描述了ZooKeeper工作流:

Zookeeper:工作流.png

其中:

操作或组件 描述及说明
写入(write) 写入过程由leader节点处理
  • leader将写入请求转发到所有znode,并等待znode的回复。如果一半的znode回复,则写入过程完成。
读取(read) 读取由特定连接的znode在内部执行,因此不需要与集群进行交互
领导者(Leader) Leader是负责处理写入请求的Znode。
跟随者(Follower) follower从客户端接收写入请求,并将它们转发到leader znode。
复制数据库(replicated database) 它用于在zookeeper中存储数据。
  • 每个znode都有自己的数据库,每个znode在一致性的帮助下每次都有相同的数据。
请求处理器(request processor) 管理来自follower节点的写入请求
  • 只存在于leader节点。
原子广播(atomic broadcasts) 负责广播从leader节点到follower节点的变化


一旦ZooKeeper集合启动,它将等待客户端连接:

  • 客户端将连接到ZooKeeper集合中的一个节点,它可以是领导节点跟随节点
  • 一旦客户端被连接,节点将向特定客户端分配会话ID并向该客户端发送确认。
    • 如果客户端没有收到确认,它将尝试连接ZooKeeper集合中的另一个节点。
  • 一旦连接到节点,客户端将以有规律的间隔向节点发送心跳,以确保连接不会丢失。

连接之后,

  1. 如果客户端想要读取特定的znode:(读取
    它将会向具有znode路径的节点发送读取请求,并且节点通过从其自己的数据库获取来返回所请求的znode。【所以,在ZooKeeper集合中读取速度快。】
  2. 如果客户端想要将数据存储在ZooKeeper集合中:(写入
    1. 将znode路径和数据发送到服务器;
    2. 连接的服务器将该请求转发给领导者,然后领导者将向所有的跟随着重新发出写入请求:
      • 如果只有大部分节点(Quorum???)成功响应,而写入请求成功,则成功返回代码将被发送到客户端。
      • 否则,写入请求失败。

Leader 选举

Leader 选举是保证分布式数据一致性的关键所在。

Leader 选举分为 Zookeeper 集群初始化启动时选举和 Zookeeper 集群运行期间重新选举两种情况。

  • 若进行 Leader 选举,则至少需要两台机器,这里选取 3 台机器组成的服务器集群为例。


选举过程中的相关参数:

  1. 服务器ID(myid):在选举算法中,编号越大权重越大
  2. 事务ID(zxid):在选举算法中,值越大权重越大(说明数据越新)。
    • ZooKeeper 状态的每次变化都接收一个 ZXID(ZooKeeper 事务 id)形式的标记。
    • ZXID 是一个 64 位的数字,由 Leader 统一分配,全局唯一,不断递增
    • ZXID 展示了所有的 ZooKeeper 的变更顺序。(如果 zxid1 小于 zxid2 说明 zxid1 在 zxid2 之前发生)
  3. 逻辑时钟(epoch-logicalclock):在选举算法中,同一轮投票过程中的逻辑时钟值是相同的,每投完一次值会增加


选举过程中的节点状态:

  • LOOKING:寻找 Leader 状态,处于该状态需要进入选举流程;
  • LEADING:领导者状态,处于该状态的节点说明是角色已经是 Leader
  • FOLLOWING:跟随者状态,表示 Leader 已经选举出来,当前节点角色是 follower
  • OBSERVER:观察者状态,表明当前节点角色是 observer
    • OBSERVING 不参与投票。


初始化启动时选举

在集群初始化阶段,当有一台服务器 ZK1 启动时,其单独无法进行和完成 Leader 选举,当第二台服务器 ZK2 启动时,此时两台机器可以相互通信,每台机器都试图找到 Leader,于是进入 Leader 选举过程。


选举流程如下图:

Zookeeper:Leader选举:初始化启动时选举.png

节点的选举操作流程:

Zookeeper:Leader选举:初始化启动时选举(节点选举操作流程).png

选举过程如下:  

  1. 发出投票:每个Server发出一个投票。
    由于是初始情况,ZK1 和 ZK2 都会将自己作为 Leader 服务器来进行投票,每次投票会包含所推举的服务器的 myid 和 ZXID,使用(myid, ZXID)来表示,此时 ZK1 的投票为(1, 0),ZK2 的投票为(2, 0),然后各自将这个投票发给集群中其他机器。  
  2. 接受投票:接受来自各个服务器的投票。
    • 集群的每个服务器收到投票后,首先判断该投票的有效性,如检查是否是本轮投票(根据 epoch-logicalclock)、是否来自 LOOKING 状态的服务器。  
  3. 处理投票:针对每一个投票,服务器都需要将别人的投票和自己的投票进行比较。
    • 规则如下:
      1. 检查 epoch
      2. 先比较 zxid:zxid 比较大的服务器优先作为 Leader。
      3. 再比较 myid:如果 zxid 相同,myid 较大的服务器作为Leader服务器。
    对于 ZK1 而言,它的投票是(1, 0),接收 ZK2 的投票为(2, 0),首先会比较两者的 ZXID,均为 0,再比较 myid,此时 ZK2 的 myid 最大,于是 ZK2 胜。ZK1 更新自己的投票为(2, 0),并将投票重新发送给 ZK2。  
  4. 统计投票:每次投票后,服务器都会统计投票信息,判断是否已经有过半机器接受到相同的投票信息。
    对于 ZK1、ZK2 而言,都统计出集群中已经有两台机器接受了(2, 0)的投票信息,此时便认为已经选出 ZK2 作为Leader。  
  5. 改变服务器状态:一旦确定了 Leader,每个服务器就会更新自己的状态:如果是 Follower,那么就变更为 FOLLOWING,如果是 Leader,就变更为 LEADING。
    当新的 Zookeeper 节点 ZK3 启动时,发现已经有 Leader 了,不再选举,直接将直接的状态从 LOOKING 改为 FOLLOWING。

运行期间重新选举

在 Zookeeper 运行期间,如果 Leader 节点挂了,那么整个 Zookeeper 集群将暂停对外服务,进入新一轮Leader选举。


选举流程如下图:

Zookeeper:Leader选举:运行期间重新选举.png

选举过程如下:

  1. 变更状态:Leader 挂后,余下的非 Observer 服务器都会讲自己的服务器状态变更为 LOOKING,然后开始进入 Leader 选举过程。  
  2. 发出投票:每个Server会发出一个投票。
    在运行期间,每个服务器上的 ZXID 可能不同,此时假定 ZK1 的 ZXID 为 124,ZK3 的 ZXID 为 123;在第一轮投票中,ZK1 和 ZK3 都会投自己,产生投票(1, 124),(3, 123),然后各自将投票发送给集群中所有机器。  
  3. 接受投票:(同“初始化启动时选举”)
  4. 处理投票:(同“初始化启动时选举”)
    由于 ZK1 事务 ID 大,ZK1 将会成为 Leader。  
  5. 统计投票:(同“初始化启动时选举”)
  6. 改变服务器的状态:(同“初始化启动时选举”)