序列化与反序列化:概念、作用及应用
一、基本定义
-
序列化(Serialization)
将 ** 对象的状态(数据、属性等)转换为可存储或传输的字节流(二进制或文本格式)** 的过程。- 目的:使对象能在网络中传输(如 RPC 调用)、存储到文件 / 数据库,或在内存中持久化保存。
- 本质:将复杂的对象结构 “flatten” 为线性字节序列,便于跨平台、跨进程处理。
-
反序列化(Deserialization)
将字节流恢复为原始对象的过程,是序列化的逆操作。- 目的:从存储介质或网络接收端重构对象,恢复其状态和功能。
二、核心作用
-
数据存储与持久化
- 例:将内存中的对象(如用户信息、配置参数)保存到文件(如 JSON、XML、二进制文件)或数据库,以便后续重新加载。
- 典型场景:缓存系统(如 Redis 存储对象)、日志记录、断点续传。
-
网络通信与跨进程交互
- 在分布式系统中(如 RPC 框架、微服务),对象需通过网络传输时,必须先序列化为字节流,接收方再反序列化为对象。
- 例:Hadoop 中 MapReduce 任务间传递数据时,自定义的
Writable
对象需实现序列化接口,确保节点间数据正确传输。
-
对象状态共享
- 在分布式环境中,序列化可用于复制对象状态(如分布式锁、集群节点状态同步)。
三、常见应用场景
-
分布式系统
- Hadoop/Spark:自定义数据类型(如
Text
、IntWritable
)需实现Writable
接口,确保在 Map/Reduce 任务间序列化传输。 - RPC 框架(如 gRPC、Thrift):通过序列化协议(如 Protocol Buffers、JSON)定义接口参数和返回值的格式。
- Hadoop/Spark:自定义数据类型(如
-
数据交换格式
- 文本格式:JSON、XML(可读性强,适合跨语言交互,但效率较低)。
- 二进制格式:Protocol Buffers、Apache Avro、Thrift(体积小、解析快,适合高性能场景)。
- 语言特定格式:Java 的
ObjectOutputStream
、Python 的pickle
(仅适用于同语言环境,可能存在安全风险)。
-
缓存与持久化
- Redis 支持序列化对象存储(需选择高效格式如 MsgPack)。
- Java 对象序列化后可写入
ObjectInputStream/ObjectOutputStream
。
四、不同语言的实现方式
语言 | 序列化框架 / 接口 | 特点 |
---|---|---|
Java | Serializable 接口、Kryo、Protostuff | 内置Serializable 简单但效率低;Kryo 等第三方库性能更高。 |
Python | pickle 、dill 、JSON、Protocol Buffers | pickle 支持复杂对象但不安全;JSON 跨语言友好,需手动转换数据类型。 |
C++ | Protobuf、FlatBuffers | 高性能二进制格式,需定义 IDL(接口描述语言)。 |
通用 | JSON、XML、Protobuf、Avro | 跨语言支持,适合微服务、API 数据交互。 |
五、关键技术点与注意事项
-
序列化协议的选择
- 性能:二进制格式(如 Protobuf)比文本格式(如 JSON)更快、更紧凑,适合大数据量或高频交互场景。
- 兼容性:需考虑版本变更时的向后兼容(如 Protobuf 允许新增字段,不破坏旧解析逻辑)。
- 安全性:避免使用不安全的反序列化接口(如 Python 的
pickle
直接反序列化不可信数据可能导致代码执行攻击)。
-
自定义序列化逻辑
- 当内置序列化机制无法满足需求时(如忽略敏感字段、压缩数据),需自定义序列化方法。
- 例:Hadoop 中自定义
Writable
类型需实现write()
(序列化)和readFields()
(反序列化)方法,确保数据在集群中正确传输。
-
反序列化漏洞
- 风险:若反序列化不可信数据,可能导致远程代码执行(如 Java 的反序列化漏洞 CVE-2015-4852)。
- 防护:避免反序列化不可信数据,使用安全的序列化协议(如 Protobuf),或对输入数据进行严格校验。