Kryo序列化问题

问题一:

背景:使用pt文件生成的java

报错信息:

尝试序列化或反序列化 Protos.AdvertChain 对象时,Flink 使用的 Kryo 序列化器遇到了一个未注册的类 ID。Kryo 是一种高效的 Java 序列化库,默认情况下它不会自动注册所有的类。如果你的应用程序中使用了某些特定的类

解决办法:

  1. 找到所有需要注册的类:检查你的 Protobuf 定义文件,并找出所有可能包含在 Protos.AdvertChain 或者其他相关对象中的消息类型。
  2. 注册这些类到 Kryo:在 Flink 的配置环境中添加对这些类的支持
        // 不可变集合等特殊类型,注册对应的序列化器
        try {
            //注册 Protobuf 类型的序列化器
            env.getConfig().registerTypeWithKryoSerializer(Protos.FlowrateHumanProperty.class, ProtobufSerializer.class);
            env.getConfig().registerTypeWithKryoSerializer(Protos.AdvertPlaySnap.class, ProtobufSerializer.class);
            env.getConfig().registerTypeWithKryoSerializer(Protos.AdvertChain.class, ProtobufSerializer.class);
            // 注册 UnmodifiableCollection 序列化器
            Class<?> unmodColl = Class.forName("java.util.Collections$UnmodifiableCollection");
            env.getConfig().addDefaultKryoSerializer(unmodColl, UnmodifiableCollectionsSerializer.class);

            // 注册 UnmodifiableList 序列化器
            Class<?> unmodList = Class.forName("java.util.Collections$UnmodifiableList");
            env.getConfig().addDefaultKryoSerializer(unmodList, UnmodifiableCollectionsSerializer.class);

            // 注册 UnmodifiableSet 序列化器
            Class<?> unmodSet = Class.forName("java.util.Collections$UnmodifiableSet");
            env.getConfig().addDefaultKryoSerializer(unmodSet, UnmodifiableCollectionsSerializer.class);

            // 注册 UnmodifiableMap 序列化器
            Class<?> unmodMap = Class.forName("java.util.Collections$UnmodifiableMap");
            env.getConfig().addDefaultKryoSerializer(unmodMap, UnmodifiableCollectionsSerializer.class);
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }

问题二:

报错:不可序列化

Exception in thread "main" org.apache.flink.api.common.InvalidProgramException: The implementation of the KeySelector is not serializable. The implementation accesses fields of its enclosing class, which is a common reason for non-serializability. A common solution is to make the function a proper (non-inner) class, or a static inner class.
	at org.apache.flink.api.java.ClosureCleaner.clean(ClosureCleaner.java:164)
	at org.apache.flink.api.java.ClosureCleaner.clean(ClosureCleaner.java:69)
	at org.apache.flink.streaming.api.environment.StreamExecutionEnvironment.clean(StreamExecutionEnvironment.java:2317)
	at org.apache.flink.streaming.api.datastream.DataStream.clean(DataStream.java:202)
	at org.apache.flink.streaming.api.datastream.DataStream.keyBy(DataStream.java:292)
	at com.xzl.bigdata.realtime.dwd.advertis.tpAdvSnapV2.app.DwdTpAdvSnpV2.getKeyBySnpv2(DwdTpAdvSnpV2.java:192)
	at com.xzl.bigdata.realtime.dwd.advertis.tpAdvSnapV2.app.DwdTpAdvSnpV2.handle(DwdTpAdvSnpV2.java:63)
	at com.xzl.bigdata.realtime.common.app.BaseAPP_test.start(BaseAPP_test.java:53)
	at com.xzl.bigdata.realtime.dwd.advertis.tpAdvSnapV2.app.DwdTpAdvSnpV2.main(DwdTpAdvSnpV2.java:45)
Caused by: java.io.NotSerializableException: com.xzl.bigdata.realtime.dwd.advertis.tpAdvSnapV2.app.DwdTpAdvSnpV2

原因

  1. 避免了对外部实例的隐式引用:在原来的实现中,匿名内部类(或非静态内部类)会隐式地持有对外部类实例的引用。如果外部类包含未实现 Serializable 接口的成员变量,那么整个对象图就无法序列化。通过将其改为静态内部类或者独立类,你消除了这种隐式的对外部类实例的引用,从而确保了 KeySelector 自身是可序列化的。
  2. 简化了依赖关系:静态内部类不持有对外部类实例的引用,因此它们不会试图序列化外部类的状态。这使得 Flink 能够更容易地将函数发送到集群中的各个节点执行。
  3. Flink 需要将函数(如 KeySelector、MapFunction 等)发送到集群中的各个节点执行,因此这些函数必须是可序列化的。当你的 KeySelector 实现类内部访问了外部类的非静态字段或方法时,会导致该实现类不可序列化,因为默认情况下,它会隐式地持有对外部类实例的引用。

解决:

  1. 实现Serializable 接口
  2. 方法改为静态
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值