读完这篇文章你将会收获到

  • 在 Zookeeper 源码项目中新建模块,使用 Jute 进行序列化和反序列化
  • 修改 Jute 中的 buffer size 来序列化/反序列化大对象

序言

前面的文章 我们得知、ZK 的客户端和服务端会通过网络进行一系列的数据交互(节点中的数据内容、ACL 信息),而我们知道从一个内存对象到网络传输,那么就会涉及到序列化和反序列化操作。ZK 使用到是一个叫 Jute 的序列化组件(对不起,我真的没听过,尴尬了)

Jute 介绍

Jute 是 ZK 中序列化的组件,前身是 Hadoop Record IO 中的序列化组件。

ZK 从第一个正式对外的版本开始,就一直使用 Jute 组件来进行网络数据传输和本地磁盘数据存储的序列化和反序列化工作。并不是 Jute 优秀到不被其他序列化框架所超越、而是替换这种基层组件、老版本的兼容性问题很难处理,并且 Jute 的序列化能力并不是 ZK 性能上的瓶颈,so 现在还是这个序列化组件。

Jute 使用

Talk is cheap. Show me the code

在 zk 源代码中新建一个模块

加入依赖

dependencies>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.12</version>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.apache.zookeeper</groupId>
<artifactId>zookeeper-jute</artifactId>
<version>3.7.0-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>org.apache.zookeeper</groupId>
<artifactId>zookeeper</artifactId>
<version>3.7.0-SNAPSHOT</version>
</dependency>
</dependencies>

创建 POJO , 并实现 Record 接口

@Data
@Accessors(chain = true)
@AllArgsConstructor
@NoArgsConstructor
public class Person implements Record {
private String name;
private int age;
@Override
public void serialize(OutputArchive archive, String tag) throws IOException {
archive.startRecord(this, tag);
archive.writeInt(age, "age");
archive.writeString(name, "name");
archive.endRecord(this, tag);
} @Override
public void deserialize(InputArchive archive, String tag) throws IOException {
archive.startRecord(tag);
age = archive.readInt("age");
name = archive.readString("name");
archive.endRecord(tag);
}
}

创建单元测试

    @Test
public void serializeTest() throws IOException {
// 开始序列化
ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
BinaryOutputArchive binaryOutputArchive = BinaryOutputArchive.getArchive(byteArrayOutputStream);
new Person("coderLi", 100).serialize(binaryOutputArchive, "person");
// 通常是 TCP 网络传输对象
ByteBuffer byteBuffer = ByteBuffer.wrap(byteArrayOutputStream.toByteArray());
// 反序列化
ByteBufferInputStream byteBufferInputStream = new ByteBufferInputStream(byteBuffer);
BinaryInputArchive binaryInputArchive = BinaryInputArchive.getArchive(byteBufferInputStream);
Person person = new Person();
person.deserialize(binaryInputArchive, "person");
System.out.println(person.toString()); byteArrayOutputStream.close();
byteBufferInputStream.close(); }

运行

Person(name=coderLi, age=100)

可能出现的问题

java.io.IOException: Unreasonable length = 1668244581
at org.apache.jute.BinaryInputArchive.checkLength(BinaryInputArchive.java:166)
at org.apache.jute.BinaryInputArchive.readString(BinaryInputArchive.java:116)
at com.coder.li.data.Person.deserialize(Person.java:36)

根据报错信息找到 BinaryInputArchive

public class BinaryInputArchive implements InputArchive {

    public static final String UNREASONBLE_LENGTH = "Unreasonable length = ";

    // CHECKSTYLE.OFF: ConstantName - for backward compatibility
public static final int maxBuffer = Integer.getInteger("jute.maxbuffer", 0xfffff);
// CHECKSTYLE.ON:
private static final int extraMaxBuffer; static {
final Integer configuredExtraMaxBuffer =
Integer.getInteger("zookeeper.jute.maxbuffer.extrasize", maxBuffer);
if (configuredExtraMaxBuffer < 1024) {
// Earlier hard coded value was 1024, So the value should not be less than that value
extraMaxBuffer = 1024;
} else {
extraMaxBuffer = configuredExtraMaxBuffer;
}
}
....
...
private void checkLength(int len) throws IOException {
if (len < 0 || len > maxBufferSize + extraMaxBufferSize) {
throw new IOException(UNREASONBLE_LENGTH + len);
}
}

我们系统中并没有配置这两个参数,所以这俩个 buffer size 的和应该是 1024

我们在启动参数中配置

-Djute.maxbuffer=0 -Dzookeeper.jute.maxbuffer.extrasize=1668244581

只要 maxBufferSize + extraMaxBufferSize 和大于等于 1668244581 即可(注意不要设置过大、导致相加结果溢出变为负数)

后来排查问题发现原来导致这个问题的出现是在反序列化的时候、自己写代码出错导致,但是借此来认识到一个坑还是不错的

或者你在实体类中有一个非常大的对象需要被序列化和反序列化、也会抛出这个异常

private String name;
private int age;
private byte[] bigData; public Person() {
} public Person(String name, int age) {
this.age = age;
this.name = name;
bigData = new byte[2048 * 2048];
}

Jute 使用流程

  • 实体类实现接口 Recordserializedeserialize
  • 构造 BinaryOutputArchive
  • 序列化
  • 反序列化

相关组件

Record

public interface Record {
void serialize(OutputArchive archive, String tag) throws IOException;
void deserialize(InputArchive archive, String tag) throws IOException;
}

Zookeeper Watcher 流程分析 文章中我们分析的 WatcherEvent 这个实体类就是实现了 Record 接口

InputArchive/OutputArchive

这两个接口分别是 Jute 底层序列化器和反序列化器接口定义,实现类主要有 BinaryOutputArchiveBinaryInputArchive

public interface InputArchive {

byte readByte(String tag) throws IOException;

boolean readBool(String tag) throws IOException;

int readInt(String tag) throws IOException;

long readLong(String tag) throws IOException;

float readFloat(String tag) throws IOException;

double readDouble(String tag) throws IOException;

String readString(String tag) throws IOException;

byte[] readBuffer(String tag) throws IOException;

void readRecord(Record r, String tag) throws IOException;
..........
}

都是定义了一些非常基本的方法

其实都是依赖于 Java 的 InputStreamOutputStream 进行操作的

相关文章

编译运行Zookeeper源码

ZooKeeper 数据模型:节点的特性

Zookeeper-Access Control List

Zookeeper Watcher 流程分析

Zookeeper 序列化的更多相关文章

  1. Zookeeper 序列化机制

    一.到底在哪些地方需要使用序列化技术呢? 二.Zookeeper(分布式协调服务组件+存储系统) Java 序列化机制 Hadoop序列化机制 Zookeeper序列化机制 一.到底在哪些地方需要使用 ...

  2. 【分布式】Zookeeper序列化及通信协议

    一.前言 前面介绍了Zookeeper的系统模型,下面进一步学习Zookeeper的底层序列化机制,Zookeeper的客户端与服务端之间会进行一系列的网络通信来实现数据传输,Zookeeper使用J ...

  3. Zookeeper系列六:服务器角色、序列化与通信协议、数据存储、zookeeper总结

    一.服务器角色 1. Leader 1)事务请求的唯一调度者和处理者.保证事务处理的顺序性 事务请求:导致数据一致性的请求(数据发生改变).如删除一个节点.创建一个节点.设置节点数据,设置节点权限就是 ...

  4. 【目录】Zookeeper目录

    Zookeeper的目录整理如下 1. [分布式]分布式架构 2. [分布式]一致性协议 3. [分布式]Chubby与Paxos 4. [分布式]Zookeeper与Paxos 5. [分布式]Zo ...

  5. 网络与RPC

    网络与RPC 标签 : Java基础 Java为网络编程提供的java.net包封装了底层通信细节, 包含了大量的基础组件以及TCP/UDP协议的编程接口, 使得开发者可以专注于解决问题, 而不用关注 ...

  6. 使用Dubbox构架分布式服务

    第一部分:Dubbo的背景分析及工作原理 1. Dubbo是什么?Dubbo是一个来自阿里巴巴的开源分布式服务框架,致力于提供高性能和透明化的RPC远程服务调用方案,以及SOA服务治理方案. 简单的说 ...

  7. Java开发技术

    1.基础技术 数据结构与算法   逻辑结构:数据对象中的数据元素之间的逻辑关系 1.集合结构:集合结构中的数据元素除了同属一个集合外,没有其他关系. 2.线性结构:线性结构中的数据元素之间是一对一的关 ...

  8. zookeeper原理解析-序列化

    1)底层通信数据封装与操作           BinaryInputArchive& BinaryOutputArchive底层通信数据封装与操作     BinaryInputArchiv ...

  9. 【Zookeeper】源码之序列化

    一.前言 在完成了前面的理论学习后,现在可以从源码角度来解析Zookeeper的细节,首先笔者想从序列化入手,因为在网络通信.数据存储中都用到了序列化,下面开始分析. 二.序列化 序列化主要在zook ...

随机推荐

  1. Java实现 蓝桥杯 基础练习 杨辉三角形

    基础练习 杨辉三角形 时间限制:1.0s 内存限制:256.0MB 提交此题 锦囊1 锦囊2 问题描述 杨辉三角形又称Pascal三角形,它的第i+1行是(a+b)i的展开式的系数. 它的一个重要性质 ...

  2. Java实现 LeetCode 493 翻转对

    493. 翻转对 给定一个数组 nums ,如果 i < j 且 nums[i] > 2*nums[j] 我们就将 (i, j) 称作一个重要翻转对. 你需要返回给定数组中的重要翻转对的数 ...

  3. Java实现 蓝桥杯VIP 算法提高 文化之旅

    算法提高 文化之旅 时间限制:1.0s 内存限制:128.0MB 问题描述 有一位使者要游历各国,他每到一个国家,都能学到一种文化,但他不愿意学习任何一种文化超过一次(即如果他学习了某种文化,则他就不 ...

  4. Java实现 LeetCode 108 将有序数组转换为二叉搜索树

    108. 将有序数组转换为二叉搜索树 将一个按照升序排列的有序数组,转换为一棵高度平衡二叉搜索树. 本题中,一个高度平衡二叉树是指一个二叉树每个节点 的左右两个子树的高度差的绝对值不超过 1. 示例: ...

  5. Linux文件处理命令 ls 详解

    Linux系统的应用场景最多的就是用作服务器的系统了,简洁,安全,高效,一般我们服务器端不会安装Linux的图形化界面,虽然现在一些Linux发行版的图形界面也很漂亮,但是,服务器最主要的是高效.所以 ...

  6. python3 主机实时监控系统

    主机实时监控系统(可在局域网访问) 一.思路: 前端: 1.管理员登录(编写一个管理员登录界面) 技术:html+css 2.资源数据显示(用于显示主机资源数据情况) 插件:echarts+jquer ...

  7. maven配置阿里云仓库进行下载

    maven阿里云仓库下载 为了解决maven在下载jar包的时候,速度比较慢的问题,可以配置阿里云仓库配置方式的进行下载,首先找到您安装的maven路径. 在conf文件夹下面有个settings.x ...

  8. 嵌入式Linux学习笔记(六) 上位机QT界面实现和串口通讯实现

    目录 (1).参考资料 (2).QT界面布局实现 (3).数据和操作逻辑 在上一章我们实现了下位机的协议制定,并通过串口通讯工具完成了对设备内外设(LED)的状态修改,下面就要进行上位机软件的实现了( ...

  9. 曹工说JDK源码(2)--ConcurrentHashMap的多线程扩容,说白了,就是分段取任务

    前言 先预先说明,我这边jdk的代码版本为1.8.0_11,同时,因为我直接在本地jdk源码上进行了部分修改.调试,所以,导致大家看到的我这边贴的代码,和大家的不太一样. 不过,我对源码进行修改.重构 ...

  10. javafx分别设置四个边框

    package border; import javafx.application.Application; import javafx.geometry.Insets; import javafx. ...