AWS Glue ジョブが「Command failed with exit code 1」(終了コード 1 でコマンドが失敗しました) というメッセージで失敗します。Amazon CloudWatch Logs に、「java.lang.OutOfMemoryError: Java heap space」(java.lang.OutOfMemoryError: Java ヒープの容量) エラーが表示されます。
簡単な説明
「java.lang.OutOfMemoryError: Java heap space」(java.lang.OutOfMemoryError: Java ヒープの容量) エラーは、ドライバーまたはエグゼキューターが JVM メモリを使い果たしていることを示します。OOM の原因がドライバーなのかエグゼキューターなのかを判断するには、「OOM 例外とジョブ異常のデバッグ」を参照してください。
注: 以下の解決方法は、ドライバーの OOM 例外のみに適用されます。
ドライバーの OOM 例外は次の原因で発生します。
- AWS Glue Spark ジョブで、Amazon Simple Storage Service (Amazon S3) から多数の小さなファイルを読み取る
- collect()、ブロードキャスト結合、共有変数などのドライバー負荷の高い操作を行う
解決方法
多数の小さなファイルが原因で発生するドライバーの OOM 例外を解決する
DynamicFrames を含む多数の小さなファイルが原因で発生するドライバーの OOM 例外を解決するには、次の 1 つまたは複数の方法を使用します。
useS3ListImplementation をアクティブ化する
ファイルを一覧表示すると、AWS Glue はドライバーのメモリリストにファイルインデックスを作成します。useS3ListImplementation を True に設定すると、AWS Glue はファイルのリストをメモリに一度にキャッシュしません。代わりに、AWS Glue はリストをバッチでキャッシュします。そのため、ドライバーがメモリ不足になる可能性が低くなります。
from_catalog で useS3ListImplementation をアクティブ化する方法については、次の例を参照してください。
datasource0 = glueContext.create_dynamic_frame.from_catalog(database = "database", table_name = "table", additional_options = {'useS3ListImplementation': True}, transformation_ctx = "datasource0")
from_catalog で useS3ListImplementation をアクティブ化する次の例を参照してください。
datasource0 = glueContext.create_dynamic_frame.from_options(connection_type="s3", connection_options = {"paths": ["s3://input_path"], "useS3ListImplementation":True,"recurse":True}, format="json")
useS3ListImplementation 機能は Amazon S3 ListKeys オペレーションを実装したものです。これにより、大きな結果セットが複数の応答に分割されます。useS3ListImplementation をジョブブックマークと共に使用するのがベストプラクティスです。
グループ化
Spark アプリケーションは、それぞれ異なる Spark タスクを使用してすべての小さなファイルを処理します。ドライバーが場所とタスク情報を保存して追跡するため、これによって OOM が発生する可能性があります。グループ化機能を有効にすると、タスクは個々のファイルではなく複数のファイルのグループを処理します。動的フレームを使用する場合、および Amazon S3 データセットのファイル数が 50,000 を超える場合、グループ化機能は自動的に有効になります。詳細については、「大きなグループでの入力ファイルの読み取り」を参照してください。
プッシュダウン述語によるフィルタリング
プッシュダウン述語を使用して、AWS Glue ジョブが読み取る Amazon S3 ファイルと Amazon S3 パーティションの数を減らします。これにより、基礎となるデータが読み取られる前に、AWS Glue テーブルから不要なパーティションが削除されます。詳細については、「プッシュダウン述語を使用した事前フィルタリング」を参照してください。
ドライバーの負荷の高い操作が原因で発生するドライバーの OOM 例外
次のいずれかの方法を使用して、ドライバーの負荷の高い操作が原因で発生するドライバーの OOM 例外を解決します。
ドライバーに高い負荷のかかる操作に注意する
collect() は、ワーカーから結果を収集し、それを単一のオブジェクトとしてドライバーに返す Spark 操作です。この操作は結果が非常に大きくなり、ドライバーの負担が大きくなってしまいます。デフォルトでは、Spark 設定の spark.driver.maxResultSize は 1 GB に設定されており、ドライバーに負荷がかかるのを防いでいます。
そのため、これらのアクションを制限し、可能な限り take()、takeSample()、isEmpty() などのアクションを使用してください。
また、リレーション (テーブル) がドライバーの使用可能なメモリよりも大きい場合、Spark のブロードキャスト結合で OOM エラーが発生する可能性があることにも注意してください。リレーションがエグゼキューターにブロードキャストされる前に、そのリレーションはドライバーノードでマテリアライズされます。複数のテーブルがブロードキャストされている場合や、リレーションが大きすぎる場合は、ドライバーがメモリ不足に陥る可能性があります。これを制御するには、Spark 設定の spark.sql.autoBroadcastJoinThreshold と Spark の結合のヒントを使用してください。
共有変数を定期的に破棄する
共有変数は慎重に使用してください。共有変数は、Spark ドライバーの OOM 例外を引き起こす可能性があるため、不要になったら破棄してください。共有変数には、ブロードキャスト変数とアキュムレータの 2 種類があります。
- ブロードキャスト変数は読み取り専用データで、エグゼキューターに 1 回だけ送信されます。すべてのエグゼキューター間で共有される小さな辞書や小さなテーブルなどの、不変の参照データを保存するのに適したソリューションです。
- アキュムレータは Spark エグゼキューター間で書き込み可能なコピーを提供するもので、(MapReduce のように) 分散カウンタや合計を実装するのにも使えます。
その他のトラブルシューティング
関連情報
AWS Glue でのメモリ管理を最適化する
大きなグループでの入力ファイルの読み取り
Amazon EMR で Apache Spark アプリケーションのメモリを正常に管理するためのベストプラクティス
Apache Spark ウェブ UI を使用したジョブの監視