Zookeeper 的通信及会话
1. 前言
在前面的章节中,我们学习了 Zookeeper 的 Java 客户端 ZkClient 和 Curator 的基本使用,那这些客户端是如何与 Zookeeper 服务端建立通信的呢?我们就带着这个问题开启本节的内容。
2. Zookeeper 的通信协议
首先我们从 Zookeeper 的通信协议开始说起。我们都知道最常用的网络通信协议 TCP/IP 协议,而 Zookeeper 就是基于 TCP/IP 协议实现了自己的通信方式。
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 个属性:
- 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 的结构和运行中的状态变化。以下是本节内容的总结:
- Zookeeper 的通信协议。
- Zookeeper 的会话。