AWS Glue Spark ジョブの並列処理数を検証して理解してみた

記事タイトルとURLをコピーする

はじめに

こんにちは!アプリケーションサービス本部ディベロップメントサービス1課の森山です。

私事ですが、先日 Serverless 部門でAWS Community Builders に選出されました! 引き続き、アウトプットを頑張っていきたいと思いますので、何卒よろしくお願いいたします。

今回は、AWS Glue の Apache Spark ジョブを使う中で、NumberOfWorkersWorkerType の組み合わせで並列処理数がどう変わるかについて理解が浅かったため、実際にジョブを動かして検証してみました。

そこで、検証用スクリプトを Glue Spark ジョブとして実行し、ワーカー構成ごとの並列処理の挙動をログから確認してみます。

この記事で学べること

  • AWS Glue のワーカー(Driver・Executor)の役割
  • NumberOfWorkersWorkerType の組み合わせによる並列処理数の違い

前提知識・条件

  • AWS Glue 5.0(Spark 3.5.4, Python 3.11)を使用
  • Spark ジョブを対象に記載しています
  • AWS Glue の基本的な概念については割愛します

AWS Glue のワーカーとは

AWS Glue の Spark ジョブは、複数のワーカーから構成されるクラスタ上で実行され、「Driver」と「Executor」の 2 つの役割があります。

簡単にワーカーのイメージ図を書いてみました。

また、ジョブ作成時に NumberOfWorkers パラメータでワーカーの総数を指定します。

docs.aws.amazon.com

Driver

ジョブ全体の管理を行います。

タスクのスケジューリングや Executor への作業割り当てを行いますが、データ処理自体は行いません。

NumberOfWorkers から 1 台が Driver として使われます。

Executor

実際にデータを処理するワーカーです。

各 Executor はワーカータイプに応じた vCPU を持ち、vCPU の数だけ Spark タスクを同時実行できます。

つまり、ワーカー数分並列処理できるというわけではありません。 NumberOfWorkers を 2 に設定した場合、実際に同時に処理を行えるワーカーは 1 つのみとなります。

並列処理の仕組み

Spark は処理を「タスク」という最小単位に分割して並列実行します。

また、デフォルト設定(spark.task.cpus=1)では 1 つの vCPU が 1 つのタスクを担当するため、並列処理数は Executor の vCPU 合計で決まります。

以下、例です。

NumberOfWorkers: 3、G.2X(8 vCPU) の場合

[Driver]     ← 管理のみ
[Executor1]  ← 8 vCPU = 8タスク同時実行
[Executor2]  ← 8 vCPU = 8タスク同時実行
               合計: 最大16タスク並列

ワーカータイプ別スペック(今回の検証で使用するもの)

今回の検証では G.1X と G.2X を使用します。

タイプ DPU vCPU メモリ ディスク
G.1X 1 4 16GB 94GB
G.2X 2 8 32GB 138GB

この他にも G.4X〜G.16X や、メモリ最適化の R タイプなど複数のワーカータイプがあります。適切なワーカータイプの選択方法を含め、詳細は以下の公式ドキュメントを参照してください。

やってみた

では、動作確認してみます!

今回は以下の 3 つの構成で検証し、並列度の違いを確認しました。

  • NumberOfWorkers=2、G.1X
  • NumberOfWorkers=3、G.1X
  • NumberOfWorkers=2、G.2X

検証用スクリプト

今回は以下のスクリプトを準備しました。

16 個のタスクを起動し、各タスクがどのホスト・PID で実行されたかをログに出力し、5 秒の待機を入れることでバッチの区切りが分かるようにしています。

import sys
import logging
from pyspark.context import SparkContext
 
logger = logging.getLogger(__name__)
logging.basicConfig(level=logging.INFO, stream=sys.stdout)
 
sc = SparkContext.getOrCreate()
 
# Executor 数(Driver を除く)
num_executors = sc._jsc.sc().getExecutorMemoryStatus().size() - 1
logger.info(f"Executor 数: {num_executors}")
logger.info(f"デフォルト並列度: {sc.defaultParallelism}")
 
# 並列処理でワーカー情報をログ出力
def log_worker_info(task_id):
    import logging, sys, socket, os, time
    worker_logger = logging.getLogger(__name__)
    if not worker_logger.handlers:
        handler = logging.StreamHandler(sys.stderr)
        handler.setFormatter(logging.Formatter('%(asctime)s %(levelname)s - %(message)s'))
        worker_logger.addHandler(handler)
        worker_logger.setLevel(logging.INFO)
     
    worker_logger.info(f"タスク {task_id}: ホスト={socket.gethostname()}, PID={os.getpid()}")
    time.sleep(5)  # 5秒待機
    worker_logger.info(f"タスク {task_id}: 完了")
    return task_id
 
tasks = sc.parallelize(range(16), 16)
tasks.foreach(log_worker_info)
 
logger.info("全タスク完了")

※ 今回は time.sleep による均一なワークロードで検証しています。実際のデータ処理で今回の検証通りの並列処理にはならない可能性もあるので注意ください。

また補足ですが、handler = logging.StreamHandler(sys.stderr) でログを stderr に出力しているのは、デフォルトでは Amazon CloudWatch に Driver のログのみが保存され、Executor のログは転送されないためです。

stderr に出力することで /aws-glue/jobs/error ロググループに Executor ログストリームも記録されます。

また、Spark UI を有効にすれば Executor のログを Amazon S3 に保存することも可能です。

私も最初 stdout に出力していて Executor のログが見えず詰まったので、同じところでハマった方の参考になれば幸いです。

環境構築

今回はCDKを使って環境構築します。

参考までにCDKのソースは下記で公開しています。

github.com

NumberOfWorkers=2、G.1X の場合

最初は以下の構成で試してみます。

  • NumberOfWorkers=2、G.1X
    • Executor: 1(NumberOfWorkers 2 - Driver 1)
    • DPU: 1 DPU/台 × 2 台 = 2
    • vCPU: 4 vCPU/台 × Executor 1 台 = 4
    • 同時タスク数: 最大 4

以下結果です。

バッチ タスク 開始 完了
1 0, 1, 2, 3 22:00:06 22:00:11
2 4, 5, 6, 7 22:00:11 22:00:16
3 8, 9, 10, 11 22:00:16 22:00:21
4 12, 13, 14, 15 22:00:22 22:00:27

16 タスクが 4 タスクずつ 4 バッチに分かれて処理されました。

全タスクが同一ホスト(Executor 1 台)上の 4 つの PID で実行され、4 vCPU = 4 並列が確認できました。

実行ログ抜粋(クリックで展開)

2026-03-04 22:00:06,215 INFO - タスク 1: ホスト=ip-172-35-78-108, PID=126
2026-03-04 22:00:06,220 INFO - タスク 0: ホスト=ip-172-35-78-108, PID=134
2026-03-04 22:00:06,228 INFO - タスク 3: ホスト=ip-172-35-78-108, PID=130
2026-03-04 22:00:06,233 INFO - タスク 2: ホスト=ip-172-35-78-108, PID=127
2026-03-04 22:00:11,218 INFO - タスク 1: 完了
2026-03-04 22:00:11,222 INFO - タスク 0: 完了
2026-03-04 22:00:11,230 INFO - タスク 3: 完了
2026-03-04 22:00:11,238 INFO - タスク 2: 完了
2026-03-04 22:00:11,542 INFO - タスク 6: ホスト=ip-172-35-78-108, PID=127
2026-03-04 22:00:11,547 INFO - タスク 5: ホスト=ip-172-35-78-108, PID=130
2026-03-04 22:00:11,562 INFO - タスク 4: ホスト=ip-172-35-78-108, PID=134
2026-03-04 22:00:11,597 INFO - タスク 7: ホスト=ip-172-35-78-108, PID=126
2026-03-04 22:00:16,552 INFO - タスク 5: 完了
2026-03-04 22:00:16,552 INFO - タスク 6: 完了
2026-03-04 22:00:16,567 INFO - タスク 4: 完了
2026-03-04 22:00:16,602 INFO - タスク 7: 完了
2026-03-04 22:00:16,801 INFO - タスク 9: ホスト=ip-172-35-78-108, PID=134
2026-03-04 22:00:16,803 INFO - タスク 8: ホスト=ip-172-35-78-108, PID=127
2026-03-04 22:00:16,824 INFO - タスク 11: ホスト=ip-172-35-78-108, PID=130
2026-03-04 22:00:16,826 INFO - タスク 10: ホスト=ip-172-35-78-108, PID=126
2026-03-04 22:00:21,808 INFO - タスク 9: 完了
2026-03-04 22:00:21,808 INFO - タスク 8: 完了
2026-03-04 22:00:21,826 INFO - タスク 11: 完了
2026-03-04 22:00:21,831 INFO - タスク 10: 完了
2026-03-04 22:00:22,024 INFO - タスク 13: ホスト=ip-172-35-78-108, PID=130
2026-03-04 22:00:22,033 INFO - タスク 12: ホスト=ip-172-35-78-108, PID=127
2026-03-04 22:00:22,045 INFO - タスク 14: ホスト=ip-172-35-78-108, PID=126
2026-03-04 22:00:22,051 INFO - タスク 15: ホスト=ip-172-35-78-108, PID=134
2026-03-04 22:00:27,029 INFO - タスク 13: 完了
2026-03-04 22:00:27,038 INFO - タスク 12: 完了
2026-03-04 22:00:27,050 INFO - タスク 14: 完了
2026-03-04 22:00:27,052 INFO - タスク 15: 完了

NumberOfWorkers=3、G.1X の場合

次にワーカーを 1 台増やして試してみます。

  • NumberOfWorkers=3、G.1X
    • Executor: 2(NumberOfWorkers 3 - Driver 1)
    • DPU: 1 DPU/台 × 3 台 = 3
    • vCPU: 4 vCPU/台 × Executor 2 台 = 8
    • 同時タスク数: 最大 8

以下結果です。

バッチ タスク Executor1(172-36-253-116) Executor2(172-35-243-40)
1 0-7 タスク 0, 1, 2, 3 タスク 4, 5, 6, 7
2 8-15 タスク 8, 9, 10, 11 タスク 12, 13, 14, 15

NumberOfWorkers=2 の場合と比べ、並列処理数が 4→8 に倍増し、バッチ数が 4→2 に半減しました。

実行ログ抜粋(クリックで展開)

2026-03-05 19:42:53,882 INFO - タスク 2: ホスト=ip-172-36-253-116, PID=134
2026-03-05 19:42:53,886 INFO - タスク 1: ホスト=ip-172-36-253-116, PID=129
2026-03-05 19:42:53,889 INFO - タスク 0: ホスト=ip-172-36-253-116, PID=128
2026-03-05 19:42:53,894 INFO - タスク 3: ホスト=ip-172-36-253-116, PID=137
2026-03-05 19:42:57,990 INFO - タスク 7: ホスト=ip-172-35-243-40, PID=144
2026-03-05 19:42:57,992 INFO - タスク 6: ホスト=ip-172-35-243-40, PID=152
2026-03-05 19:42:57,993 INFO - タスク 4: ホスト=ip-172-35-243-40, PID=142
2026-03-05 19:42:58,002 INFO - タスク 5: ホスト=ip-172-35-243-40, PID=143
2026-03-05 19:42:58,888 INFO - タスク 2: 完了
2026-03-05 19:42:58,891 INFO - タスク 0: 完了
2026-03-05 19:42:58,893 INFO - タスク 1: 完了
2026-03-05 19:42:58,899 INFO - タスク 3: 完了
2026-03-05 19:42:59,236 INFO - タスク 8: ホスト=ip-172-36-253-116, PID=128
2026-03-05 19:42:59,238 INFO - タスク 10: ホスト=ip-172-36-253-116, PID=129
2026-03-05 19:42:59,251 INFO - タスク 9: ホスト=ip-172-36-253-116, PID=137
2026-03-05 19:42:59,259 INFO - タスク 11: ホスト=ip-172-36-253-116, PID=134
2026-03-05 19:43:02,993 INFO - タスク 4: 完了
2026-03-05 19:43:02,994 INFO - タスク 6: 完了
2026-03-05 19:43:02,996 INFO - タスク 7: 完了
2026-03-05 19:43:03,007 INFO - タスク 5: 完了
2026-03-05 19:43:03,254 INFO - タスク 12: ホスト=ip-172-35-243-40, PID=144
2026-03-05 19:43:03,290 INFO - タスク 13: ホスト=ip-172-35-243-40, PID=143
2026-03-05 19:43:03,331 INFO - タスク 15: ホスト=ip-172-35-243-40, PID=142
2026-03-05 19:43:03,332 INFO - タスク 14: ホスト=ip-172-35-243-40, PID=152
2026-03-05 19:43:04,241 INFO - タスク 10: 完了
2026-03-05 19:43:04,241 INFO - タスク 8: 完了
2026-03-05 19:43:04,256 INFO - タスク 9: 完了
2026-03-05 19:43:04,262 INFO - タスク 11: 完了
2026-03-05 19:43:08,259 INFO - タスク 12: 完了
2026-03-05 19:43:08,295 INFO - タスク 13: 完了
2026-03-05 19:43:08,337 INFO - タスク 15: 完了
2026-03-05 19:43:08,337 INFO - タスク 14: 完了

NumberOfWorkers=2、G.2X の場合

最後にワーカー数は 2 のまま、ワーカータイプを G.2X に変更して試してみます。

  • NumberOfWorkers=2、G.2X
    • Executor: 1(NumberOfWorkers 2 - Driver 1)
    • DPU: 2 DPU/台 × 2 台 = 4
    • vCPU: 8 vCPU/台 × Executor 1 台 = 8
    • 同時タスク数: 最大 8

以下結果です。

バッチ タスク 開始 完了
1 0, 1, 2, 3, 4, 5, 6, 7 19:51:37 19:51:42
2 8, 9, 10, 11, 12, 13, 14, 15 19:51:42 19:51:47

全タスクが同一ホスト(Executor 1 台)上の 8 つの PID で実行されました。 NumberOfWorkers=2・G.1X(4 並列)と同じワーカー数でも、G.2X にすることで並列処理数が 4→8 に倍増しています。

実行ログ抜粋(クリックで展開)

2026-03-05 19:51:37,599 INFO - タスク 6: ホスト=ip-172-34-43-33, PID=179
2026-03-05 19:51:37,600 INFO - タスク 1: ホスト=ip-172-34-43-33, PID=184
2026-03-05 19:51:37,608 INFO - タスク 7: ホスト=ip-172-34-43-33, PID=194
2026-03-05 19:51:37,612 INFO - タスク 0: ホスト=ip-172-34-43-33, PID=198
2026-03-05 19:51:37,612 INFO - タスク 5: ホスト=ip-172-34-43-33, PID=188
2026-03-05 19:51:37,626 INFO - タスク 4: ホスト=ip-172-34-43-33, PID=206
2026-03-05 19:51:37,641 INFO - タスク 3: ホスト=ip-172-34-43-33, PID=178
2026-03-05 19:51:37,641 INFO - タスク 2: ホスト=ip-172-34-43-33, PID=201
2026-03-05 19:51:42,603 INFO - タスク 6: 完了
2026-03-05 19:51:42,604 INFO - タスク 1: 完了
2026-03-05 19:51:42,611 INFO - タスク 7: 完了
2026-03-05 19:51:42,615 INFO - タスク 0: 完了
2026-03-05 19:51:42,617 INFO - タスク 5: 完了
2026-03-05 19:51:42,631 INFO - タスク 4: 完了
2026-03-05 19:51:42,643 INFO - タスク 2: 完了
2026-03-05 19:51:42,646 INFO - タスク 3: 完了
2026-03-05 19:51:42,863 INFO - タスク 8: ホスト=ip-172-34-43-33, PID=179
2026-03-05 19:51:42,867 INFO - タスク 9: ホスト=ip-172-34-43-33, PID=194
2026-03-05 19:51:42,871 INFO - タスク 12: ホスト=ip-172-34-43-33, PID=206
2026-03-05 19:51:42,886 INFO - タスク 11: ホスト=ip-172-34-43-33, PID=188
2026-03-05 19:51:42,888 INFO - タスク 14: ホスト=ip-172-34-43-33, PID=201
2026-03-05 19:51:42,889 INFO - タスク 13: ホスト=ip-172-34-43-33, PID=178
2026-03-05 19:51:42,889 INFO - タスク 10: ホスト=ip-172-34-43-33, PID=198
2026-03-05 19:51:42,899 INFO - タスク 15: ホスト=ip-172-34-43-33, PID=184
2026-03-05 19:51:47,868 INFO - タスク 9: 完了
2026-03-05 19:51:47,869 INFO - タスク 8: 完了
2026-03-05 19:51:47,875 INFO - タスク 12: 完了
2026-03-05 19:51:47,890 INFO - タスク 10: 完了
2026-03-05 19:51:47,891 INFO - タスク 11: 完了
2026-03-05 19:51:47,891 INFO - タスク 14: 完了
2026-03-05 19:51:47,891 INFO - タスク 13: 完了
2026-03-05 19:51:47,903 INFO - タスク 15: 完了

検証結果のまとめ

3 つの構成を比較すると、以下のようになります。

構成 Executor vCPU合計 並列処理数 バッチ数 DPU
NumberOfWorkers=2、G.1X 1台 4 4 4 2
NumberOfWorkers=3、G.1X 2台 8 8 2 3
NumberOfWorkers=2、G.2X 1台 8 8 2 4

NumberOfWorkers=3・G.1X と NumberOfWorkers=2・G.2X はどちらも最大 8 並列ですが、DPU 数が異なります。

AWS Glue の料金は DPU 数 × 実行時間(秒単位)で課金されるため、メモリを多く必要としない処理であれば、G.1X でワーカー数を増やすほうがコスト効率の観点で良い場合もありそうですね!

まとめ

今回は AWS Glue のワーカー構成ごとの並列処理の挙動を、実際にジョブを実行して確認してみました。

少しイメージしづらい NumberOfWorkersWorkerType の関係も理解することができました。

ポイントをまとめると以下のとおりです。

  • NumberOfWorkers には Driver が含まれるため、実際に処理を行う Executor は NumberOfWorkers - 1
  • 並列処理数は Executor の vCPU 合計で決まる(デフォルト設定)
  • 同じ並列処理数でもワーカータイプによって DPU(= コスト)が異なる

ジョブの設定を検討する際は、処理に必要なメモリ量と並列処理数のバランスを考慮して、ワーカータイプとワーカー数を選択するのが良さそうです。

なお、Gタイプはワーカータイプを上げても、1タスク(vCPU)あたりの平均メモリ割当量は約4GBのままです。

ワーカー全体のメモリが共有されるためOOMは発生しにくくなりますが、1つのタスクに処理が集中するような極端なデータの偏りがある場合は、引き続きOOMエラーに注意してください。

森山 智史 (記事一覧)

アプリケーションサービス本部ディベロップメントサービス1課

2025年10月中途入社。

AWS Community Builders Serverless 2026