AWS Glue ETL ジョブが長時間実行されているのはなぜですか?

最終更新日: 2021 年 8 月 20 日

AWS Glue ジョブが長時間実行されています。

- または -

AWS Glue ストラグラータスクの完了に長時間かかっています。

簡単な説明

AWS Glue ジョブの完了に時間がかかる一般的な理由は次のとおりです。

  • 大規模なデータセット
  • データセット内のデータの不均一な分布
  • エグゼキューター間でのタスクの不均等な分布
  • リソースのプロビジョニング不足

解決方法

メトリクスの有効化

AWS Glue は Amazon CloudWatch メトリクスを提供します。このメトリクスを使用して、エグゼキューターに関する情報と各エグゼキューターによる実行量を提供します。AWS Glue ジョブで CloudWatch メトリクスを有効にするには、次のいずれかの操作を行います。

特別なパラメータの使用: AWS Glue ジョブに次の引数を追加します。このパラメータにより、ジョブ実行のジョブプロファイリングのメトリクスを収集できます。これらのメトリクスは、AWS Glue コンソールと CloudWatch コンソールで使用できます。

Key: --enable-metrics

AWS Glue コンソールを使用する: 既存のジョブでメトリクスを有効にするには、次の手順を実行します。

  1. AWS Glue コンソールを開きます。
  2. ナビゲーションペインで [ジョブ] を選択します。
  3. メトリクスを有効にするジョブを選択します。
  4. [アクション] を選択してから、[ジョブの編集] をクリックします。
  5. [モニタリングオプション] で、[ジョブメトリクス] を選択します。
  6. [保存] を選択します。

API の使用: 既存のジョブでメトリクスを有効にするには、DefaultArguments パラメータとして -enable-metrics で AWS Glue の UpdateJob API を使用します。

注: AWS Glue 2.0 は、メトリクスを報告する YARN を使用しません。つまり、AWS Glue 2.0 では、numberMaxNeededExecutors や numberAllExecutor などのエグゼキュータメトリクスの一部を取得できません。

継続的なログ記録の有効化

AWS Glue ジョブで継続的なログ記録を有効にすると、リアルタイムのドライバーとエグゼキューターのログは 5 秒ごとに CloudWatch にプッシュされます。このリアルタイムログ記録情報を使用すると、実行中のジョブの詳細を取得できます。詳細については、「AWS Glue ジョブの継続的なログ記録の有効化」を参照してください。

ドライバーとエグゼキューターのログの確認

ドライバーログで、完了する前に長時間実行されたタスクを確認します。以下はその例です。

2021-04-15 10:53:54,484 ERROR executionlogs:128 - g-7dd5eec38ff57a273fcaa35f289a99ecc1be6901:2021-04-15 10:53:54,484 INFO [task-result-getter-1] scheduler.TaskSetManager (Logging.scala:logInfo(54)): Finished task 0.0 in stage 7.0 (TID 139) in 4538 ms on 10.117.101.76 (executor 10) (13/14)
...
2021-04-15 12:11:30,692 ERROR executionlogs:128 - g-7dd5eec38ff57a273fcaa35f289a99ecc1be6901:2021-04-15 12:11:30,692 INFO [task-result-getter-3] scheduler.TaskSetManager (Logging.scala:logInfo(54)): Finished task 13.0 in stage 7.0 (TID 152) in 4660742 ms on 10.117.97.97 (executor 11) (14/14)

これらのログでは、1 つのタスクの完了に 77 分かかったことが確認できます。この情報を使用して、その特定のタスクに長い時間がかかっている理由を確認します。Apache Spark ウェブ UI を使用してこれを行うことができます。Spark UI は、さまざまなステージ、タスク、およびエグゼキューターについてよく構造化された情報を提供します。

Spark UI を有効にする

Spark UI を使用して、長時間実行される Spark ジョブのトラブルシューティングを行うことができます。Spark 履歴サーバーを起動して Spark UI ログを有効にすると、ステージとタスクに関する情報を取得できます。ログを使用して、ワーカーによるタスクの実行方法を知ることができます。AWS Glue コンソールまたは AWS Command Line Interface (AWS CLI) を使用して Spark UI を有効にできます。詳細については、「AWS Glue ジョブ用の Apache Spark ウェブ UI の有効化」を参照してください。

ジョブが完了すると、次のようなドライバーログが表示される場合があります。

ERROR executionlogs:128 - example-task-id:example-timeframe INFO [pool-2-thread-1] s3n.MultipartUploadOutputStream (MultipartUploadOutputStream.java:close(414)): close closed:false s3://dox-example-bucket/spark-application-1626828545941.inprogress

ジョブのログを分析した後、Spark 履歴サーバーを Amazon Elastic Compute Cloud (Amazon EC2) インスタンスまたは Docker を使用して起動できます。UI を開き、[エグゼキューター] タブに移動して、特定のエグゼキューターが長時間実行されているかどうかを確認します。その場合は、データセット内のデータスキューが原因で、作業の分布が不均一になり、利用可能なリソースの利用率が低下する可能性があります。[ステージ] タブでは、長い時間がかかったステージの詳細情報と統計情報を取得できます。これらのステージに高価で時間のかかるシャッフルスピルが関わっているかどうかについての詳細を見つけることができます。

データ処理ユニット (DPU) のキャパシティープランニング

すべてのエグゼキューターがジョブに対して均等に貢献しても、ジョブの完了にまだ長い時間がかかる場合は、ジョブにワーカーを追加して速度を向上させることを検討してください。DPU キャパシティープランニングは、次のことを回避するのに役立ちます。

  • 実行時間が長くなるアンダープロビジョニング
  • コストが高くなるが、同じ時間内に結果をもたらすオーバープロビジョニング

CloudWatch メトリクスから、現在使用されているエグゼキューターの数と必要なエグゼキューターの最大数に関する情報を取得できます。必要な DPU の数は、入力パーティションの数とリクエストされたワーカータイプによって異なります。

入力パーティションの数を定義するときは、次の点に注意してください。

  • Amazon Simple Storage Service (Amazon S3) ファイルが分割できない場合、パーティションの数は入力ファイルの数に等しくなります。
  • Amazon S3 ファイルが分割可能で、データが構造化されていないか半構造化されている場合、パーティションの数は合計ファイルサイズ / 64 MBに等しくなります。各ファイルのサイズが 64 MB 未満の場合、パーティションの数はファイル数と等しくなります。
  • Amazon S3 ファイルが分割可能であり、データが構造化されている場合、パーティションの数は合計ファイルサイズ / 128 MBに等しくなります。

DPU の最適数を計算するには、次の手順を実行します。

例えば、入力パーティションの数が 428 であるとします。次に、以下の式で最適な DPU 数を計算できます。

必要なエグゼキューターの最大数 = 入力パーティション数 / エグゼキューターあたりのタスク数 = 428/4 = 107

以下の点にご注意ください。

  • 標準ワーカータイプでは、エグゼキューターごとに 4 つのタスクがサポートされます。
  • G.1X では、エグゼキューターごとに 8 つのタスクがサポートされます
  • G.2X では、エグゼキューターごとに 16 個のタスクがサポートされます

標準ワーカータイプには、1 つのノードに 1 つのドライバーを含む 2 つのエグゼキューターがあります。これらのエグゼキューターの 1 つは Spark のドライバーです。したがって、108 のエグゼキューターが必要です。

必要な DPU の数 = (エグゼキューター数 / ノードあたりのエグゼキューター数) + 1 DPU = (108/2) + 1 = 55。