ZK简介

1 会话

会话:客户端与服务端创建并保持TCP连接的过程。

1.1 会话状态

当客户端与服务端成功完成连接创建后,就会建立一个会话。ZK会话在整个运行期间的生命周期,会在不同的会话状态之间进行切换:

  • CONNECTING
    • 一旦客户端开始创建对象,客户端状态就会为CONNECTING
    • 网络闪断或其他原因,导致客户端和服务器端之间连接断开
  • CONNECTED
  • RECONNECTING
  • RECONNECTED
  • CLOSED
    • 会话超时
    • 权限校验失败
    • 客户端主动退出程序

1.2 会话基本信息

Zookeeper使用SessionImpl实现来表示会话的基本信息

public static class SessionImpl implements Session {
    // sessionId全局唯一
    final long sessionId;
    // 会话的超时时间
    final int timeout;
    // 下次会话的超时时间
    long tickTime;
    // 会话是否关闭
    boolean isClosing;
}

1.3 会话管理

ZK的会话管理称为分桶策略:将类似的会话放在同一块区域中进行管理,便于ZK对会话进行不同区块的隔离处理,以及同一区块的统一处理。如下图:
image

会话激活

为保证会话的有效性,ZK在运行过程中,客户端会在会话超时时间过期范围内向服务端发送PING请求保持会话的有效性。同时服务端不断地接收来自客户端的心跳检测,并且需要重新激活对应的客户端会话,称之为TouchSession

激活会话的情况有2种:

  • 客户端向服务端发送请求:读或写请求
  • 客户端发现sessionTimeout/3时间内,未与服务端进行通信,客户端主动发起PING请求

1.4 会话清理

会话清理步骤:

  • 标记会话为"已关闭"

    isClosing标记为true,即使会话清理期间接收到该客户的新请求,也不会处理

  • 发起会话关闭
  • 收集需要清理的临时节点

    临界情况考虑,在会话关闭请求之前,正好有如下2类请求达到,并正在处理中:
    假如当前收集到的临时节点列表为tmpNodes。下面两种情况的共同点是,事务处理尚未完成,因此还没有应用到内存数据库中。

    • 节点删除请求:将节点从tmpNodes中移除,避免重复删除。
    • 临时节点创建请求:将请求对应的数据节点路径添加到tmpNodes节点集中
  • 添加"节点删除"事务变更

    将临时节点集逐个转换成"节点删除"请求,并放入事务变更队列中

  • 删除临时节点

    删除内存数据库中tmpNodes对应的临时节点

  • 移除会话
  • 关闭NIOServerCnxn

1.5 重连

客户端和服务端在网络断开期间,ZK客户端会自动进行重连,直至成功连接到ZK集群中的某个服务器。这种情况下,客户端可能会处于如下两种状态:

  • CONNECTED:若在超时时间内连接上,重连成功
  • EXPIRED:若超时时间外连上,服务端其实已经认定该会话失效,进行了清理操作。因此为非法会话

ZK中客户端和服务端之间维持TCP长连接,在连接期间,若客户端和服务端出现连接断开后,客户端可能会看到如下几种异常:

  • CONNECTION_LOSS,连接断开

    CONNECTION_LOSS情况下,客户端会自动从地址列表中重新逐个选取新的地址并尝试重新连接。

  • SESSIN_EXPIRED,会话失效

    重连时间超过了会话超时时间,服务端认为该会话结束,会清理该会话。但客户端本身不知道会话已经失效,且状态仍未DISCONNECTED,之后客户端重新连接服务器,此时服务器会告诉客户端会话失效。

  • SESSION_MOVE,会话转移

    客户端会话从A服务器转移到B服务器上(断开重连到B服务器)。在3.2.0版本之前,会话转移没有被明确提出,因此会出现如下异常情况

    • ZK集群有S1、S2、S3。C1和S1建立会话:
      T1时刻,C1向S1发送R1请求:SetData("/ses/test", 1),但请求发送刚结束,连接断开。
      T2时刻,C1重新连接到S2,并发送R2请求:SetData("/ses/test", 2)。
      结果R2请求先处理,R1请求之后处理。

    因此之后,ZK提出会话转移的概念。服务端在处理客户端请求时,检查会话的owner,若会话owner不是当前服务器,会抛出SessionMovedException异常。

2 分布式一致性

分布式系统中,为了保持事务处理的ACID特性,引入了协调者来统一调度所有参与者的事务请求。基于该思想,衍生出了2PC和3PC协议。

2.1 二阶段提交

2PC是一种一致性协议,用于保证分布式系统数据的一致性。目前绝大多数关系型数据库都采用2PC协议来完成分布式事务(XA Transaction)。协议的执行流程如下:

2.1.1 阶段1:提交事务请求

  1. 发送事务请求
    协调者向所有参与者发送事务内容,询问是否可以执行事务提交操作,并开始等待所有参与者的响应
  2. 执行事务
    所有参与者执行事务,将Undo和Redo信息记入事务日志
  3. 反馈事务请求结果
    参与者成功执行了事务,反馈给协调者成功响应;否则反馈失败响应

2.1.2 阶段2:执行事务提交

该阶段有2种情况:执行事务提交、中断事务。

1. 事务提交
若所有参与者协调者反馈的都是成功响应

  1. 协调者向所有参与者发送提交事务请求
  2. 参与者执行事务提交,提交完成释放事务资源
  3. 参与者将事务提交后,反馈提交结果给协调者
  4. 协调者完成事务

2. 中断事务
若任一参与者协调者反馈失败响应、或协调者等待超时等等。

  1. 协调者向所有参与者发送回滚事务请求
  2. 参与者根据Undo日志进行事务回滚,提交完成释放事务资源
  3. 参与者将事务回滚后,反馈提交结果给协调者
  4. 协调者完成事务中断

2.2 ZAB协议

2.2.1 Zookeeper分布式一致性特性

  • 顺序一致性。同一个Client发起的事务请求,最终将严格地按照其发起顺序被应用到Zookeeper中。
  • 原子性。所有事务请求的处理结果在整个分布式系统中的所有节点数据一致。
  • 单一视图。无论Client连接的是哪个Zookeeper服务器,其看到的服务端数据模型都是一致的
  • 可靠性。事务所引起的服务端状态变更,会被一直保留,除非又有新事务对其变更
  • 实时性。Zookeeper仅保证在一定时间范围内,Client最终一定能从服务端读取到最新的数据状态。

2.2.2 ZAB协议概述

ZAB:Zookeeper Atomic Broadcast,原子消息广播协议(一致性协议)。它是一种特别为ZK设计的崩溃可恢复的原子消息广播算法。ZAB协议有2种模式:崩溃恢复和消息广播。

协议简介

  1. 当整个应用启动时,或Leader崩溃退出、重启、网络中断等异常情况下,ZAB协议会进入恢复模式并选举产生新的Leader服务器。

    启动时、或Leader崩溃,服务器会进入到LOOKING状态,开启LEADER选举过程

  2. 当选举出新的Leader,同时集群中已经有过半的机器与该Leader完成了状态同步后,ZAB协议就会退出恢复模式,进入消息广播模式。

消息广播

类似二阶段提交过程。Leader会为每个Follower都各自分配一个单独的队列,针对需要广播的事务请求(Proposal)依次放入到这些队列中,并且根据FIFO策略进行消息发送。

Follower接收到Proposal后,首先将Proposal以事务日志的形式写入到本地磁盘,并在写入成功后反馈给Leader,Leader接收到超过半数的响应后,就会广播COMMIT消息让所有的Follower提交事务,同时Leader自身也会提交事务。

崩溃恢复

一旦Leader服务器崩溃或Leader服务失去了过半的Follower联系,就会进入崩溃恢复模式,此时需要进行Leader的选举(事务编号ZXID):

  • 变更Follower的状态

    当leader挂了,Follower会将自己的服务器状态变更为LOOKING

  • 发起投票

    每个服务器都发起一个投票(myid, ZXID)。

  • 仲裁投票

    每个服务器都会选举:首先对比ZXID最大,选择ZXID最大的投票,当ZXID相等时就选择myid最大的服务器

  • 统计投票

    某个投票超过半数则认为是Leader,其余服务器为Follower

posted @ 2019-03-13 14:43  wolf_w  阅读(1369)  评论(0编辑  收藏  举报