• 序列化方式介绍和性能比较 (kryo fastjson hessian jdk)


    目录

    测试条件

    序列化对象

    结果展示

    码流大小比较

    fastJson < kryo < hessian < jdk

    序列化+反序列化速度

    测试代码

    序列化+反序列化

    序列化速度

    反序列化速度

    待验证

    四种序列化介绍以及Demo

    JDK自带序列化

    Hessian

    Hessian2.0的Demo实现

    Kryo

    为什么kryo序列化后的字节流很小?

    FastJson


    测试条件

    • 操作系统:Windows
    • 内存:16 GB DDR4
    • 处理器:3.2GHz 八核 AMD Ryzen 7 5800H

    序列化框架版本

    序列化框架fastjsonkryohessianjdk
    版本1.2.293.0.34.0.621.8

    序列化对象

    采用同一个对象 RpcInvocation 进行测试,由于 bean 对象的不同,测试结果可能会有差异。

    1. static final String UUIDstr = UUID.randomUUID().toString();
    2. static RpcInvocation rpcInvocation = new RpcInvocation();
    3. static {
    4. rpcInvocation.setRetry(1);
    5. rpcInvocation.setTargetMethod("sendData");
    6. rpcInvocation.setTargetServiceName("org.idea.VVrpc.framework.interfaces.DataService");
    7. rpcInvocation.setArgs(new Object[]{"hello"});
    8. rpcInvocation.setUuid(UUIDstr);
    9. }

    结果展示

    码流大小比较

    fastJson < kryo < hessian < jdk

    序列化+反序列化速度

    测试代码

    1. @BenchmarkMode({Mode.Throughput})
    2. @Warmup(iterations = 3,time = 3,timeUnit = TimeUnit.SECONDS)
    3. @Measurement(iterations = 3, time = 5,timeUnit = TimeUnit.SECONDS)
    4. @Fork(1)
    5. public class SerializeRpcCompareTest {
    6. static final String UUIDstr = UUID.randomUUID().toString();
    7. static RpcInvocation rpcInvocation = new RpcInvocation();
    8. static {
    9. rpcInvocation.setRetry(1);
    10. rpcInvocation.setTargetMethod("sendData");
    11. rpcInvocation.setTargetServiceName("org.idea.VVrpc.framework.interfaces.DataService");
    12. rpcInvocation.setArgs(new Object[]{"hello"});
    13. rpcInvocation.setUuid(UUIDstr);
    14. }
    15. static SerializeFactory jdkserializeFactory = new JdkSerializeFactory();
    16. static SerializeFactory hesserializeFactory = new HessianSerializeFactory();
    17. static SerializeFactory fastserializeFactory = new FastJsonSerializeFactory();
    18. static SerializeFactory kryoserializeFactory = new KryoSerializeFactory();
    19. @Benchmark
    20. public void jdkSerializeTest(){
    21. byte[] result = jdkserializeFactory.serialize(rpcInvocation);
    22. RpcInvocation deserializeUser = jdkserializeFactory.deserialize(result,RpcInvocation.class);
    23. }
    24. @Benchmark
    25. public void hessianSerializeTest(){
    26. byte[] result = hesserializeFactory.serialize(rpcInvocation);
    27. RpcInvocation deserializeUser = hesserializeFactory.deserialize(result,RpcInvocation.class);
    28. }
    29. @Benchmark
    30. public void fastJsonSerializeTest(){
    31. byte[] result = fastserializeFactory.serialize(rpcInvocation);
    32. RpcInvocation deserializeUser = fastserializeFactory.deserialize(result,RpcInvocation.class);
    33. }
    34. @Benchmark
    35. public void kryoSerializeTest(){
    36. byte[] result = kryoserializeFactory.serialize(rpcInvocation);
    37. RpcInvocation deserializeUser = kryoserializeFactory.deserialize(result,RpcInvocation.class);
    38. }
    39. public static void main(String[] args) throws RunnerException {
    40. Options options = new OptionsBuilder()
    41. .include(SerializeRpcCompareTest.class.getSimpleName())
    42. .build();
    43. new Runner(options).run();
    44. }
    45. }

    序列化+反序列化

    Score 表示 每秒进行 score次操作   单位: ops: operations per second

    一次操作指的是 执行一次方法体内的程序。

    序列化速度

     

    反序列化速度

     

    fastjson >  kryo > hessian >> jdk

    网上的测试 kryo大都排在第一位,可能测试的代码或者场景有些问题。

    搜到的一些可能原因:

    1.kryo 针对每一种类型 在序列化反序列化前都要实例化,否则会异常
    但是实例化又会影响性能,所以使用时,针对特定类型只要实例化一次,速度就会飞快.

    2.kryo在复杂对象的序列化时效果会比较好。

    待验证

    四种序列化介绍以及Demo

    JDK自带序列化

    JDK自带的序列化框架使用_trigger333的博客-CSDN博客

    深入理解Java序列化机制:ObjectOutputStream源码简要分析_A__Plus的博客-CSDN博客_objectoutputstream

    Hessian

    Hessian是caucho公司开发的轻量级RPC(Remote Procedure Call)框架,它使用HTTP协议传输,使用Hessian二进制序列化。

    Hessian由于其支持跨语言、高效的二进制序列化协议,被经常用于序列化框架使用。Hessian序列化协议分为Hessian1.0和Hessian2.0,Hessian2.0协议对序列化过程进行了优化(优化内容待看),在性能上相较Hessian1.0有明显提升。

    Hessian2.0的Demo实现

    1. public class HessianSerializeFactory implements SerializeFactory {
    2. @Override
    3. public byte[] serialize(T t) {
    4. byte[] data = null;
    5. try {
    6. ByteArrayOutputStream os = new ByteArrayOutputStream();
    7. Hessian2Output output = new Hessian2Output(os);
    8. output.writeObject(t);
    9. output.getBytesOutputStream().flush();
    10. output.completeMessage();
    11. output.close();
    12. data = os.toByteArray();
    13. } catch (Exception e) {
    14. throw new RuntimeException(e);
    15. }
    16. return data;
    17. }
    18. @Override
    19. public T deserialize(byte[] data, Class clazz) {
    20. if (data == null) {
    21. return null;
    22. }
    23. Object result = null;
    24. try {
    25. ByteArrayInputStream is = new ByteArrayInputStream(data);
    26. Hessian2Input input = new Hessian2Input(is);
    27. result = input.readObject();
    28. } catch (Exception e) {
    29. throw new RuntimeException(e);
    30. }
    31. return (T) result;
    32. }

    Kryo

    Kryo一个快速有效的Java二进制序列化框架,它依赖底层ASM库用于字节码生成,因此有比较好的运行速度。Kryo的目标就是提供一个序列化速度快、结果体积小、API简单易用的序列化框架。Kryo支持自动深/浅拷贝,它是直接通过对象->对象的深度拷贝,而不是对象->字节->对象的过程。
    kryo不是线程安全的, 所以需要使用ThreadLocal来存储kryo对象

    比kyro更高效的序列化库就只有google的protobuf了(而且两者性能很接近),protobuf有个缺点就是要传输的每一个类的结构都要生成对应的proto文件(也可以都放在同一个proto文件中,如果考虑到扩展性的话,不建议放在一个proto文件中),如果某个类发生修改,还得重新生成该类对应的proto文件.

    为什么kryo序列化后的字节流很小?

    源码分析Dubbo序列化-源码分析kryo序列化实现原理 - 码农岛

    Kryo 对 Class 的序列化只需要化 Class 的全路径名,在反序列化时根据 Class 通过类加载进行加载,大大减少了序列化后的文件大小,能极大提高性能。

    Kryo 的核心设计理念就是尽最大可能减少序列化后的文件大小,其举措1就是通过对long,int等数据类型,采用变长字节存储来代替java中使用固定字节(4,8)字节的模式,因为在软件开发中,对象的这些值基本上都是小值,能节省很多空间,第二个举措是使用了类似缓存的机制,在一次序列化对象中,在整个递归序列化期间,相同的对象,只会序列化一次,后续的用一个局部int值来代替。

    1. public class KryoSerializeFactory implements SerializeFactory {
    2. private static final ThreadLocal kryos = new ThreadLocal() {
    3. @Override
    4. protected Kryo initialValue() {
    5. Kryo kryo = new Kryo();
    6. return kryo;
    7. }
    8. };
    9. @Override
    10. public byte[] serialize(T t) {
    11. Output output = null;
    12. try {
    13. // 从当前线程中的 ThreadLocalMap 中拿到 kryo 并写入字节流
    14. Kryo kryo = kryos.get();
    15. ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
    16. output = new Output(byteArrayOutputStream);
    17. kryo.writeClassAndObject(output, t);
    18. return output.toBytes();
    19. } catch (Exception e) {
    20. throw new RuntimeException(e);
    21. } finally {
    22. if (output != null) {
    23. output.close();
    24. }
    25. }
    26. }
    27. @Override
    28. public T deserialize(byte[] data, Class clazz) {
    29. Input input = null;
    30. try {
    31. // 从当前线程中的 ThreadLocalMap 中拿到 kryo 并将字节流转化为 对象
    32. Kryo kryo = kryos.get();
    33. ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(data);
    34. input = new Input(byteArrayInputStream);
    35. return (T) kryo.readClassAndObject(input);
    36. } catch (Exception e) {
    37. throw new RuntimeException(e);
    38. } finally {
    39. if (input != null) {
    40. input.close();
    41. }
    42. }
    43. }
    44. }

     

    FastJson

    fastjson详解_吴声子夜歌的博客-CSDN博客_fastjson

    ​在前后端数据传输交互中,经常会遇到字符串(String)与json,XML等格式相互转换与解析,其中json以跨语言,跨前后端的优点在开发中被频繁使用,基本上可以说是标准的数据交换格式。fastjson 是一个java语言编写的高性能且功能完善的JSON库,它采用一种“假定有序快速匹配”的算法,把JSON Parse 的性能提升到了极致。它的接口简单易用,已经被广泛使用在缓存序列化,协议交互,Web输出等各种应用场景中。
    Demo 把 json 字符串转为 byte数组即可。

    1. public class FastJsonSerializeFactory implements SerializeFactory {
    2. @Override
    3. public byte[] serialize(T t) {
    4. String jsonStr = JSON.toJSONString(t);
    5. return jsonStr.getBytes();
    6. }
    7. @Override
    8. public T deserialize(byte[] data, Class clazz) {
    9. return JSON.parseObject(new String(data),clazz);
    10. }
    11. }

    转换效果:

     

    参考:

    几种常用序列化框架_涛歌依旧fly的博客-CSDN博客_序列化框架

    jackson、fastjson、kryo、protostuff等序列化工具性能对比_双面神像的博客-CSDN博客_kryo和fastjson

  • 相关阅读:
    【正点原子STM32连载】 第六十一章 UCOSII实验1-任务调度摘自【正点原子】MiniPro STM32H750 开发指南_V1.1
    用餐高峰期,排队现象严重?食堂多元化升级改造
    探索性测试的概念及方法
    重温《Unix设计哲学》
    SpringBoot + Vue实现博文上传+展示+博文列表
    JSD-2204-使用Idea启动Nacos-创建csmall项目-Dubbo-Day03
    解决json_decode解析返回null空值
    Appium入门自动化测试(6)—— Appium 常用方法的自己动手封装
    ArcGIS Pro导出布局时去除在线地图水印
    mysql加密存储敏感数据
  • 原文地址:https://blog.csdn.net/weixin_40757930/article/details/125950648