为你的 Flink 程序注册自定义序列化器

如果在 Flink 程序中使用了 Flink 类型序列化器无法进行序列化的用户自定义类型,Flink 会回退到通用的 Kryo 序列化器。可以使用 Kryo 注册自己的序列化器或序列化系统,比如 Google Protobuf 或 Apache Thrift。使用方法是在 Flink 程序中的 ExecutionConfig 注册类类型以及序列化器。

  1. final ExecutionEnvironment env = ExecutionEnvironment.getExecutionEnvironment();
  2. // 为类型注册序列化器类
  3. env.getConfig().registerTypeWithKryoSerializer(MyCustomType.class, MyCustomSerializer.class);
  4. // 为类型注册序列化器实例
  5. MySerializer mySerializer = new MySerializer();
  6. env.getConfig().registerTypeWithKryoSerializer(MyCustomType.class, mySerializer);

需要确保你的自定义序列化器继承了 Kryo 的序列化器类。对于 Google Protobuf 或 Apache Thrift,这一点已经为你做好了:

  1. final ExecutionEnvironment env = ExecutionEnvironment.getExecutionEnvironment();
  2. // 使用 Kryo 注册 Google Protobuf 序列化器
  3. env.getConfig().registerTypeWithKryoSerializer(MyCustomType.class, ProtobufSerializer.class);
  4. // 注册 Apache Thrift 序列化器为标准序列化器
  5. // TBaseSerializer 需要初始化为默认的 kryo 序列化器
  6. env.getConfig().addDefaultKryoSerializer(MyCustomType.class, TBaseSerializer.class);

为了使上面的例子正常工作,需要在 Maven 项目文件中(pom.xml)包含必要的依赖。为 Apache Thrift 添加以下依赖:

  1. <dependency>
  2. <groupId>com.twitter</groupId>
  3. <artifactId>chill-thrift</artifactId>
  4. <version>0.7.6</version>
  5. <!-- exclusions for dependency conversion -->
  6. <exclusions>
  7. <exclusion>
  8. <groupId>com.esotericsoftware.kryo</groupId>
  9. <artifactId>kryo</artifactId>
  10. </exclusion>
  11. </exclusions>
  12. </dependency>
  13. <!-- libthrift is required by chill-thrift -->
  14. <dependency>
  15. <groupId>org.apache.thrift</groupId>
  16. <artifactId>libthrift</artifactId>
  17. <version>0.11.0</version>
  18. <exclusions>
  19. <exclusion>
  20. <groupId>javax.servlet</groupId>
  21. <artifactId>servlet-api</artifactId>
  22. </exclusion>
  23. <exclusion>
  24. <groupId>org.apache.httpcomponents</groupId>
  25. <artifactId>httpclient</artifactId>
  26. </exclusion>
  27. </exclusions>
  28. </dependency>

对于 Google Protobuf 需要添加以下 Maven 依赖:

  1. <dependency>
  2. <groupId>com.twitter</groupId>
  3. <artifactId>chill-protobuf</artifactId>
  4. <version>0.7.6</version>
  5. <!-- exclusions for dependency conversion -->
  6. <exclusions>
  7. <exclusion>
  8. <groupId>com.esotericsoftware.kryo</groupId>
  9. <artifactId>kryo</artifactId>
  10. </exclusion>
  11. </exclusions>
  12. </dependency>
  13. <!-- We need protobuf for chill-protobuf -->
  14. <dependency>
  15. <groupId>com.google.protobuf</groupId>
  16. <artifactId>protobuf-java</artifactId>
  17. <version>3.7.0</version>
  18. </dependency>

请根据需要调整两个依赖库的版本。

使用 Kryo JavaSerializer 的问题

如果你为自定义类型注册 Kryo 的 JavaSerializer,即使你提交的 jar 中包含了自定义类型的类,也可能会遇到 ClassNotFoundException 异常。这是由于 Kryo JavaSerializer 的一个已知问题,它可能使用了错误的类加载器。

在这种情况下,你应该使用 org.apache.flink.api.java.typeutils.runtime.kryo.JavaSerializer 来解决这个问题。这个类是在 Flink 中对 JavaSerializer 的重新实现,可以确保使用用户代码的类加载器。

更多细节可以参考 FLINK-6025