【ITニュース解説】AWS Glue Concurrent Execution: What Happens When Multiple Jobs Write to the Same S3 Location?
2026年11月04日に「Dev.to」が公開したITニュース「AWS Glue Concurrent Execution: What Happens When Multiple Jobs Write to the Same S3 Location?」について初心者にもわかりやすく解説しています。
ITニュース概要
AWS Glueジョブが同時に同じS3へ書き込むと、データ欠損や重複が起こる。S3は自動的に排他制御しないため、個別の作業場所、実行順序制御、またはIcebergのようなトランザクション対応技術で書き込みを調整し、データ衝突を防ぐ設計が重要だ。
ITニュース解説
AWS GlueとAmazon S3を組み合わせてデータパイプラインを構築する際、複数のGlueジョブが同じS3の出力場所に同時にデータを書き込もうとすると、意図しない問題が発生する可能性がある。個々のジョブを単独で実行する際には問題なく動作するにもかかわらず、本番環境で複数のジョブがほぼ同時に起動し、同じS3の場所に書き込みを行うと、最終的なデータが欠落したり、重複したり、全体として不正確になったりすることがある。これは、Amazon S3がオブジェクト単位での「書き込み後の読み込み整合性」を提供する一方で、S3のプレフィックス(特定のフォルダ構造)全体に対するトランザクションやロックの機能を持っていないためだ。S3は、複数のGlueジョブが連携して動作することを認識せず、それぞれのジョブが独立した書き込み操作を実行してしまう。この結果、データの整合性は、書き込みモード、データのパーティション分割戦略、および出力コミットプロトコルに大きく左右される。
具体的に、両方のGlueジョブが「overwrite」(上書き)モードを使用する場合を考える。例えば、df.write.mode("overwrite").parquet(output_path)のように設定されている場合である。あるジョブがデータの書き込みを開始し、その処理中に別のジョブも同じS3の場所に書き込みを開始すると、互いの出力が干渉し合う可能性がある。それぞれのジョブが独立して書き込みやコミットを実行するため、先行するジョブの出力が後続のジョブの上書き操作によって部分的に、あるいは完全に消去されたり、予期せぬファイルの組み合わせが生じたりすることがある。その結果、個々のジョブは「成功」と報告されても、最終的なデータセットはビジネス要件を満たさない不正確なものとなり得る。overwriteモードは分散トランザクションではないため、複数のジョブが同時に同じS3プレフィックスを上書きする操作は安全ではないと認識する必要がある。
次に、「append」(追記)モードを使用する場合について説明する。df.write.mode("append").parquet(output_path)のように設定されている場合、Sparkは既存のファイルを置き換えるのではなく、新しいParquetファイルをターゲットの場所に追記していく。この方法は一見すると安全に思えるが、別の問題を引き起こす可能性がある。例えば、ジョブAが顧客C101とC102のデータを処理し、ジョブBが顧客C101とC103のデータを同時に処理し、どちらも追記モードでS3に書き込んだ場合、最終的なデータセットには顧客C101が重複して記録されてしまうことがある。S3は異なるオブジェクトとして両方のファイルを問題なく受け入れるが、ビジネス上の観点からはデータに重複が発生する。このケースからわかるように、S3への書き込みが成功したとしても、それがビジネスデータの正確性を保証するものではないという点を理解しておく必要がある。追記モードは、入力データが純粋に追加される性質のものであり、かつデータ重複のハンドリングがパイプライン設計の一部として考慮されている場合にのみ適切である。
さらに、データが「partitionBy」(パーティション分割)によって整理されている場合でも、問題は発生し得る。例えば、df.write.mode("overwrite").partitionBy("business_date").parquet(output_path)のように日付でパーティションを分割し、S3のパスがsilver/customers/business_date=YYYY-MM-DD/のようになる場合、複数のGlueジョブが同時に同じ日付パーティション(例: 2026-11-03)を対象として書き込みを行うと、やはり互いの出力に干渉する可能性が出てくる。特に、各ジョブが異なるソースデータやビジネスロジックを持っている場合、最終的なパーティションがどちらかの完全なデータセットを表さない、不完全な状態になりかねない。このようなリスクを軽減するためには、どのジョブがどのパーティションの書き込みを担当するかを明確に割り当て、「パーティションの所有権」を定義することが重要だ。しかし、データがパーティション分割されているというだけでは、複数のジョブが同じパーティションに書き込むことを防ぐことはできないため、この所有権はオーケストレーションシステムやアプリケーションロジックによって強制する必要がある。
本番環境でこの問題を特定するのは困難な場合が多い。なぜなら、Glueジョブの実行ログには両方のジョブが「成功」と表示されても、S3のデータは誤っているという状況が起こりうるからだ。問題特定にはいくつかのチェックが有効である。まず、期待されるレコード数と実際にS3に書き込まれたレコード数を比較することで、データの欠落や予期せぬ増加を検出できる。次に、ビジネスキー(例えば、顧客ID)に基づいて重複レコードが存在しないかをチェックする方法もある。また、S3のプレフィックスを直接確認し、予期せぬファイル数、複数の出力バッチ、欠落したパーティション、または不規則なファイル更新パターンがないかを検証することも有効だ。さらに、Glueジョブの実行履歴を精査し、複数のジョブが同じ出力場所を対象としていて、かつ実行時間が重複している場合は、その書き込み操作を詳しく調査すべきである。
これらの問題に対する解決策がいくつか提案されている。
一つ目の解決策は、各Glueジョブに固有の「S3ステージング場所」を与えることである。最終的な出力プレフィックスに直接書き込むのではなく、staging/customers/job_a/run_id=001/のように、ジョブごとに異なる一時的な場所にデータを書き込む。これにより、各ジョブは独立して書き込みを実行できる。その後、「制御されたパブリッシャー」と呼ばれる単一のプロセスが、ステージングされたデータを検証し、設定された競合解決ポリシーに基づいて最終的なS3の場所(例: silver/customers/)にデータを公開する。この「制御されたパブリッシャー」の存在が重要であり、単に複数のステージングディレクトリの内容を最終プレフィックスにコピーするだけでは、まだ競合解決の必要性が残る。
二つ目の解決策は、「AWS Step Functions」を活用してジョブの実行を制御することである。Step Functionsは、複数のGlueジョブの実行順序をオーケストレーションできるため、同時に書き込みが発生しないように制御できる。例えば、まず顧客データを処理するジョブを実行し、その出力を検証した後に、修正データを処理するジョブを実行するといった、順序だった処理フローを定義できる。これは、複数のジョブが同じデータセットを更新する場合や、データ品質チェックが最終公開前に完了する必要がある場合に特に効果的である。Step FunctionsのMapステートを用いて複数のジョブを並列実行する場合でも、出力場所の所有権に基づいて並行度を適切に設定することで、競合のリスクを低減できる。
三つ目の解決策は、「DynamoDB」を利用して分散ロック機構を実装することだ。EventBridgeやS3イベントなどによって、複数のパイプラインが非同期にトリガーされるような状況では、DynamoDBテーブルをロック管理に利用できる。例えば、PipelineLocksというテーブルを作成し、各GlueジョブがS3への書き込み操作を開始する前に、対象となるリソース名に対するロックの取得を試みる。DynamoDBの条件付き書き込み機能を利用し、既にロックが存在する場合は書き込みを失敗させることで、複数のジョブが同時にロックを取得することを防ぐ。ただし、本番環境での利用には、ロックの有効期限管理、安全なロック解除、失敗したジョブからの回復、および長期間実行されるジョブのためのハートビートなど、より堅牢な設計が必要となる。
四つ目の解決策は、大規模なデータレイクハウスを構築する際に有効な「Apache Iceberg」の利用である。S3に直接保存された従来のParquetファイルではテーブルレベルのトランザクションが提供されないが、Icebergはメタデータレイヤーを導入し、データセットのスナップショットとテーブルの変更履歴を管理する。これにより、アプリケーションは個々のParquetファイルを直接操作するのではなく、Icebergのテーブルメタデータを介して変更をコミットする。Icebergはアトミックなメタデータコミットとオプティミスティック並行性制御をサポートしており、複数の書き込み処理が同時に実行された場合でも、競合する変更を検出し、それに応じて再試行や競合解決ロジックを適用できる。複数のパイプラインが同じ論理テーブルを更新する場合や、信頼性の高いスナップショット管理、タイムトラベル機能、スキーマ進化などが必要な場合に、IcebergはS3プレフィックスを単なるファイルの置き場として扱うよりも、優れたトランザクションテーブルの基盤となる。
以上の解決策を踏まえ、本番環境のデータレイクでは、複数の独立したGlueジョブが同じ最終S3出力場所を直接上書きすることを避けるべきである。推奨されるアプローチとしては、EventBridgeをトリガーとしてStep Functionsで全体をオーケストレーションし、各Glueジョブはデータを処理し、それぞれ固有のステージングプレフィックスに書き込む。その後、データ品質チェックを実施し、Step Functionsが調整する「制御された公開プロセス」を通じて、Apache Icebergによって管理されるトランザクションテーブルにデータを投入する。CloudWatchで実行の失敗や処理メトリクスを監視することも重要である。Icebergが不要なワークロードであっても、ユニークなステージング場所と単一の「制御されたパブリッシャー」の利用は、各最終データセットやパーティションに対して採用すべき重要な原則だ。
並列実行はパイプラインの実行時間を短縮し、リソース利用率を向上させる上で非常に有用であるが、それは無制御な書き込みを許容するという意味ではない。複数のAWS Glueジョブが同じS3場所に書き込む場合、その結果は書き込みの設定とコミット方法に大きく依存する。上書き操作は相互に干渉し、追記操作はビジネス上の重複データをもたらし、パーティションレベルの競合は予期せぬ結果を生む可能性がある。この問題の解決策は、並列実行を全面的に無効にすることではない。むしろ、独立したワークロードは並列で実行しつつ、競合する可能性のある書き込み操作は適切に調整されるようにパイプラインを設計することだ。データパイプラインを設計する上での原則として、「処理は並列化するが、公開は制御する」という考え方が重要である。このアーキテクチャ上の小さな決定が、本番環境で起こりうる多くの予期せぬデータの問題を防ぐことにつながるだろう。