• 高性能的序列化与反序列化:kryo的简单使用


    前言:kryo是个高效的java序列化/反序列化库,目前Twitter、yahoo、Apache、strom等等在使用该技术,比如Apache的spark、hive等大数据领域用的较多。

    为什么使用kryo而不是其他?

    因为性能足够好。比kyro更高效的序列化库就只有google的protobuf了(而且两者性能很接近),protobuf有个缺点就是要传输的每一个类的结构都要生成对应的proto文件(也可以都放在同一个proto文件中,如果考虑到扩展性的话,不建议放在一个proto文件中),如果某个类发生修改,还得重新生成该类对应的proto文件;另外考虑到项目中用的全部是java技术栈,不存在不同编程语言间的兼容性问题,因此最终采用了kryo作为序列化库。

    使用场景:(数据交换或数据持久化)比如使用kryo把对象序列化成字节数组发送给消息队列或者放到redis等nosql中等等应用场景。

    注意:由于kryo不是线程安全的,针对多线程情况下的使用,要对kryo进行一个简单的封装设计,从而可以多线程安全的使用序列化和反序列化

    序列化和反序列化接口设计

    1. /**
    2. * 序列化工具(程序调用该接口来实现obj<->byte[]之间的序列化/反序列化)
    3. * @author eguid
    4. *
    5. */
    6. public interface Serializer{
    7.  
    8. /**
    9. * 序列化
    10. * @param t
    11. * @param bytes
    12. */
    13. public void serialize(Object t,byte[] bytes);
    14.  
    15. /**
    16. * 序列化
    17. * @param obj
    18. * @param bytes
    19. * @param offset
    20. * @param count
    21. */
    22. public void serialize(Object obj, byte[] bytes, int offset, int count);
    23.  
    24. /**
    25. * 反序列化
    26. * @param bytes -字节数组
    27. * @return T<T>
    28. */
    29. public <T>T deserialize(byte[] bytes);
    30.  
    31.  
    32. /**
    33. * 反序列化
    34. * @param bytes
    35. * @param offset
    36. * @param count
    37. * @return
    38. */
    39. public <T>T deserialize(byte[] bytes, int offset, int count);
    40.  
    41. }

    使用kryo实现上面的接口

    1. /**
    2. * 基于kyro的序列化/反序列化工具
    3. *
    4. * @author eguid
    5. *
    6. */
    7. public class kryoSerializer implements Serializer {
    8.  
    9. // 由于kryo不是线程安全的,所以每个线程都使用独立的kryo
    10. final ThreadLocal<Kryo> kryoLocal = new ThreadLocal<Kryo>() {
    11. @Override
    12. protected Kryo initialValue() {
    13. Kryo kryo = new Kryo();
    14. kryo.register(ct, new BeanSerializer<>(kryo, ct));
    15. return kryo;
    16. }
    17. };
    18. final ThreadLocal<Output> outputLocal = new ThreadLocal<Output>();
    19. final ThreadLocal<Input> inputLocal = new ThreadLocal<Input>();
    20. private Class<?> ct = null;
    21.  
    22. public kryoSerializer(Class<?> ct) {
    23. this.ct = ct;
    24. }
    25.  
    26. public Class<?> getCt() {
    27. return ct;
    28. }
    29.  
    30. public void setCt(Class<?> ct) {
    31. this.ct = ct;
    32. }
    33.  
    34. @Override
    35. public void serialize(Object obj, byte[] bytes) {
    36. Kryo kryo = getKryo();
    37. Output output = getOutput(bytes);
    38. kryo.writeObjectOrNull(output, obj, obj.getClass());
    39. output.flush();
    40. }
    41.  
    42. @Override
    43. public void serialize(Object obj, byte[] bytes, int offset, int count) {
    44. Kryo kryo = getKryo();
    45. Output output = getOutput(bytes, offset, count);
    46. kryo.writeObjectOrNull(output, obj, obj.getClass());
    47. output.flush();
    48. }
    49.  
    50. /**
    51. * 获取kryo
    52. *
    53. * @param t
    54. * @return
    55. */
    56. private Kryo getKryo() {
    57. return kryoLocal.get();
    58. }
    59.  
    60. /**
    61. * 获取Output并设置初始数组
    62. *
    63. * @param bytes
    64. * @return
    65. */
    66. private Output getOutput(byte[] bytes) {
    67. Output output = null;
    68. if ((output = outputLocal.get()) == null) {
    69. output = new Output();
    70. outputLocal.set(output);
    71. }
    72. if (bytes != null) {
    73. output.setBuffer(bytes);
    74. }
    75. return output;
    76. }
    77.  
    78. /**
    79. * 获取Output
    80. *
    81. * @param bytes
    82. * @return
    83. */
    84. private Output getOutput(byte[] bytes, int offset, int count) {
    85. Output output = null;
    86. if ((output = outputLocal.get()) == null) {
    87. output = new Output();
    88. outputLocal.set(output);
    89. }
    90. if (bytes != null) {
    91. output.writeBytes(bytes, offset, count);
    92. }
    93. return output;
    94. }
    95.  
    96. /**
    97. * 获取Input
    98. *
    99. * @param bytes
    100. * @param offset
    101. * @param count
    102. * @return
    103. */
    104. private Input getInput(byte[] bytes, int offset, int count) {
    105. Input input = null;
    106. if ((input = inputLocal.get()) == null) {
    107. input = new Input();
    108. inputLocal.set(input);
    109. }
    110. if (bytes != null) {
    111. input.setBuffer(bytes, offset, count);
    112. }
    113. return input;
    114. }
    115.  
    116. @SuppressWarnings("unchecked")
    117. @Override
    118. public <T> T deserialize(byte[] bytes, int offset, int count) {
    119. Kryo kryo = getKryo();
    120. Input input = getInput(bytes, offset, count);
    121. return (T) kryo.readObjectOrNull(input, ct);
    122. }
    123.  
    124. @Override
    125. public <T> T deserialize(byte[] bytes) {
    126. return deserialize(bytes, 0, bytes.length);
    127. }

    测试一下kryo的序列化和反序列化

    为什么使用纳秒,而不用毫秒?与java原生的序列化反序列化要耗时几毫秒不同,kryo序列化和反序列化太快了,单个对象的序列化反序列化速度都在0.0x毫秒左右(如果电脑性能更好的话,会更快)

    1. Serializer ser = new kryoSerializer(Msg.class);
    2. for (int i = 0; i < 10; i++) {
    3.  
    4. Msg msg = new Msg();
    5.  
    6. msg.setVersion_flag(new byte[] { 1, 2, 3 });
    7. msg.setCrc_code((short) 1);
    8. msg.setMsg_body(new byte[] { 123, 123, 123, 43, 42, 1, 12, 45, 57, 98 });
    9. byte[] bytes = new byte[300];
    10. long start = System.nanoTime();
    11. ser.serialize(msg, bytes);
    12. System.err.println("序列化耗时:" + (System.nanoTime() - start));
    13. System.out.println(msg);
    14. System.out.println(Arrays.toString(bytes));
    15.  
    16. Msg newmsg = null;
    17. start = System.nanoTime();
    18. newmsg = ser.deserialize(bytes);
    19. System.err.println("反序列化耗时:" + (System.nanoTime() - start));
    20. System.out.println(newmsg);
    21. }

    ----end----

  • 相关阅读:
    Linux安装JDK1.8
    两台Linux主机之间文件的复制
    Tigase数据库结构(1)
    应用架构之接入层原理
    MySQL开发规范
    Google MapReduce到底解决什么问题?
    使用 RestTemplate 调用 restful 服务
    App开放接口API安全性 — Token签名sign的设计与实现
    深入探讨 Java 类加载器
    Java 的 I/O 类库的基本架构
  • 原文地址:https://www.cnblogs.com/eguid/p/9667133.html
Copyright © 2020-2023  润新知