zookeeper的序列化解决方案
zookeeper采用了jute框架进行数据的序列化传输,选择jute并不是因为这个框架的序列化解决方式性能很好,相反,像apache Avro,thrift等框架的性能要优于它,选择他是因为新老版本的兼容问题
使用jute实现java序列化也很简单,只需要实现Record接口,重写他的serialize和deserialize方法就可以了, jute框架支持非常多的数据类型的转化,有整型,双精度数,长整型,字符串等等
一例胜千言 :
class TestJute implements Record throws ....{
private long ids;
private Strinng name;
.....
public void serialize(OutputArchive a, String tag){
a.startRecord(this.tag);
a.writeLong(ids, "ids");
a.writeString(name, "name");
......
a.endRecord(this.tag);
}
public void deserialize(INputArchive a, String tag){
.... 同理
}
}
可以看的出Out / INputArchive这个类还是蛮关键的两个类,我们序列化的方法写在这两个类中,具体调用时,我们根据目的数据类型可以有不同的实现 : xml、binary、Csv
我们接着深入一些,首先从binary的序列化方法开始,了解一下jute的底层源码,我们先来拿上面的writeString方法开使分析
void writeString(String s, String tag){
if (s == null){
// 如果字符串为空,则将其当作值为-1的字符串进行序列化
writeInt(-1, "len");
return;
}
// 如果不为空,调用下面的这个方法 看样子,这个方法便是BinaryOutPutArchive的核心方法了
ByteBuffer bb = stringtoByteBuffer(s);
}
stringToByteBuffer
private ByteBuffer bb = ByteBuffer.allocate(1024);
ByteBuffer stringToByteBuffer(CharSequence c){
if( c < 0x80){
bb.put((byte)c) // 对于字母或者是数字,直接使用一个byte
}else if(c < 0x800){
bb.put((byte)(0xc0 | c >> 6)));
bb.put((byte)(0x80 | (c & 0x3f)));
}
}
Binary二进制序列化方式的底层实现相对简单,只是采用将对应的java对象转化为二进制字节流的方式,Binary方式序列化的优点有很多,无论是windows操作系统和mac操作系统,其底层都是对二进制文件的编译与解析也是一样的,所有操作系统都能对二进制文件进行操作,缺点是,在不同的操作系统下,会产生大端小端的问题。
xml、Csv原理和Binary大同小异, 对于xml(extensible markup language)来说,其对于Binary的优点在于其在各大平台上的序列化和反序列化的标准都是一样的,不存在一个像Binary那样的大端或者小端问题。当然,我们的zookeeper采用的默认的序列化方式就是Binary二进制方式,这是因为二进制具有较好的性能,虽然大多数的平台对于二进制的实现方式都不尽相同。
zookeeper的网络协议
身为一个分布式的协调框架,zookeeper基于tcp|ip上实现了属于自己的网络通信协议
zookeeper的请求响应结构如下:
一个请求 = 请求头 + 请求体
一个响应 = 响应头 + 响应体
请求头和响应头的格式是固定的, 而请求体和响应体的格式会随着数据类型的变化而改变格式
请求和响应的结构都是通过java类来进行实现的,配合上我们的序列化传输方式,便可以愉快的进行传输
class RequestHeader implements Record{
// 实现record接口,以进行序列化
private int xid; // 记录请求的发起顺序
private int type; // 记录请求的类型
}
请求体的话根据请求类型的不同,结构也分为很多种, 下面拿会话创建来举例子
class ConnectRequest implements Record {
private int protocolId; // 协议的版本的信息
private int timout; // 超时时间
private long lastZxidSeen; // 最后一个接收到服务器的zxid的序号
private long sessionId; // 会话的标示符
private byte[] passwd;// 会话的密码
}
响应头和请求头的结构类似,多了一个错误字段
public class replyHeader implements Recorder {
private int xid;
private int zxid;
private int err;
}
响应体拿会话创建来举例子
public class ConnectResponse implements Recorder {
private int protocolVersion;
private int timeout;
private long sessionId;
private byte[] passwd;
}
以上就是zookeeper封装的的报文结构,是不是有了一个大致的概念了呢