订阅更新

Flink的State为什么用序列化存储?——Java序列化机制全解析

Java手册 第 4 题 约 8 分钟读完

本文目录
  1. 先说结论
  2. 为什么需要序列化?——三大场景
  3. Java原生序列化——为什么不推荐?
  4. 主流序列化框架对比
  5. Flink的序列化体系——为什么Flink不用Kryo?
  6. Spark的序列化——Kryo vs Java Serializable
  7. 实战踩坑:Flink Checkpoint变慢——序列化是罪魁祸首
  8. 面试高频追问
  9. 总结

先说结论

序列化是把Java对象转成字节数组的过程,反序列化是反过来。大数据场景需要序列化的地方:网络传输(Shuffle/RPC)、持久化存储(State/Checkpoint)、缓存(堆外内存)。Java原生序列化(Serializable)最慢最大,不推荐。大数据推荐Kryo(通用)或框架内置序列化器(Flink的TypeSerializer、Spark的Encoder)。

先把这段讲顺;面试官追问时,再展开下面的原理和细节。

详细讲解

序列化在大数据领域无处不在:Flink的State要序列化才能做Checkpoint、Spark的RDD在Shuffle时要序列化传输、Kafka的消息要序列化才能发送到Broker。在某元宇宙社交公司用Flink做实时数仓时,有一次Checkpoint突然从秒级变成了分钟级——排查发现是新加了一个复杂的State对象,用的Java默认序列化非常慢。改成Flink的内置序列化器后Checkpoint恢复正常。序列化性能直接影响大数据作业的效率。

为什么需要序列化?——三大场景

场景具体用途序列化的原因
网络传输Spark Shuffle、Flink算子间数据交换对象不能直接在网络上传输,必须转成字节流
持久化存储Flink Checkpoint、Spark RDD缓存到磁盘对象在内存里,持久化要写成字节
堆外内存Flink RocksDB State、Spark Tungsten堆外内存存的是字节数组不是Java对象

Java原生序列化——为什么不推荐?

// Java原生序列化(实现Serializable接口)
public class UserEvent implements Serializable {
    private static final long serialVersionUID = 1L;
    private long userId;
    private String eventName;
    private double amount;
}
 
// 序列化:对象写入字节流
ByteArrayOutputStream baos = new ByteArrayOutputStream();
ObjectOutputStream oos = new ObjectOutputStream(baos);
oos.writeObject(event);
byte[] bytes = baos.toByteArray();
 
// 问题:
// 1. 体积大——包含完整的类名、字段名、类型信息
//    一个简单对象序列化后可能是Kryo的5-10倍大
// 2. 速度慢——反射遍历所有字段,性能差
// 3. 不跨语言——只有Java能反序列化
// 4. 安全风险——反序列化漏洞(CVE频出)

主流序列化框架对比

框架体积速度跨语言适用场景
Java Serializable大(5-10x)最慢否不推荐
Kryo小(1-2x)快(5-10x比Java)否Spark默认、通用Java
Protobuf最小(0.5-1x)很快是跨语言RPC/消息
Avro小(1x)快是Kafka消息、Schema演进
Flink TypeSerializer最小最快否Flink专用

Flink的序列化体系——为什么Flink不用Kryo?

Flink有自己的序列化体系(TypeSerializer),比Kryo还快。原因是Flink在编译时就知道数据的类型信息(通过TypeInformation),可以生成高度优化的序列化代码。

// Flink对常见类型有专门的序列化器
// 比如Tuple3<Long, String, Double>
// Flink知道第1个字段是Long(8字节)、第2个是String、第3个是Double(8字节)
// 序列化时直接按字段顺序写入字节,不需要额外的类型信息
 
// 什么时候Flink会退化为Kryo?
// 当Flink无法推断类型时(比如用了泛型、匿名类、或复杂的POJO)
// Flink日志中会打印WARNING:
// 'Using Kryo serialization for type: YourClass'
// 这时性能会下降3-5倍!
 
// 怎么避免Flink退化为Kryo?
// 1. 用Flink支持的类型:Tuple、POJO(public字段+无参构造)
// 2. 用@TypeInfo注解手动指定TypeInformation
// 3. 避免在Lambda中使用匿名类
// 4. 用Flink的Row类型(Table API/SQL推荐)

Spark的序列化——Kryo vs Java Serializable

# Spark默认用Java序列化,性能差
# 强烈推荐切换到Kryo
 
# 配置Kryo序列化
spark.serializer = org.apache.spark.serializer.KryoSerializer
 
# 注册自定义类(提高Kryo效率)
spark.kryo.registrationRequired = false
spark.kryo.classesToRegister = com.myapp.UserEvent,com.myapp.Device
 
# Kryo vs Java序列化的性能差距
# 序列化速度:Kryo快5-10倍
# 序列化体积:Kryo小2-5倍
# Shuffle数据量直接减半 ==> 作业更快
 
# 我在出海硬件品牌把Spark切到Kryo后
# Shuffle密集型作业平均快了20-30%

实战踩坑:Flink Checkpoint变慢——序列化是罪魁祸首

在某元宇宙社交公司,Flink的一个Job使用了ValueState存储用户画像信息。一开始用户画像类是一个简单的POJO(几个基本类型字段),Checkpoint秒级完成。

后来产品需求加了一个Map类型的字段(用户标签,Map<String, List>),Flink无法用内置序列化器处理复杂嵌套的Map+List结构,退化成了Kryo序列化。

症状:Checkpoint从2秒涨到45秒,因为每次Checkpoint都要把所有State序列化一遍,Kryo处理嵌套Map比内置序列化器慢了20倍。

解决方案:① 把Map<String, List>改成JSON字符串存储,Flink对String有高效的内置序列化器;② 在反序列化时手动解析JSON。虽然多了JSON解析的开销,但Checkpoint速度从45秒回到了3秒——因为序列化的瓶颈远大于JSON解析的开销。

教训:Flink的State类型设计要尽量使用Flink能高效序列化的类型(基本类型、String、Tuple、简单POJO)。复杂嵌套结构会导致退化为Kryo,Checkpoint性能急剧下降。

面试高频追问

追问一:serialVersionUID有什么用?不写会怎样?

serialVersionUID用于版本控制——反序列化时检查序列化端和反序列化端的类版本是否一致。如果不写,JVM会根据类的结构自动生成一个。问题是:如果你修改了类的字段(加了一个字段),自动生成的UID会变,导致反序列化失败。在Flink中这意味着从旧Checkpoint恢复时State可能读不出来。所以一定要显式定义serialVersionUID。

追问二:Protobuf和Avro有什么区别?

Protobuf用字段编号标识(更紧凑、速度更快),适合RPC和对性能要求高的场景。Avro用Schema描述数据结构,支持Schema演进(新增字段不影响旧数据),适合数据存储和Kafka消息。在Kafka消息格式那篇(Kafka第11篇)详细讲过。

追问三:Flink为什么不全部用Protobuf?

Protobuf需要提前定义.proto文件并编译生成Java类,使用门槛比较高。Flink的内置序列化器对常见类型(基本类型、String、Tuple)已经足够快了,不需要引入Protobuf的复杂性。只有在跨系统通信或对序列化体积极度敏感的场景才值得用Protobuf。

总结

序列化面试讲清楚三层:① 为什么需要序列化(网络传输+持久化+堆外内存);② 框架对比(Java Serializable最慢不推荐、Kryo通用较快、Flink TypeSerializer最快、Protobuf跨语言最紧凑);③ 大数据场景的最佳实践(Spark用Kryo替代默认序列化、Flink用简单类型避免退化为Kryo)。能讲出Flink Checkpoint因序列化退化变慢的踩坑和解决方案,面试官会觉得你对序列化的影响有实战认知。

下一篇聊一个很底层但面试爱考的题:一个Java对象到底占多少内存?怎么估算Spark/Flink的内存需求?

你们Spark/Flink用的什么序列化?切换过Kryo吗?评论区聊聊~

关注「Wood聊大数据」| 9年大数据老兵,聊技术、聊职场、聊成长

刷题进度保存在当前浏览器