Google cloud dataflow 如何修复无法序列化我的DoFn的数据流?

Google cloud dataflow 如何修复无法序列化我的DoFn的数据流?,google-cloud-dataflow,Google Cloud Dataflow,当我运行我的数据流管道时,我得到下面的异常,抱怨我的DoFn无法序列化。我该如何解决这个问题 以下是堆栈跟踪: Caused by: java.lang.IllegalArgumentException: unable to serialize contrail.dataflow.AvroMRTransforms$AvroReducerDoFn@bba0fc2 at com.google.cloud.dataflow.sdk.util.SerializableUtils.serializ

当我运行我的数据流管道时,我得到下面的异常,抱怨我的DoFn无法序列化。我该如何解决这个问题

以下是堆栈跟踪:

Caused by: java.lang.IllegalArgumentException: unable to serialize contrail.dataflow.AvroMRTransforms$AvroReducerDoFn@bba0fc2
    at com.google.cloud.dataflow.sdk.util.SerializableUtils.serializeToByteArray(SerializableUtils.java:51)
    at com.google.cloud.dataflow.sdk.util.SerializableUtils.ensureSerializable(SerializableUtils.java:81)
    at com.google.cloud.dataflow.sdk.runners.DirectPipelineRunner$Evaluator.ensureSerializable(DirectPipelineRunner.java:784)
    at com.google.cloud.dataflow.sdk.transforms.ParDo.evaluateHelper(ParDo.java:1025)
    at com.google.cloud.dataflow.sdk.transforms.ParDo.evaluateSingleHelper(ParDo.java:963)
    at com.google.cloud.dataflow.sdk.transforms.ParDo.access$000(ParDo.java:441)
    at com.google.cloud.dataflow.sdk.transforms.ParDo$1.evaluate(ParDo.java:951)
    at com.google.cloud.dataflow.sdk.transforms.ParDo$1.evaluate(ParDo.java:946)
    at com.google.cloud.dataflow.sdk.runners.DirectPipelineRunner$Evaluator.visitTransform(DirectPipelineRunner.java:611)
    at com.google.cloud.dataflow.sdk.runners.TransformTreeNode.visit(TransformTreeNode.java:200)
    at com.google.cloud.dataflow.sdk.runners.TransformTreeNode.visit(TransformTreeNode.java:196)
    at com.google.cloud.dataflow.sdk.runners.TransformHierarchy.visit(TransformHierarchy.java:109)
    at com.google.cloud.dataflow.sdk.Pipeline.traverseTopologically(Pipeline.java:204)
    at com.google.cloud.dataflow.sdk.runners.DirectPipelineRunner$Evaluator.run(DirectPipelineRunner.java:584)
    at com.google.cloud.dataflow.sdk.runners.DirectPipelineRunner.run(DirectPipelineRunner.java:328)
    at com.google.cloud.dataflow.sdk.runners.DirectPipelineRunner.run(DirectPipelineRunner.java:70)
    at com.google.cloud.dataflow.sdk.Pipeline.run(Pipeline.java:145)
    at contrail.stages.DataflowStage.stageMain(DataflowStage.java:51)
    at contrail.stages.NonMRStage.execute(NonMRStage.java:130)
    at contrail.stages.NonMRStage.run(NonMRStage.java:157)
    at org.apache.hadoop.util.ToolRunner.run(ToolRunner.java:65)
    at contrail.stages.ValidateGraphDataflow.main(ValidateGraphDataflow.java:139)
    ... 6 more
Caused by: java.io.NotSerializableException: org.apache.hadoop.mapred.JobConf
    at java.io.ObjectOutputStream.writeObject0(ObjectOutputStream.java:1183)
    at java.io.ObjectOutputStream.defaultWriteFields(ObjectOutputStream.java:1547)
    at java.io.ObjectOutputStream.writeSerialData(ObjectOutputStream.java:1508)
    at java.io.ObjectOutputStream.writeOrdinaryObject(ObjectOutputStream.java:1431)
    at java.io.ObjectOutputStream.writeObject0(ObjectOutputStream.java:1177)
    at java.io.ObjectOutputStream.writeObject(ObjectOutputStream.java:347)
    at com.google.cloud.dataflow.sdk.util.SerializableUtils.serializeToByteArray(SerializableUtils.java:47)
    ... 27 more

如果滚动堆栈跟踪,其中一个原因会明确标识不可序列化的数据

Caused by: java.io.NotSerializableException: org.apache.hadoop.mapred.JobConf
问题是我的DoFn在构造函数中获取了一个JobConf实例,并将其存储在一个实例变量中。我假设JobConf是可序列化的,但事实证明不是

为了解决这个问题,我做了以下工作

  • 我将JobConf成员变量标记为transient,这样它就不会被序列化
  • 我创建了一个类型为byte[]的单独变量来存储JobConf的序列化版本
  • 在我的构造函数中,我将JobConf序列化为一个字节[],并将其存储在一个实例变量中
  • 我重写了startBundle并从字节[]反序列化了JobConf

这里有一个关于我丈夫的建议。

来补充杰里米所说的


可序列化问题的另一个常见原因是在非静态上下文中使用匿名DoFn。匿名内部类有一个指向封闭类的隐式指针,这将导致它也被序列化

这个解决方案与我找到的非常接近。我的问题是通过DoFn函数序列化模式(avro)。我发现的方法是将模式字符串传递给函数类的构造函数,然后在processElement()方法中进行解析。这种方法会对要转换的PCollection的每个条目进行模式反序列化,从而降低性能。我想知道您的解决方案的行为是否与此相同,或者在startBound()方法中看到您这样做后,它会进行反序列化/解析。执行From java doc时未指定它。谢谢您如何实现
serializeJobConf()
方法?好的。。。这没有任何意义,但事实上,当我将DoFn从匿名更改为真实类时,问题就消失了。在我的例子中,我使用Kotlin而不是java。