Zookeeper 源码(二)序列化组件 Jute

一、序列化组件 Jute

对于一个网络通信,首先需要解决的就是对数据的序列化和反序列化处理,在 ZooKeeper 中,使用了Jute 这一序列化组件来进行数据的序列化和反序列化操作。同时,为了实现一个高效的网络通信程序,良好的通信协议设计也是至关重要的。Zookeeper 团队曾想过将 Jute 替换成 Apache 的 Avro 或是 Google 的 protobuf 但是考虑到新老版本序列化组件的兼容性和当前 Jute 的序列化能力并不是 ZooKeeper 的性能瓶颈。

import org.apache.jute.*;
import org.apache.zookeeper.server.ByteBufferInputStream; import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.nio.ByteBuffer; public class JuteHeader implements Record { private long sessionId;
private String type; public JuteHeader() {
} public JuteHeader(long sessionId, String type) {
this.sessionId = sessionId;
this.type = type;
} @Override
public void serialize(OutputArchive outputArchive, String tag) throws IOException {
outputArchive.startRecord(this, tag);
outputArchive.writeLong(sessionId, "sessionId");
outputArchive.writeString(type, "type");
outputArchive.endRecord(this, tag);
} @Override
public void deserialize(InputArchive inputArchive, String tag) throws IOException {
inputArchive.startRecord(tag);
sessionId = inputArchive.readLong("sessionId");
type = inputArchive.readString("type");
inputArchive.endRecord(tag);
} public static void main(String[] args) throws IOException { final String tag = "header";
// 序列化
ByteArrayOutputStream baos = new ByteArrayOutputStream();
BinaryOutputArchive boa = BinaryOutputArchive.getArchive(baos);
new JuteHeader(100001L, "xxx").serialize(boa, tag); // 包装成 ByteBuffer 用于网络传输
ByteBuffer bb = ByteBuffer.wrap(baos.toByteArray()); // 反序列化
ByteBufferInputStream bbis = new ByteBufferInputStream(bb);
BinaryInputArchive bbia = BinaryInputArchive.getArchive(bbis);
JuteHeader header = new JuteHeader();
header.deserialize(bbia, tag); baos.close();
bbis.close();
} }

二、Zookeeper 通信协议

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

协议的请求头组成如下:

Packet 类中的 createBB() 将 packet 对象序列化:

public void createBB() {
try {
ByteArrayOutputStream baos = new ByteArrayOutputStream();
BinaryOutputArchive boa = BinaryOutputArchive.getArchive(baos);
boa.writeInt(-1, "len"); // We'll fill this in later
if (requestHeader != null) {
requestHeader.serialize(boa, "header");
}
if (request instanceof ConnectRequest) {
request.serialize(boa, "connect");
// append "am-I-allowed-to-be-readonly" flag
boa.writeBool(readOnly, "readOnly");
} else if (request != null) {
request.serialize(boa, "request");
}
baos.close();
this.bb = ByteBuffer.wrap(baos.toByteArray());
this.bb.putInt(this.bb.capacity() - 4);
this.bb.rewind();
} catch (IOException e) {
LOG.warn("Ignoring unexpected exception", e);
}
}

请求头:

public class RequestHeader implements Record {
private int xid;
private int type; public void serialize(OutputArchive a_, String tag) throws java.io.IOException {
a_.startRecord(this,tag);
a_.writeInt(xid,"xid");
a_.writeInt(type,"type");
a_.endRecord(this,tag);
} public void deserialize(InputArchive a_, String tag) throws java.io.IOException {
a_.startRecord(tag);
xid=a_.readInt("xid");
type=a_.readInt("type");
a_.endRecord(tag);
}
}

请求体有多种,如 ConnectRequest、CreateRequest ...:

public class ConnectRequest implements Record {
private int protocolVersion;
private long lastZxidSeen;
private int timeOut;
private long sessionId;
private byte[] passwd; public void serialize(OutputArchive a_, String tag) throws java.io.IOException {
a_.startRecord(this,tag);
a_.writeInt(protocolVersion,"protocolVersion");
a_.writeLong(lastZxidSeen,"lastZxidSeen");
a_.writeInt(timeOut,"timeOut");
a_.writeLong(sessionId,"sessionId");
a_.writeBuffer(passwd,"passwd");
a_.endRecord(this,tag);
}
public void deserialize(InputArchive a_, String tag) throws java.io.IOException {
a_.startRecord(tag);
protocolVersion=a_.readInt("protocolVersion");
lastZxidSeen=a_.readLong("lastZxidSeen");
timeOut=a_.readInt("timeOut");
sessionId=a_.readLong("sessionId");
passwd=a_.readBuffer("passwd");
a_.endRecord(tag);
}
}

每天用心记录一点点。内容也许不重要,但习惯很重要!

Zookeeper 源码(二)序列化组件 Jute的更多相关文章

  1. zookeeper源码 — 二、集群启动—leader选举

    上一篇介绍了zookeeper的单机启动,集群模式下启动和单机启动有相似的地方,但是也有各自的特点.集群模式的配置方式和单机模式也是不一样的,这一篇主要包含以下内容: 概念介绍:角色,服务器状态 服务 ...

  2. ZooKeeper源码阅读——client(二)

    原创技术文章,转载请注明:转自http://newliferen.github.io/ 如何连接ZooKeeper集群   要想了解ZooKeeper客户端实现原理,首先需要关注一下客户端的使用方式, ...

  3. Zookeeper源码(启动+选举)

    简介 关于Zookeeper,目前普遍的应用场景基本作为服务注册中心,用于服务发现.但这只是Zookeeper的一个的功能,根据Apache的官方概述:"The Apache ZooKeep ...

  4. zookeeper源码分析之三客户端发送请求流程

    znode 可以被监控,包括这个目录节点中存储的数据的修改,子节点目录的变化等,一旦变化可以通知设置监控的客户端,这个功能是zookeeper对于应用最重要的特性,通过这个特性可以实现的功能包括配置的 ...

  5. Zookeeper 源码(三)Zookeeper 客户端源码

    Zookeeper 源码(三)Zookeeper 客户端源码 Zookeeper 客户端主要有以下几个重要的组件.客户端会话创建可以分为三个阶段:一是初始化阶段.二是会话创建阶段.三是响应处理阶段. ...

  6. zookeeper源码分析之四服务端(单机)处理请求流程

    上文: zookeeper源码分析之一服务端启动过程 中,我们介绍了zookeeper服务器的启动过程,其中单机是ZookeeperServer启动,集群使用QuorumPeer启动,那么这次我们分析 ...

  7. Unity UGUI图文混排源码(二)

    Unity UGUI图文混排源码(一):http://blog.csdn.net/qq992817263/article/details/51112304 Unity UGUI图文混排源码(二):ht ...

  8. Django-restframework 源码之认证组件源码分析

    Django-restframework 源码之认证组件源码分析 一 前言 之前在 Django-restframework 的流程分析博客中,把最重要的关于认证.权限和频率的方法找到了.该方法是 A ...

  9. Tomcat8源码笔记(七)组件启动Server Service Engine Host启动

    一.Tomcat启动的入口 Tomcat初始化简单流程前面博客介绍了一遍,组件除了StandardHost都有博客,欢迎大家指文中错误.Tomcat启动类是Bootstrap,而启动容器启动入口位于 ...

随机推荐

  1. jenkins配置email

    # 系统设置 # Jenkins Location # 邮件通知 # 高级 # Failed to send out e-mail 勾选“使用SSL协议” SMTP端口改为465 密码使用授权码,不能 ...

  2. 如何检测MySQL中建立的索引是否生效

    使用方法,在select语句前加上explain就可以了: EXPLAIN SELECT surname,first_name form a,b WHERE a.id=b.id EXPLAIN列的解释 ...

  3. python api接口认证脚本

    import requests import sys def acces_api_with_cookie(url_login, USERNAME, PASSWORD, url_access):     ...

  4. Yocto使用小技巧

    1. 借助Yocto编译模块 SRC := mytest obj-m := $(SRC).o KDIR := /media/Yocto/build/tmp/work/poky-linux/linux- ...

  5. mysql 源代码目录及安装目录介绍

    1.源代码目录介绍: 1.BUILD    BUILD目录是编译.安装脚本目录,绝大部分以compile-开头,其中的SETUP.sh脚本为C和C++编译器设置了优化选项.2.client    cl ...

  6. linux中内核延时函数 (转)

    第一类延时函数原型是:(忙等) void ndelay(unsigned long nsecs); void udelay(unsigned long usecs); void mdelay(unsi ...

  7. SQL相关简单游标

    BEGIN TRY Create Table #Temp_Table_Record_Stat ( .... ) DECLARE table_Cursor CURSOR FOR SELECT objec ...

  8. bzoj 3159: 决战

    Description 树上链翻转,链加,查询链上的和/max/min 树链剖分套treap,修改查询可以用类似线段树的写法,翻转可以利用分裂合并和翻转标记实现,时间复杂度O(nlog2n) 实测除了 ...

  9. linux命令killall 、kill 、pkill 命令详解

    转自:http://www.cnblogs.com/rsky/p/4886043.html killall 命令 Linux系统中的killall命令用于杀死指定名字的进程(kill processe ...

  10. window.onload()和$(document).ready()区别

    执行时间:window.onload:必须等待网页中所有的内容加载完毕后(包括图片)才能执行;$(document).ready();网页中所有DOM结构绘制完毕后就执行,可能DOM元素关联的东西并没 ...