EMR Sparkで、データフレームを介してRDD[String]
をS3に書き込みます。
rddString
.toDF()
.coalesce(16)
.write
.option("compression", "gzip")
.mode(SaveMode.Overwrite)
.json(s"s3n://my-bucket/some/new/path")
保存モードはOverwrite
で、s3n://my-bucket/some/new/path
はまだ存在しません。
私は一貫してIOException: File already exists
を取得します:
org.Apache.spark.SparkException: Job aborted due to stage failure: Task 15 in stage 55.0 failed 4 times, most recent failure: Lost task 15.3 in stage 55.0 (TID 8441, ip-172-31-17-30.us-west-2.compute.internal, executor 3): org.Apache.spark.SparkException: Task failed while writing rows
at org.Apache.spark.sql.execution.datasources.FileFormatWriter$.org$Apache$spark$sql$execution$datasources$FileFormatWriter$$executeTask(FileFormatWriter.scala:270)
at org.Apache.spark.sql.execution.datasources.FileFormatWriter$$anonfun$write$1$$anonfun$apply$mcV$sp$1.apply(FileFormatWriter.scala:189)
at org.Apache.spark.sql.execution.datasources.FileFormatWriter$$anonfun$write$1$$anonfun$apply$mcV$sp$1.apply(FileFormatWriter.scala:188)
at org.Apache.spark.scheduler.ResultTask.runTask(ResultTask.scala:87)
at org.Apache.spark.scheduler.Task.run(Task.scala:108)
at org.Apache.spark.executor.Executor$TaskRunner.run(Executor.scala:338)
at Java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.Java:1149)
at Java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.Java:624)
at Java.lang.Thread.run(Thread.Java:748)
Caused by: Java.io.IOException: File already exists:s3n://my-bucket/some/new/path/part-00015-03a0c001-fc99-4055-9be5-68a1fb0cf6d3-c000.json.gz
at com.Amazon.ws.emr.hadoop.fs.s3n.S3NativeFileSystem.create(S3NativeFileSystem.Java:625)
at org.Apache.hadoop.fs.FileSystem.create(FileSystem.Java:932)
at org.Apache.hadoop.fs.FileSystem.create(FileSystem.Java:913)
at org.Apache.hadoop.fs.FileSystem.create(FileSystem.Java:810)
at com.Amazon.ws.emr.hadoop.fs.EmrFileSystem.create(EmrFileSystem.Java:176)
at org.Apache.spark.sql.execution.datasources.CodecStreams$.createOutputStream(CodecStreams.scala:81)
at org.Apache.spark.sql.execution.datasources.CodecStreams$.createOutputStreamWriter(CodecStreams.scala:92)
at org.Apache.spark.sql.execution.datasources.json.JsonOutputWriter.<init>(JsonFileFormat.scala:140)
at org.Apache.spark.sql.execution.datasources.json.JsonFileFormat$$anon$1.newInstance(JsonFileFormat.scala:80)
at org.Apache.spark.sql.execution.datasources.FileFormatWriter$SingleDirectoryWriteTask.newOutputWriter(FileFormatWriter.scala:303)
at org.Apache.spark.sql.execution.datasources.FileFormatWriter$SingleDirectoryWriteTask.execute(FileFormatWriter.scala:312)
at org.Apache.spark.sql.execution.datasources.FileFormatWriter$$anonfun$org$Apache$spark$sql$execution$datasources$FileFormatWriter$$executeTask$3.apply(FileFormatWriter.scala:256)
at org.Apache.spark.sql.execution.datasources.FileFormatWriter$$anonfun$org$Apache$spark$sql$execution$datasources$FileFormatWriter$$executeTask$3.apply(FileFormatWriter.scala:254)
at org.Apache.spark.util.Utils$.tryWithSafeFinallyAndFailureCallbacks(Utils.scala:1371)
at org.Apache.spark.sql.execution.datasources.FileFormatWriter$.org$Apache$spark$sql$execution$datasources$FileFormatWriter$$executeTask(FileFormatWriter.scala:259)
... 8 more
Spark v2.2.1、EMR v5.12.0
例外がスローされる前に、ファイルは宛先に書き込まれます。しかし、それらが完全であるかどうかはわかりません。
GlueジョブでEMRを実行したときに、同様の問題に遭遇しました。そして一言で言えば、それは通常あなたの仕事を失敗させる本当の根本的な原因ではありません。 sparkタスクは他の理由で失敗する可能性があります。元の失敗を再試行した後、最終的にこの「IOException:ファイルはすでに存在します」をスローします。
したがって、真の根本原因を見つけて解決すれば、それもなくなります。
私の場合、報告されたエラーはCloudWatchErrorLogsで以下のようになりました。
: org.Apache.spark.SparkException: Job aborted.
at ...
at org.Apache.spark.executor.Executor$TaskRunner.run(Executor.scala:338)
at Java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.Java:1149)
at Java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.Java:624)
at Java.lang.Thread.run(Thread.Java:748)
Caused by: Java.io.IOException: File already exists:s3://personal-tests/xdqian/zappos_triplet_loss/output_cache_test/part-00003-8eaa7c78-e227-4476-b96d-4300e7350bc7-c000.csv
手がかりはありませんが、ログを調べたところ、次のような例外が見つかりました。
18/12/05 06:14:15 ERROR Utils: Aborting task
org.Apache.spark.api.python.PythonException: Traceback (most recent call last):
File "/mnt/yarn/usercache/root/appcache/application_1543990079218_0001/container_1543990079218_0001_01_000101/pyspark.Zip/pyspark/worker.py", line 177, in main
process()
File "/mnt/yarn/usercache/root/appcache/application_1543990079218_0001/container_1543990079218_0001_01_000101/pyspark.Zip/pyspark/worker.py", line 172, in process
serializer.dump_stream(func(split_index, iterator), outfile)
File "/mnt/yarn/usercache/root/appcache/application_1543990079218_0001/container_1543990079218_0001_01_000101/pyspark.Zip/pyspark/serializers.py", line 268, in dump_stream
vs = list(itertools.islice(iterator, batch))
File "/mnt/yarn/usercache/root/appcache/application_1543990079218_0001/container_1543990079218_0001_01_000001/GoldenGardensGluePythonScripts.Zip/golden_gardens_glue_python_scripts/job.py", line 62, in <lambda>
TypeError: 'NoneType' object has no attribute '__getitem__'
最後に、このNoneTypeエラーを解決した後、「ファイルは既に存在します」という例外はなくなりました。 「ファイルはすでに存在します」エラーは常にタスクの失敗が原因であり、他の問題(私の場合はNoneType)が原因で再試行することを他の資料で読みました(申し訳ありませんが、追跡できませんでした)。エグゼキュータタスクがファイルを作成し、データを行ごとに出力することを期待しています。ファイルが最初の33行でまだ存在している間に、NoneTypeエラーが原因で、たとえば行34で失敗し、中止される場合があります。失敗したタスクは4回再試行されると言われています。タスクが再試行されると、最初に実行された前の実行によって既存のファイルが検出されます。したがって、根本原因は実際にはLoggsとしてログに記録され、エラーログには「ファイルはすでに存在します」という例外があります。これは、ジョブが終了する前の最後の例外であるためです。また、このEdgeの場合の制御フラグではなく、最初にチェックを行うだけなので、上書きモードはここでは役に立ちません。
ファイルスキームをs3n
からs3a
に変更した後、エラーは発生しなくなりました。