当前位置: 首页 > news >正文

序列化和反序列化:从理论到实践的全方位指南

你好,我是 shengjk1,多年大厂经验,努力构建 通俗易懂的、好玩的编程语言教程。 欢迎关注!你会有如下收益:

  1. 了解大厂经验
  2. 拥有和大厂相匹配的技术等

希望看什么,评论或者私信告诉我!

文章目录

    • 一、 背景
    • 二、什么是序列化 和 反序列化
    • 三、序列化和普通的字符编码转换的区别:
    • 三、 为什么需要序列化
      • 3.1 序列化的核心价值
      • 3.2、不序列化网络传输的核心问题
    • 四、常见的序列化对比
    • 五、总结

一、 背景

上一篇文章,我们了解了网络模型 OSI 和 TCP/IP的联系和区别,今天结合TCP/IP 聊一下 序列化的应用过程

二、什么是序列化 和 反序列化

简单来说,序列化就是把一个Java对象转换成一系列字节的过程,这些字节可以被存储到文件、数据库,或者通过网络传输。反过来,反序列化则是把这些字节重新转换成Java对象的过程。

想象一下,你有一个手机应用中的用户对象(比如用户的名字、年龄等信息)。如果你想将这个用户对象存储起来,或者发送给服务器,你就需要先序列化它。等到需要使用的时候,再通过反序列化把它恢复成原来的对象。

三、序列化和普通的字符编码转换的区别:

  • 序列化(Serialization):
  1. 是将整个对象的状态(包括其属性、关系等)转换为字节序列
  2. 目的是保存/传输对象的完整状态,以便之后可以重建对象
  3. 包含对象的类型信息、属性结构等元数据
  • 字符编码转换
  1. 仅是将字符按照编码规则转换为字节
  2. 不包含任何元数据或类型信息
  3. 只是一种字符到字节的映射转换

三、 为什么需要序列化

从网络层来说的话,数据在网络中传输都是以二进制的形式,所以要么你自己手动序列化,要么框架帮你序列化,比如 Flink 在分布式计算中对 java 对象的序列化

3.1 序列化的核心价值

1. 跨平台与跨语言兼容性
序列化通过将对象状态转换为与架构无关的标准化格式(如二进制流或JSON),解决了不同硬件架构、操作系统和编程语言之间的兼容性问题。例如:
• 内存布局差异:直接传输内存指针会因32位/64位系统对齐方式不同导致解析错误。

• 数据表示统一:二进制协议(如Protobuf)通过TLV编码消除字节顺序(大端/小端)影响,确保跨平台数据一致性。

2. 数据完整性与持久化
序列化能完整保存对象状态(包括私有字段和嵌套对象),而不仅仅是基础数据。例如:
• 复杂对象持久化:Java的Serializable接口通过递归序列化对象及其引用的所有对象,实现深复制。

• 恢复能力:将用户会话数据序列化后存入Redis,重启服务时可精确重建状态。

3. 网络传输效率优化
序列化通过压缩数据体积和减少冗余提升传输效率:
• 体积对比:Protobuf的二进制编码体积仅为JSON的1/3,节省带宽。

• 性能优势:Spark使用Kryo序列化将内存占用减少50%,反序列化速度提升2倍。

3.2、不序列化网络传输的核心问题

1. 数据解析失败与结构混乱
• 内存布局不可控:直接传输结构体可能导致不同平台的内存对齐差异(如C++结构体在32位/64位系统下占用不同空间)。

• 私有字段丢失:未序列化的对象可能因语言特性(如Java反射机制未启用)无法访问私有字段。

2. 性能与资源浪费
• 冗余数据开销:未压缩的内存对象包含元数据(如类名、方法签名),导致带宽浪费。例如,Java原生序列化体积比Protobuf大30%以上。

• 解析效率低下:文本格式(如XML)需逐字符解析,耗时是二进制协议的5-10倍。

3. 安全与稳定性风险
• 反序列化攻击:未经验证的字节流可能触发恶意代码(如Java的readObject()漏洞)。

• 版本兼容性崩溃:未定义serialVersionUID的类在字段增减后,反序列化会因版本不匹配抛出异常。

三、典型场景对比

场景使用序列化不使用序列化
分布式服务调用通过gRPC + Protobuf实现跨语言通信,延迟低于5ms需手动拼接字符串或结构体,易因平台差异解析失败(如C++结构体在Python端无法读取)
数据库存储对象序列化为BLOB字段(如Java的Serializable),支持嵌套对象持久化仅能存储基础类型字段,复杂对象需拆分为多表,维护成本高
缓存系统Redis通过MessagePack存储会话对象,反序列化速度比JSON快2倍缓存仅支持字符串键值,复杂对象需多次查询拼接,增加I/O压力

四、如何选择序列化方案?

  1. 性能敏感场景:选择二进制协议(如Protobuf、FlatBuffers),适用于高并发微服务。
  2. 可读性优先场景:使用JSON/XML,适合API调试或配置文件。
  3. 跨语言需求:Thrift、Avro提供多语言IDL支持,适合混合技术栈。
  4. 安全性要求:避免Java原生序列化,采用加密协议(如Protobuf + TLS)。

四、常见的序列化对比

常见序列化协议全面对比与应用场景选择指南

一、核心协议特性对比

协议核心优势主要缺陷适用场景
JSON可读性强、全语言原生支持、动态扩展性好体积大(比Protobuf大2-3倍)、性能较低(解析速度约5us/次)前后端API交互、移动端通信、配置文件
Protobuf性能顶级(序列化速度比JSON快8倍)、体积最小(比JSON小25%)、版本兼容性强需预编译.proto文件、调试困难(二进制不可读)、动态类型支持弱高并发微服务(如gRPC)、大数据存储(Hadoop/Spark)、跨防火墙通信
Thrift内置RPC框架、支持30+语言、字段增删兼容性好开发复杂(需生成代码)、不支持HTTP协议集成、线程安全性差跨语言服务网格(如Java-PHP混合架构)、金融交易系统
MessagePack二进制体积比JSON小50%、解析速度比JSON快3倍、兼容JSON数据结构不支持复杂嵌套模型、依赖字段顺序维护、跨语言模型同步困难Redis缓存会话、移动端数据传输、IoT设备通信
XML树形结构清晰、支持命名空间、企业级标准兼容体积最大(比JSON大20%)、解析速度最慢(100us/次)、冗余标签多传统银行系统、Office文档格式(如Word/Excel)、遗留系统集成

二、应用场景

  1. 性能优先场景
    • 选择Protobuf:适用于要求<50ms响应时间的微服务调用(如电商秒杀系统)

    • 备选MessagePack:适合简单数据结构的实时传输(如智能家居设备状态上报)

  2. 跨语言RPC需求
    • 选择Thrift:提供完整的服务发现、负载均衡等RPC生态(如跨Java/Python的支付系统)

    • 备选gRPC+Protobuf:需要HTTP/2协议支持时优先考虑(如Kubernetes服务通信)

  3. 可读性优先场景
    • 选择JSON:前后端联调、第三方开放API(如天气预报接口)

    • 备选XML:需严格数据校验时使用(如银行SWIFT报文)

  4. 存储优化场景
    • 列式存储选Protobuf:HDFS中存储PB级日志(如用户行为分析数据)

    • 文档存储选Avro:Hive表结构动态扩展时更优(如数据仓库分层存储)

三、协议扩展性设计原则

  1. 版本兼容策略
    • Protobuf采用字段编号机制(新增字段用optional,删除字段标记reserved
    • JSON通过@version元数据字段实现多版本共存(需手动处理废弃字段)

  2. 安全加固方案
    • 敏感字段加密:对Protobuf的bytes类型使用AES-GCM加密
    • 完整性校验:Thrift数据包末尾追加HMAC签名

四、典型错误规避建议

  1. Java原生序列化陷阱
    • 避免直接使用Serializable接口:存在远程代码执行漏洞(如Log4j反序列化攻击)
    • 替代方案:改用Kryo(性能提升3倍)或FST(零拷贝优化)

  2. MessagePack使用误区
    • 禁止嵌套复杂对象:如订单含用户画像数据时改用Protobuf
    • 字段顺序强制约定:跨语言场景需同步.msg定义文件

五、总结
• 新项目:微服务优先Protobuf,Web应用主用JSON,IoT设备选MessagePack

• 遗留系统:Java序列化迁移至Kryo,XML逐步替换为JSON Schema

• 大数据场景:Hadoop生态用Avro,实时计算用Protobuf

五、总结

序列化是将对象转换为字节序列的过程,用于数据存储、网络传输和跨平台通信。它与字符编码转换不同,包含对象的完整状态和元数据。序列化的重要性体现在跨平台兼容性、数据完整性和网络传输效率等方面。文章对比了多种序列化协议,提供了选择建议和应用场景指南,帮助开发者根据需求选择合适的序列化方案。同时,还介绍了协议扩展性设计原则和常见错误的规避方法,为实际应用提供了参考。

http://www.xdnf.cn/news/447913.html

相关文章:

  • c++STL——哈希表封装:实现高效unordered_map与unordered_set
  • teneo自动机器人部署教程
  • 固定步长和变步长的LMS自适应滤波器算法
  • [Spring]-组件的生命周期
  • 【Linux网络】传输层协议TCP
  • TypeScript泛型:从入门到精通的全方位指南
  • Linux下的c/c++开发之操作Redis数据库
  • 上网行为审计软件系统说明书:上网行为审计是什么?是干啥的?哪家好?
  • AI世界的崩塌:当人类思考枯竭引发数据生态链断裂
  • new optimizers for dl
  • 在Unity中制作拥有36年历史的游戏系列新作《桃太郎电铁世界》
  • 通过宝塔配置HTTPS证书
  • Python爬虫实战:研究拦截器,实现逆向解密
  • UI 原型设计:交互规则的三要素——重要性、原则与实践
  • 【Liblib】基于LiblibAI自定义模型,总结一下Python开发步骤
  • 小说所有设定(v3.0 preview)
  • Qml自定义组件之车辆风扇展示
  • 【Linux】掌握 setsid:让进程脱离终端独立运行
  • 三种映射方式总结
  • 第二十九节:直方图处理-直方图均衡化
  • ET ProcessInnerSender类(实体) 分析
  • ultralytics中tasks.py---parse_model函数解析
  • 求助求助,重金酬谢
  • Java知识框架
  • AIGC与数字媒体实验室解决方案分享
  • Jmeter对服务端进行压测快速上手
  • 【电路笔记 通信】8B/10B编码 高速数据传输的串行数据编码技术 论文第三部分 The 8B/10B coding map
  • HarmonyOS NEXT 适配高德地图FlutterSDK实现地图展示,添加覆盖物和移动Camera
  • OpenCV CUDA 模块中用于在 GPU 上计算两个数组对应元素差值的绝对值函数absdiff(
  • Flutter 开发入门:从一个简单的计数器应用开始