zookeeper-通信协议

来源:互联网 发布:天猫淘宝双十一晚会 编辑:程序博客网 时间:2024/06/01 21:25

1.    Zookeeper技术内幕

1.1. 通信协议

        基于TCP/IP协议,zookeeper实现了自己的通信协议来完成客户端与服务端、服务端与服务端之间的网络通信。Zookeeper通信协议整体上的设计非常简单,对于请求,主要包含请求头和请求体,而对于响应,则主要包含响应头和响应体。


1.1.1.  协议解析:请求部分

        GetDataRequest“获取节点数据”请求的完整协议定义

 

请求长度

请求头

请求体

字节偏移量

0 - 3

4 - 11

12 - n

4 - 7

8 - 11

12 - 15

16-(n-1)

n

协议内容

len

xid

type

len(数据体长度)

path

watch

 

请求头:RequestHeader

[java] view plain copy 在CODE上查看代码片派生到我的代码片
  1. public class RequestHeader implements Record {  
  2.   private int xid;  
  3.   private int type;  
  4. }  

        xid用于记录请求发起的先后序号,用于确定单个客户端请求的响应顺序。Type代表请求的操作类型,常见的包括创建节点(OpCode.create)、删除节点(OpCode.delete)和获取节点数据(OpCode.getData)等。

请求体:Request

        协议的请求体部分是指请求的主体内容部分,包含了请求的所有操作内容。不同的请求类型,其请求体部分的结构是不同的,下面以获取节点数据的请求体为例来对请求体进行分析。

[java] view plain copy 在CODE上查看代码片派生到我的代码片
  1. public class GetDataRequest implements Record {  
  2.   private String path;  
  3.   private boolean watch;  
  4. }  

        该请求体包含了数据节点的节点路径path和是否注册Watcher的标识watch。

        序列化请求协议到缓存中:

[java] view plain copy 在CODE上查看代码片派生到我的代码片
  1. static class Packet {  
  2.     RequestHeader requestHeader;  
  3.     ReplyHeader replyHeader;  
  4.     Record request;  
  5.     Record response;  
  6.     ByteBuffer bb;  
  7.     ......  
  8.     public void createBB() {  
  9.         try {  
  10.             ByteArrayOutputStream baos = new ByteArrayOutputStream();  
  11.             BinaryOutputArchive boa = BinaryOutputArchive.getArchive(baos);  
  12.             boa.writeInt(-1"len"); // We'll fill this in later  
  13.             if (requestHeader != null) {  
  14.                 requestHeader.serialize(boa, "header");  
  15.             }  
  16.             if (request != null) {  
  17.                 request.serialize(boa, "request");  
  18.             }  
  19.             baos.close();  
  20.             this.bb = ByteBuffer.wrap(baos.toByteArray());  
  21.             this.bb.putInt(this.bb.capacity() - 4);  
  22.             this.bb.rewind();  
  23.         } catch (IOException e) {  
  24.             LOG.warn("Ignoring unexpected exception", e);  
  25.         }  
  26.     }  
  27. }  

1.1.2.  协议解析:响应部分

        以GetDataResponse“获取节点数据”响应为例,解析完整协议定义

 

请求长度

响应头

响应体

字节偏移量

0 - 3

4 - 19

20 - n

4 - 7

8 - 15

16 - 19

20 - 23

len

68

协议内容

len

xid

zxid

err

len

data

Stat

 

8

8

8

8

4

4

4

8

4

4

8

czxid

mzxid

ctime

mtime

version

cversion

aversion

ephemeral Owner

dataLength

numChildren

pzxid

 

响应头:ReplyHeader

[java] view plain copy 在CODE上查看代码片派生到我的代码片
  1. public class ReplyHeader implements Record {  
  2.   private int xid;  
  3.   private long zxid;  
  4.   private int err;  
  5. }  

        Xid和上文中提到的请求头中的xid是一致的,响应中只是将请求的xid原值返回。Zxid代表zookeeper服务器上当前最新的事物Id。Err则是一个错误码,当请求处理过程中出现异常情况时,会在这个错误码中表示出来,常见的包括处理成功(Code.OK)、节点不存在(Code.NONODE)和没有权限(Code.NOAUTH)等。

响应体:Request

        协议的响应体部分是指响应的主体内容部分,包含了相应的所有返回数据。不通的响应类型,其相应体部分的结构是不同的,下面以获取节点数据的响应体为例来对响应体进行分析。

[java] view plain copy 在CODE上查看代码片派生到我的代码片
  1. public class GetDataResponse implements Record {  
  2.   private byte[] data;  
  3.   private org.apache.zookeeper.data.Stat stat;  
  4. }  
  5. public class Stat implements Record {  
  6.   private long czxid;  
  7.   private long mzxid;  
  8.   private long ctime;  
  9.   private long mtime;  
  10.   private int version;  
  11.   private int cversion;  
  12.   private int aversion;  
  13.   private long ephemeralOwner;  
  14.   private int dataLength;  
  15.   private int numChildren;  
  16.   private long pzxid;  
  17. }  

        反序列化响应协议到缓存中:

[java] view plain copy 在CODE上查看代码片派生到我的代码片
  1. class SendThread extends ZooKeeperThread {  
  2.     void readResponse(ByteBuffer incomingBuffer) throws IOException {  
  3.         ByteBufferInputStream bbis = new ByteBufferInputStream(incomingBuffer);  
  4.         BinaryInputArchive bbia = BinaryInputArchive.getArchive(bbis);  
  5.         ReplyHeader replyHdr = new ReplyHeader();  
  6.         replyHdr.deserialize(bbia, "header");  
  7. ......  
  8.         Packet packet;  
  9.         synchronized (pendingQueue) {  
  10.             packet = pendingQueue.remove();  
  11.         }  
  12.         try {  
  13.             if (packet.requestHeader.getXid() != replyHdr.getXid()) {  
  14.                 packet.replyHeader.setErr(  
  15.                         KeeperException.Code.CONNECTIONLOSS.intValue());  
  16.                 throw new IOException("Xid out of order. Got Xid ");  
  17.             }  
  18.             packet.replyHeader.setXid(replyHdr.getXid());  
  19.             packet.replyHeader.setErr(replyHdr.getErr());  
  20.             packet.replyHeader.setZxid(replyHdr.getZxid());  
  21.             if (replyHdr.getZxid() > 0) {  
  22.                 lastZxid = replyHdr.getZxid();  
  23.             }  
  24.             if (packet.response != null && replyHdr.getErr() == 0) {  
  25.                 packet.response.deserialize(bbia, "response");  
  26.             }  
  27.         } finally {  
  28.             finishPacket(packet);  
  29.         }  
  30.     }  
  31. }  
0 0