Zookeeper 的通信及会话

1. 前言

在前面的章节中,我们学习了 Zookeeper 的 Java 客户端 ZkClient 和 Curator 的基本使用,那这些客户端是如何与 Zookeeper 服务端建立通信的呢?我们就带着这个问题开启本节的内容。

2. Zookeeper 的通信协议

首先我们从 Zookeeper 的通信协议开始说起。我们都知道最常用的网络通信协议 TCP/IP 协议,而 Zookeeper 就是基于 TCP/IP 协议实现了自己的通信方式。
Zookeeper 的通信协议
Zookeeper 的通信协议分为两部分,请求协议和响应协议,接下来我们分别进行介绍。

2.1 请求协议

请求协议是 Zookeeper Client 向 Zookeeper Server 发送请求时所使用的协议,包含了请求头和请求体。在 Zookeeper 中使用了 RequestHeader 类作为请求头。

// RequestHeader 类实现了 Record 接口来进行序列化操作
public class RequestHeader implements Record{
    // 客户端序号,记录客户端请求发起的顺序
    private int xid;
    // 请求类型
    private int type;
}

而请求体会根据不同的请求类型来进行封装,接下来我们以会话创建、节点查询、节点更新三种类型的请求分别介绍相对应的请求体。

  • 会话创建请求
    当 Zookeeper 客户端向 Zookeeper 服务端发送会话创建的请求时,使用 ConnectRequest 类来封装请求体:
// ConnectRequest 类实现了 Record 接口来进行序列化操作
public class ConnectRequest implements Record {
	// 请求协议的版本信息
    private int protocolVersion;
    // 最后一次接收到响应的服务端 zxid
    private long lastZxidSeen;
    // 会话超时时间
    private int timeOut;
    // 会话 id
    private long sessionId;
    // 密码
    private byte[] passwd;
}
  • 节点查询请求
    当 Zookeeper 客户端向 Zookeeper 服务端发送节点查询的请求时,使用 GetDataRequest 类来封装请求体:
    // GetDataRequest 类实现了 Record 接口来进行序列化操作
    public class GetDataRequest implements Record {
        // 节点全路径
        private String path;
        // 是否对该节点开启监听
        private boolean watch;
    }
    
  • 节点更新请求
    当 Zookeeper 客户端向 Zookeeper 服务端发送节点更新的请求时,使用 SetDataRequest 类来封装请求体:
    // SetDataRequest 类实现了 Record 接口来进行序列化操作
    public class SetDataRequest implements Record {
    	// 节点全路径
        private String path;
        // 节点更新的数据
        private byte[] data;
        // 节点更新后的版本,也就是在当前版本上加 1
        private int version;
    }
    

介绍了 Zookeeper 的请求协议之后,接下来我们继续学习 Zookeeper 的响应协议。

2.2 响应协议

响应协议会在接收到 Zookeeper 客户端的请求后,对请求协议进行解析并作出响应。和 Zookeeper 的请求协议相对应的,Zookeeper 的响应协议也是由响应头和响应体组成,响应体也需要根据不同的请求类型来封装响应体。在接收到 Zookeeper 客户端的请求后,由 ReplyHeader 类来解析请求头并对响应头进行封装:

// ReplyHeader 类实现了 Record 接口来进行序列化操作
public class ReplyHeader implements Record {
    // 客户端序号,记录客户端请求发起的顺序
    private int xid;
    // 事务id
    private long zxid;
    // 错误状态码
    private int err;
}
  • 会话创建响应
    当 Zookeeper 服务端接收到 Zookeeper 客户端的会话创建请求时,使用 ConnectResponse 类来封装响应体:
    // ConnectResponse 类实现了 Record 接口来进行序列化操作
    public class ConnectResponse implements Record {
        // 请求协议的版本信息
        private int protocolVersion;
        // 会话超时时间
        private int timeOut;
        // 会话 id
        private long sessionId;
        // 密码
        private byte[] passwd;
    }
    
  • 节点查询响应
    当 Zookeeper 服务端接收到 Zookeeper 客户端的节点查询请求时,使用 GetDataResponse 类来封装响应体:
    // GetDataResponse 类实现了 Record 接口来进行序列化操作
    public class GetDataResponse implements Record {
        // 节点的数据
        private byte[] data;
        // 节点的状态
        private org.apache.zookeeper.data.Stat stat;
    }
    
  • 节点更新响应
    当 Zookeeper 服务端接收到 Zookeeper 客户端的节点更新请求时,使用 SetDataResponse 类来封装响应体:
    // SetDataResponse 类实现了 Record 接口来进行序列化操作
    public class SetDataResponse implements Record {
        // 节点的状态
        private org.apache.zookeeper.data.Stat stat;
    }
    

介绍完 Zookeeper 的通信协议后,接下来我们要学习的是 Zookeeper 的会话,包括会话的结构,会话的状态等。

3. Zookeeper 的会话

Zookeeper 是一个 C/S 架构的服务,也就是 Client — Server 的形式。在我们使用 Zookeeper 时,都是使用 Zookeeper 的客户端向服务端发送请求,然后由服务端做出响应返回到客户端。在这个过程中,Zookeeper 的客户端需要与 Zookeeper 服务端建立连接,建立一个连接就是新建一个会话,那么会话的状态也就是 Zookeeper 客户端与 Zookeeper 服务端的连接状态。
接下来我们从会话的结构开始进行讲解:

3.1 Session 的结构

会话 Session 的结构包括会话ID、会话超时时间、会话关闭状态 3 个属性:
Session 的结构

  • SessionID: 会话的唯一标识,由 Zookeeper 自动分配。
  • TimeOut: 会话从新建到被关闭的时长,这个时间由 Zookeeper 服务端来管理。
  • isClosing: 会话关闭的状态,如果会话已经被关闭,该会话就不会再被使用了。

3.2 Session 的状态

在 Zookeeper 的运行过程中,会话 Session 会经历各种状态的变化,从 Zookeeper 客户端与 Zookeeper 服务端开始建立连接到连接被关闭,会话的状态会经历以下几种:

  • CONNECTING:正在连接状态,Zookeeper 客户端与 Zookeeper 服务端建立连接时的状态;
  • CONNECTIED:已连接状态,Zookeeper 客户端与 Zookeeper 服务端完成连接的状态;
  • RECONNECTING:正在重新连接状态,当 Zookeeper 客户端与 Zookeeper 服务端断开连接,Session 重连策略发起重新连接时的状态;
  • RECONNECTED:已经重新连接状态,在 RECONNECTING 的基础上,完成了 Zookeeper 客户端与 Zookeeper 服务端的重新连接;
  • CLOSE:连接关闭状态,Zookeeper 客户端与 Zookeeper 服务端断开连接的状态。

4. 总结

在本节内容中,我们学习了 Zookeeper 的通信协议的实现方式,以及 Zookeeper 会话 Session 的结构和运行中的状态变化。以下是本节内容的总结:

  1. Zookeeper 的通信协议。
  2. Zookeeper 的会话。