Scala Flink Kafka源时间戳提取器的类加载

Scala Flink Kafka源时间戳提取器的类加载,scala,classpath,apache-flink,flink-streaming,Scala,Classpath,Apache Flink,Flink Streaming,我正在尝试将Flink作业部署到基于Flink:1.4.1-hadoop27-scala_2.11-alpine图像的集群。作业正在使用卡夫卡连接器源(flink-connector-Kafka-0.11),我正在尝试为其分配时间戳和水印。我的代码与中的Scala示例非常相似。但是有了FlinkKafkaConsumer011 val myConsumer = new FlinkKafkaConsumer08[String]("topic", new SimpleStringSchema(),

我正在尝试将Flink作业部署到基于Flink:1.4.1-hadoop27-scala_2.11-alpine图像的集群。作业正在使用卡夫卡连接器源(flink-connector-Kafka-0.11),我正在尝试为其分配时间戳和水印。我的代码与中的Scala示例非常相似。但是有了FlinkKafkaConsumer011

val myConsumer = new FlinkKafkaConsumer08[String]("topic", new SimpleStringSchema(), properties)
myConsumer.assignTimestampsAndWatermarks(new CustomWatermarkEmitter())
从IDE本地运行时,这非常有效。但是,在集群环境中,我得到以下错误:

java.lang.ClassNotFoundException: com.my.organization.CustomWatermarkEmitter
at java.net.URLClassLoader.findClass(URLClassLoader.java:381)
at java.lang.ClassLoader.loadClass(ClassLoader.java:424)
at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:335)
at java.lang.ClassLoader.loadClass(ClassLoader.java:357)
at java.lang.Class.forName0(Native Method)
at java.lang.Class.forName(Class.java:348)
at org.apache.flink.util.InstantiationUtil$ClassLoaderObjectInputStream.resolveClass(InstantiationUtil.java:73)
at java.io.ObjectInputStream.readNonProxyDesc(ObjectInputStream.java:1863)
at java.io.ObjectInputStream.readClassDesc(ObjectInputStream.java:1746)
at java.io.ObjectInputStream.readOrdinaryObject(ObjectInputStream.java:2037)
at java.io.ObjectInputStream.readObject0(ObjectInputStream.java:1568)
at java.io.ObjectInputStream.readObject(ObjectInputStream.java:428)
at org.apache.flink.util.InstantiationUtil.deserializeObject(InstantiationUtil.java:393)
at org.apache.flink.util.InstantiationUtil.deserializeObject(InstantiationUtil.java:380)
at org.apache.flink.util.InstantiationUtil.deserializeObject(InstantiationUtil.java:368)
at org.apache.flink.util.SerializedValue.deserializeValue(SerializedValue.java:58)
at org.apache.flink.streaming.connectors.kafka.internals.AbstractFetcher.createPartitionStateHolders(AbstractFetcher.java:521)
at org.apache.flink.streaming.connectors.kafka.internals.AbstractFetcher.<init>(AbstractFetcher.java:167)
at org.apache.flink.streaming.connectors.kafka.internal.Kafka09Fetcher.<init>(Kafka09Fetcher.java:89)
at org.apache.flink.streaming.connectors.kafka.internal.Kafka010Fetcher.<init>(Kafka010Fetcher.java:62)
at org.apache.flink.streaming.connectors.kafka.FlinkKafkaConsumer010.createFetcher(FlinkKafkaConsumer010.java:203)
at org.apache.flink.streaming.connectors.kafka.FlinkKafkaConsumerBase.run(FlinkKafkaConsumerBase.java:564)
at org.apache.flink.streaming.api.operators.StreamSource.run(StreamSource.java:86)
at org.apache.flink.streaming.api.operators.StreamSource.run(StreamSource.java:55)
at org.apache.flink.streaming.runtime.tasks.SourceStreamTask.run(SourceStreamTask.java:94)
at org.apache.flink.streaming.runtime.tasks.StreamTask.invoke(StreamTask.java:264)
at org.apache.flink.runtime.taskmanager.Task.run(Task.java:718)
at java.lang.Thread.run(Thread.java:748)
java.lang.ClassNotFoundException:com.my.organization.CustomWatermarkEmitter
位于java.net.URLClassLoader.findClass(URLClassLoader.java:381)
位于java.lang.ClassLoader.loadClass(ClassLoader.java:424)
位于sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:335)
位于java.lang.ClassLoader.loadClass(ClassLoader.java:357)
位于java.lang.Class.forName0(本机方法)
位于java.lang.Class.forName(Class.java:348)
位于org.apache.flink.util.InstantiationUtil$ClassLoaderObjectInputStream.resolveClass(InstantiationUtil.java:73)
位于java.io.ObjectInputStream.readNonProxyDesc(ObjectInputStream.java:1863)
位于java.io.ObjectInputStream.readClassDesc(ObjectInputStream.java:1746)
位于java.io.ObjectInputStream.readOrdinaryObject(ObjectInputStream.java:2037)
位于java.io.ObjectInputStream.readObject0(ObjectInputStream.java:1568)
位于java.io.ObjectInputStream.readObject(ObjectInputStream.java:428)
位于org.apache.flink.util.InstantiationUtil.deserializeObject(InstantiationUtil.java:393)
位于org.apache.flink.util.InstantiationUtil.deserializeObject(InstantiationUtil.java:380)
位于org.apache.flink.util.InstantiationUtil.deserializeObject(InstantiationUtil.java:368)
位于org.apache.flink.util.SerializedValue.deserializeValue(SerializedValue.java:58)
位于org.apache.flink.streaming.connectors.kafka.internals.AbstractFetcher.createPartitionStateHolders(AbstractFetcher.java:521)
位于org.apache.flink.streaming.connectors.kafka.internals.AbstractFetcher.(AbstractFetcher.java:167)
位于org.apache.flink.streaming.connectors.kafka.internal.Kafka09Fetcher.(Kafka09Fetcher.java:89)
位于org.apache.flink.streaming.connectors.kafka.internal.Kafka010Fetcher.(Kafka010Fetcher.java:62)
在org.apache.flink.streaming.connectors.kafka.flinkkaConsumer010.createFetcher上(flinkkafsumer010.java:203)
在org.apache.flink.streaming.connectors.kafka.flinkkafsumerbase.run(flinkkafsumerbase.java:564)
位于org.apache.flink.streaming.api.operators.StreamSource.run(StreamSource.java:86)
位于org.apache.flink.streaming.api.operators.StreamSource.run(StreamSource.java:55)
位于org.apache.flink.streaming.runtime.tasks.SourceStreamTask.run(SourceStreamTask.java:94)
位于org.apache.flink.streaming.runtime.tasks.StreamTask.invoke(StreamTask.java:264)
位于org.apache.flink.runtime.taskmanager.Task.run(Task.java:718)
运行(Thread.java:748)
我正在将我的工作构建为一个胖罐子,我已经验证它包含这个类。 仅当CustomWatermarkEmitter类位于/opt/flink/lib/文件夹中时,文档中的示例才起作用吗?

这就是我解决问题的方法。但是必须单独构建这个类,并将它放在/opt/flink/lib中,这会使我的构建过程变得非常复杂,所以我想知道这是应该解决这个问题的方法,还是有其他方法可以解决这个问题

例如,本节提示必须手动为UserCodeClassLoader提供一些源?包括提供的卡夫卡资料来源

就我在org.apache.flink.streaming.connectors.kafka.internals.AbstractFetcher中所见,它似乎在内部使用了“userCodeClassLoader”:

            case PERIODIC_WATERMARKS: {
            for (Map.Entry<KafkaTopicPartition, Long> partitionEntry : partitionsToInitialOffsets.entrySet()) {
                KPH kafkaHandle = createKafkaPartitionHandle(partitionEntry.getKey());

                AssignerWithPeriodicWatermarks<T> assignerInstance =
                        watermarksPeriodic.deserializeValue(userCodeClassLoader);

                KafkaTopicPartitionStateWithPeriodicWatermarks<T, KPH> partitionState =
                        new KafkaTopicPartitionStateWithPeriodicWatermarks<>(
                                partitionEntry.getKey(),
                                kafkaHandle,
                                assignerInstance);

                partitionState.setOffset(partitionEntry.getValue());

                partitionStates.add(partitionState);
            }
大小写周期性\u水印:{
对于(Map.Entry partitionEntry:partitionsToInitialOffsets.entrySet()){
KPH kafkaHandle=createKafkaPartitionHandle(partitionEntry.getKey());
具有周期性水印assignerInstance的AssignerWithPeriodicWatermarks=
反序列化值(userCodeClassLoader);
KafkatopicPartitionState带有周期性水印partitionState=
具有周期性水印的新KafkatopicPartitionState(
partitionEntry.getKey(),
卡夫卡汉德勒,
转让人身份);
partitionState.setOffset(partitionEntry.getValue());
添加(partitionState);
}
编辑:

我创建了一个简单的项目,可以在此处重新制作此问题:

为了复制,您需要docker和docker compose

只要做:

  • git克隆
  • cd flink kafka类路径问题/docker
  • docker组合构建
  • 码头工人整理
  • 在浏览器中转到localhost:8081
  • 从target/scala-2.11/flink-kafka-classpath-problem-assembly-0.1-SNAPSHOT.jar提交包含的jar文件

  • 这将导致异常java.lang.ClassNotFoundException:se.ragnarsson.lage.MyTimestampExtractor我想您可能偶然发现了Flink 1.4.1中引入的错误:


    它将很快在1.4.2中修复。您可以尝试在1.4.2中进行测试。rc2:

    您是否能够将实际代码的净化版本放入?我已经成功地完成了这项工作,没有任何问题(Flink 1.4,Kafka 0.11连接器,基于源代码的时间戳),因此问题可能很微妙。我将尝试准备一个最小的示例。您是否部署在docker容器中?我在Kubernetes下使用一个taskmanager容器和一个jobmanager运行它,类似于:@JoshuaDeWald我用一个示例项目编辑了原始帖子,该项目再现了此问题。很好!基于这里的所有内容,看起来就像你偶然发现了一个bug,卡夫卡连接器可能正在使用全局Flink类加载器(本质上,仅限父类),而不是它自己从中加载的用户类加载器