1. 什么时候需要"第三方序列化器"?
- 你的类型无法被 Flink 类型系统识别(或性能不佳),Flink 退回到 Kryo 泛型序列化。
- 你已有统一的数据协议:Protobuf / Thrift。
- 你需要为某些复杂类型自定义更紧凑的二进制格式 或更快的序列化路径。
2. 用 pipeline.serialization-config 注册序列化器(YAML 方式)
最简单的方式是在配置里声明"某类型 → 某 Kryo 序列化器类":
yaml
pipeline.serialization-config:
- org.example.MyCustomType: {type: kryo, kryo-type: registered, class: org.example.MyCustomSerializer}
type: kryo:告诉 Flink 这是给 Kryo 用的配置kryo-type: registered:以注册类型方式绑定该序列化器class::你的 KryoSerializer实现类(需 extendscom.esotericsoftware.kryo.Serializer)
适用于:你已经写好
MyCustomSerializer,希望 Kryo 按此路由处理MyCustomType。
3. 代码里动态注册(Java 方式)
java
Configuration config = new Configuration();
config.set(
PipelineOptions.SERIALIZATION_CONFIG,
List.of("org.example.MyCustomType: {type: kryo, kryo-type: registered, class: org.example.MyCustomSerializer}")
);
StreamExecutionEnvironment env = StreamExecutionEnvironment.getExecutionEnvironment(config);
适合动态场景(多租户 / 平台统一下发);和 YAML 写法一致,只是放在代码侧。
4. 接入 Protobuf / Thrift(现成序列化器)
Kryo 社区已实现了常用协议的序列化器,直接注册即可。
4.1 Protobuf
yaml
pipeline.serialization-config:
- org.example.MyCustomProtobufType:
{type: kryo, kryo-type: registered, class: com.twitter.chill.protobuf.ProtobufSerializer}
Maven 依赖:
xml
<dependency>
<groupId>com.twitter</groupId>
<artifactId>chill-protobuf</artifactId>
<version>0.7.6</version>
<exclusions>
<exclusion>
<groupId>com.esotericsoftware.kryo</groupId>
<artifactId>kryo</artifactId>
</exclusion>
</exclusions>
</dependency>
<!-- Protobuf 运行库 -->
<dependency>
<groupId>com.google.protobuf</groupId>
<artifactId>protobuf-java</artifactId>
<version>3.7.0</version>
</dependency>
4.2 Thrift
yaml
pipeline.serialization-config:
- org.example.MyCustomThriftType:
{type: kryo, kryo-type: default, class: com.twitter.chill.thrift.TBaseSerializer}
kryo-type: default:将该序列化器作为 Kryo 的默认序列化器 进行初始化(适配 ThriftTBase族)。
Maven 依赖:
xml
<dependency>
<groupId>com.twitter</groupId>
<artifactId>chill-thrift</artifactId>
<version>0.7.6</version>
<exclusions>
<exclusion>
<groupId>com.esotericsoftware.kryo</groupId>
<artifactId>kryo</artifactId>
</exclusion>
</exclusions>
</dependency>
<!-- libthrift 是 chill-thrift 的依赖 -->
<dependency>
<groupId>org.apache.thrift</groupId>
<artifactId>libthrift</artifactId>
<version>0.11.0</version>
<exclusions>
<exclusion>
<groupId>javax.servlet</groupId>
<artifactId>servlet-api</artifactId>
</exclusion>
<exclusion>
<groupId>org.apache.httpcomponents</groupId>
<artifactId>httpclient</artifactId>
</exclusion>
</exclusions>
</dependency>
版本号请按你公司仓库与兼容矩阵调整(尤其是 Kryo 与 chill 版本的搭配)。
5. 大坑预警:不要直接用 Kryo 的 JavaSerializer
如果你注册了 com.esotericsoftware.kryo.serializers.JavaSerializer 给某个类型,即使类在用户 JAR 里,也可能在 TaskManager 上遇到 ClassNotFoundException 。
根因:Kryo 的 JavaSerializer 在某些情况下会使用错误的类加载器。
解决方案:使用 Flink 维护的替代实现
org.apache.flink.api.java.typeutils.runtime.kryo.JavaSerializer
它确保使用用户代码类加载器,避免找不到类。
这类问题在 Flink 社区里有长期跟踪(参见 FLINK-6025)。上线前务必替换。
6. 选择 registered 还是 default?
- registered :只针对指定类型 启用该序列化器;推荐,影响面小,可控。
- default :把某个序列化器设为 Kryo 的默认 ,所有无法匹配的类型都走它;谨慎使用,适合协议族(如 Thrift
TBase)统一托管。
7. 最佳实践与性能建议
-
优先避免"隐式 Kryo"回退
- 能让 Flink 识别为 POJO/基础类型/受支持集合 更好;
- 若必须走 Kryo,务必显式注册序列化器并做基准测试。
-
分清"类注册"和"默认序列化器"
- 大多数场景用
registered即可; default只在你非常确定类型族一致时使用。
- 大多数场景用
-
关注与 State 演进的关系
- Kryo 本身不支持 Schema 演进检查(无法验证兼容性);
- 如果状态里包含走 Kryo 的结构,后续状态模式演进将受限。
- 关键状态建议改为 POJO/Avro 或切到自定义可演进序列化器(参阅"Custom Serialization for Managed State")。
-
依赖版本与冲突
chill-*与kryo版本要匹配;- 经常需要在 chill 依赖里 exclusion 掉 kryo,以使用你平台统一的 Kryo 版本;
- 注意 Protobuf/Thrift 的传递依赖,避免与现网版本冲突。
-
基准测试与内存观测
- 对关键类型:对比 编码大小、序列化/反序列化 QPS、GC 分配率;
- 结合真实算子链路与 checkpoint 压力测试,评估是否需要更紧凑的编码或对象复用。
8. 上线清单(Checklist)
- 关键类型是否已被 Flink 识别(POJO/集合)?否则是否显式注册了 Kryo 序列化器?
- 是否存在 Kryo JavaSerializer 的使用?若有,已替换为 Flink JavaSerializer。
- Protobuf/Thrift 的 chill 依赖已加入 ,且与 kryo 版本兼容。
-
pipeline.serialization-config中类型名与类名拼写正确,生效范围(环境)明确。 - 关键链路做过序列化基准测试 与端到端压测。
- 若涉及状态:确认是否需要状态模式演进;如需要,避免 Kryo 或改走可演进方案。
9. 参考示例:同时注册自定义 + Protobuf + Thrift
yaml
pipeline.serialization-config:
# 绑定自定义 Kryo 序列化器
- org.acme.types.GeoHash: {type: kryo, kryo-type: registered, class: org.acme.ser.GeoHashKryoSerializer}
# Protobuf:使用 chill-protobuf
- org.acme.proto.UserEventProto:
{type: kryo, kryo-type: registered, class: com.twitter.chill.protobuf.ProtobufSerializer}
# Thrift:对 TBase 族作为默认
- org.acme.thrift.*:
{type: kryo, kryo-type: default, class: com.twitter.chill.thrift.TBaseSerializer}
注意:上面
org.acme.thrift.*只是示意,实际需按你的类型名逐项注册或在平台层做映射。