Java中二进制序列化和绝对序列化的快速框架,并且具有最少的序列化字节
#编程 #java #protobuf #kryo

A… 。介绍

  • zfoo protocol 目前,它是Java中二进制序列化和绝对序列化的最快框架,并且最少 序列化字节
  • 该协议当前是本地支持的 C ++ Java JavaCript C#GO LUA GDSCRIPT ï¼很容易进行跨平台
  • 该协议可以自定义专用协议格式以使您的协议更加安全,并支持添加字段 并与以前和后续协议兼容
  • 与Protobuf兼容,它支持Protobuf协议文件的生成,并从 因此是
  • 的概念
  • 已经有很多可以以生成pojos的方式来完成的喷气式插件,您可以搜索 IDEA插件中的原始

A…。快速使用

  • 环境要求 JDK 11+

  • 协议是一个独立的项目,不依赖其他项目,可以直接打开,本地安装到
    它自己的本地Maven存储库可以单独使用

// The zfoo protocol is registered and can only be initialized once
ProtocolManager.initProtocol(Set.of(ComplexObject.class, ObjectA.class, ObjectB.class));

// serialization
ProtocolManager.write(byteBuf, complexObject);

// deserialization
var packet = ProtocolManager.read(buffer);

•。性能测试

  • 单线程环境,比Protobuf快50%,没有任何JVM参数的Kryo快100% tuning,参见性能测试
  • 线程安全性,ZFOO和Protobuf的性能不会受到任何影响,Kryo会失去一些性能
    由于线程不安全感,参见性能测试

  • 测试环境

system:win10
cpu: i9900k
内存:64g
  • 带有横坐标的单线读取测试,作为序列化和必不可少的对象数量,并在毫秒中花费的时间 在纵梁上

Image description

Image description

Image description

£。为什么要快

  • 使用Javassist字节码来增强顺序的序列化和避免函数的动态生成 执行和顺序函数可以轻松编译以实现极端性能
  • 与Netty的高性能字节BUF
  • 本地集成
  • 有了原始类型的收藏,没有拳击和拆箱,避免了无效的GC,并且性能很快 足够
  • 固有的线程安全和无锁; Kryo强迫每个线程都有自己的Kryo实例,这很重 设计,尤其是在许多线程的情况下
  • 没有反思,没有不安全的操作;在Kryo中使用Objenesis 在Java 11
  • 运行
  • 将方法堆栈的呼叫深度变平,并且嵌套数据结构没有性能惩罚, 作为列表>>;比较Kryo和Protobuf数据结构嵌套会导致性能惩罚
  • 没有脆弱性注射的风险,只有在初始化期间进行字节码增强,而没有 字节码操作将在后期进行
The data compression volume is small, and the compression volume is smaller than that of Kryo and Protobuf; Smaller than kryo because kryo needs to write the registration number of each object
Intelligent syntax, incorrect protocol definitions will fail to start the program and give an error warning
Improve development efficiency, fully support POJO development, very easy to use

- 。为什么小

  • 轻量级实现,核心序列化和大约一千行的挑选码
  • 优化了int和long的曲线编码算法的曲线和瓦林特,避免了一些冗余方法调用和位 操作
  • 数据压缩量很小,压缩量小于Kryo和Protobuf;较小 比Kryo,因为Kryo需要编写每个对象的注册号
  • 智能语法,不正确的协议定义将无法启动程序并给出错误警告
  • 提高发展效率,完全支持Pojo开发,非常易于使用
The current size of the serialized object is as follows:
Simple objects, zfoo package size 8, kryo package size 5, protobuf package size 8
Regular objects, ZFOO package size 430, KRYO package size 483, Protobuf package size 793
For complex objects, ZFOO package size 2216, KRYO package size 2528, and Protobuf package size 5091

。数据类型

  • 默认数据格式支持消除了用户注册的需求
    手动.参考类定义

    • booleanï¼byteï¼hortï¼Intï¼longï¼floatï¼doubleishcharï¼字符串
    • booleanï¼byteï¼简短integerï¼longï¼floatï¼doubledouttrigentem如果在序列化过程中为null,则默认值为0 将给予(字符的默认值是字符。米值)
    • int []ï¼整数[]ï¼如果为null,则将其解析为长度为0
      • 本机通用列表,设置,地图,避免返回类型哈希集,数组列表,哈希地图和null指针 安全(返回尺寸0的集合)
      • listï¼您必须指定一个通用类,如果发送[1,1,null,1],并且接收[1,1,0,1]
      • listï¼如果发送[obj,obj,null,obj],[obj,obj,null,obj],也就是说,参考类型是 序列化之前的null,并且在序列化后也为null
  • 不支持的数据格式,因为ZFOO自动识别不支持类型并发出错误警告,因此用户
    不必太多

    • int [] [] [] []¼阵列以上二维的数组,考虑到并非所有语言都支持多维数组
    • 列表[]ï¼map[]ï¼ava语言本身不支持通用类数组
    • listï¼mapï¼的仿制物设置为阵列,看起来很奇怪,几乎没有实际用途
    • 考虑到许多其他语言不支持枚举类,可以替换 使用int或字符串的代码级
    • 自定义通用类XXX类,通用类容易出现在许多人中的性能和解析问题 框架,所有语言都不支持
    • 圆形引用,尽管基本支持循环引用,但考虑了循环引用 在语义上难以理解并容易出现错误,因此它们被阻止

…。协议规范

  • 协议类必须是一个简单的Javabean,不从任何其他类继承,而是可以继承界面

  • 为了防止代码中的对象并避免由对象混合引起的一些潜在的并发问题
    在协议层和PO层中,ZFOO要求协议类必须实现iPacket接口

Now the interface of IPacket is just an identification interface, inheriting the design of IPacket is mainly to make 
the code more elegant and easier to understand, and it is not a lot of work to inherit only Object

The design of inheriting IPacket also has cross-language considerations, which greatly simplifies the difficulty 
of serialization and deserialization in other languages and unifies the code implementation of other languages
  • 协议编号定义为减少数据包大小和内存大小的短类型,可以将数据包减少2 字节,每个协议的应用记忆也可以减少6个字节(协议 + iProtocolRegregistration + protocolIdmap)
It is difficult for a project's protocol body class to exceed 3 w, and there will be tools that automatically package 
your protocol number a little more compactly, so that your protocol number will not exceed 3 w
  • 有两种方法可以指示协议类必须标记为协议号

    • 第一个使用注释: @protocol(id = protoctidid)
      @Protocol(id = 104)
      public class SimpleObject implements IPacket {
    
          public int c;
          public boolean g;
    
      }
    
    • 第二种使用静态常数 +接口:该协议号的值必须与值相同 由易发器接口返回,可以稍微提高性能
      public class SimpleObject implements IPacket {
    
          public static final short PROTOCOL_ID = 104;
    
          public int c;
    
          public boolean g;
    
          @Override
          public short protocolId() {
              return PROTOCOL_ID;
          }
    
      }
    
    • 第三种用途:通过协议Manager.initprotococolauto()注册协议,而无需编写协议 数字
      public class SimpleObject implements IPacket {
    
          public int c;
    
          public boolean g;
    
      }
    
  • 如果添加了版本兼容性的字段,则需要添加兼容注释,并且该顺序需要为


    自然增加,以确保旧协议可以彼此兼容

  • 为了与版本兼容并避免修改字段名称,默认值使用字段名称读写



    按照字符串的自然顺序(也可以自定义),因此会导致序列化例外

  • 官方环境不一定必须删除不需要的字段才能兼容和


    避免减少字段

  • 在设计模式的六个原则中,开放和关闭的原则开放,可扩展,并关闭


    修改。协议的设计在功能方面也应遵守该原则,

    优先考虑将新协议添加而不是修改现有协议

A…§。在ZFOO中使用Protobuf

  • ZFOO仅在Pojo之类的方式下提供Protobuf,但它可以生成proto文件供客户端使用
    通过pojo对象

  • jprotobuf您可以直接使用简单的POJO对象而无需
    了解原始文件操作和语法

  • 生成一个原始文件供客户端通过POJO使用
    对象,Generate a proto configuration

  • 您也可以自定义自己的构建方法,
    Use code custom generation to proto