在 GCS 上读取 Avro 文件时出现 OutOfMemoryError 异常
OutOfMemoryError exception when reading Avro files on GCS
我将大小约为 650GB 的 BigQuery 数据集导出到 GCS 上的 Avro 文件和 运行 数据流程序来处理这些 Avro 文件。但是,即使只处理一个大小约为1.31GB的Avro文件,也会遇到OutOfMemoryError异常。
我收到以下错误消息,似乎异常源于 AvroIO 和 Avro 库:
Exception in thread "main" java.lang.OutOfMemoryError: GC overhead limit exceeded
at org.apache.avro.io.BinaryDecoder.readString(BinaryDecoder.java:260)
at org.apache.avro.io.ValidatingDecoder.readString(ValidatingDecoder.java:107)
at org.apache.avro.generic.GenericDatumReader.readString(GenericDatumReader.java:348)
at org.apache.avro.generic.GenericDatumReader.readString(GenericDatumReader.java:341)
at org.apache.avro.generic.GenericDatumReader.read(GenericDatumReader.java:154)
at org.apache.avro.generic.GenericDatumReader.read(GenericDatumReader.java:152)
at org.apache.avro.generic.GenericDatumReader.readRecord(GenericDatumReader.java:177)
at org.apache.avro.generic.GenericDatumReader.read(GenericDatumReader.java:148)
at org.apache.avro.generic.GenericDatumReader.read(GenericDatumReader.java:139)
at org.apache.avro.file.DataFileStream.next(DataFileStream.java:233)
at org.apache.avro.file.DataFileStream.next(DataFileStream.java:220)
at com.google.cloud.dataflow.sdk.runners.worker.AvroReader$AvroFileIterator.next(AvroReader.java:143)
at com.google.cloud.dataflow.sdk.runners.worker.AvroReader$AvroFileIterator.next(AvroReader.java:113)
at com.google.cloud.dataflow.sdk.util.ReaderUtils.readElemsFromReader(ReaderUtils.java:37)
at com.google.cloud.dataflow.sdk.io.AvroIO.evaluateReadHelper(AvroIO.java:638)
at com.google.cloud.dataflow.sdk.io.AvroIO.access[=10=]0(AvroIO.java:118)
at com.google.cloud.dataflow.sdk.io.AvroIO$Read$Bound.evaluate(AvroIO.java:294)
at com.google.cloud.dataflow.sdk.io.AvroIO$Read$Bound.evaluate(AvroIO.java:290)
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 com.htc.studio.bdi.dataflow.ActTranGenerator.main(ActTranGenerator.java:224)
对此异常有什么建议吗?
谢谢!
您正在使用 DirectPipelineRunner,它在您的本地计算机上 运行ning。这种模式 运行 完全在内存中,最适合用于测试或开发小型数据集。直接管道执行可能需要在内存中保留多个数据副本(取决于您的具体算法),因此我不建议将它用于大文件。相反,通过 Dataflow 服务将 --运行ner=BlockingDataflowPipelineRunner 指定为 运行。
此信息与您的情况没有直接关系,但可能对其他在使用 DataflowPipelineRunner 或 BlockingDataflowPipelineRunner 时遇到 OOM 的人有所帮助:
OutOfMemory 异常很难诊断,因为:
(1) 内存 运行 耗尽的位置可能不是消耗大量内存的位置。
(2) 由于 Dataflow 优化管道的方式,来自管道不同逻辑组件的 ParDos 可能会在同一个 JVM 中一起执行。
因此,您可能需要在工作日志中查找位于同一位置的 DoFn,以确定哪个 DoFn 实际上占用了所有内存。
OOM 的一个常见原因是使用 DoFn 处理 KV>,试图将所有 V 保存在内存中(例如在集合中)。这不会扩展到可能有很多值具有相同键的情况。
如果没有算法问题,您只需要内存多一点的工作人员,您可以调整 VM 实例类型,例如:
--workerMachineType=n1-standard-4
我将大小约为 650GB 的 BigQuery 数据集导出到 GCS 上的 Avro 文件和 运行 数据流程序来处理这些 Avro 文件。但是,即使只处理一个大小约为1.31GB的Avro文件,也会遇到OutOfMemoryError异常。
我收到以下错误消息,似乎异常源于 AvroIO 和 Avro 库:
Exception in thread "main" java.lang.OutOfMemoryError: GC overhead limit exceeded
at org.apache.avro.io.BinaryDecoder.readString(BinaryDecoder.java:260)
at org.apache.avro.io.ValidatingDecoder.readString(ValidatingDecoder.java:107)
at org.apache.avro.generic.GenericDatumReader.readString(GenericDatumReader.java:348)
at org.apache.avro.generic.GenericDatumReader.readString(GenericDatumReader.java:341)
at org.apache.avro.generic.GenericDatumReader.read(GenericDatumReader.java:154)
at org.apache.avro.generic.GenericDatumReader.read(GenericDatumReader.java:152)
at org.apache.avro.generic.GenericDatumReader.readRecord(GenericDatumReader.java:177)
at org.apache.avro.generic.GenericDatumReader.read(GenericDatumReader.java:148)
at org.apache.avro.generic.GenericDatumReader.read(GenericDatumReader.java:139)
at org.apache.avro.file.DataFileStream.next(DataFileStream.java:233)
at org.apache.avro.file.DataFileStream.next(DataFileStream.java:220)
at com.google.cloud.dataflow.sdk.runners.worker.AvroReader$AvroFileIterator.next(AvroReader.java:143)
at com.google.cloud.dataflow.sdk.runners.worker.AvroReader$AvroFileIterator.next(AvroReader.java:113)
at com.google.cloud.dataflow.sdk.util.ReaderUtils.readElemsFromReader(ReaderUtils.java:37)
at com.google.cloud.dataflow.sdk.io.AvroIO.evaluateReadHelper(AvroIO.java:638)
at com.google.cloud.dataflow.sdk.io.AvroIO.access[=10=]0(AvroIO.java:118)
at com.google.cloud.dataflow.sdk.io.AvroIO$Read$Bound.evaluate(AvroIO.java:294)
at com.google.cloud.dataflow.sdk.io.AvroIO$Read$Bound.evaluate(AvroIO.java:290)
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 com.htc.studio.bdi.dataflow.ActTranGenerator.main(ActTranGenerator.java:224)
对此异常有什么建议吗?
谢谢!
您正在使用 DirectPipelineRunner,它在您的本地计算机上 运行ning。这种模式 运行 完全在内存中,最适合用于测试或开发小型数据集。直接管道执行可能需要在内存中保留多个数据副本(取决于您的具体算法),因此我不建议将它用于大文件。相反,通过 Dataflow 服务将 --运行ner=BlockingDataflowPipelineRunner 指定为 运行。
此信息与您的情况没有直接关系,但可能对其他在使用 DataflowPipelineRunner 或 BlockingDataflowPipelineRunner 时遇到 OOM 的人有所帮助:
OutOfMemory 异常很难诊断,因为: (1) 内存 运行 耗尽的位置可能不是消耗大量内存的位置。 (2) 由于 Dataflow 优化管道的方式,来自管道不同逻辑组件的 ParDos 可能会在同一个 JVM 中一起执行。 因此,您可能需要在工作日志中查找位于同一位置的 DoFn,以确定哪个 DoFn 实际上占用了所有内存。
OOM 的一个常见原因是使用 DoFn 处理 KV>,试图将所有 V 保存在内存中(例如在集合中)。这不会扩展到可能有很多值具有相同键的情况。
如果没有算法问题,您只需要内存多一点的工作人员,您可以调整 VM 实例类型,例如: --workerMachineType=n1-standard-4