
はじめに
こんにちは!アプリケーションサービス本部ディベロップメントサービス1課の森山です。
私事ですが、先日 Serverless 部門でAWS Community Builders に選出されました! 引き続き、アウトプットを頑張っていきたいと思いますので、何卒よろしくお願いいたします。
今回は、AWS Glue の Apache Spark ジョブを使う中で、NumberOfWorkers や WorkerType の組み合わせで並列処理数がどう変わるかについて理解が浅かったため、実際にジョブを動かして検証してみました。
そこで、検証用スクリプトを Glue Spark ジョブとして実行し、ワーカー構成ごとの並列処理の挙動をログから確認してみます。
この記事で学べること
- AWS Glue のワーカー(Driver・Executor)の役割
NumberOfWorkersとWorkerTypeの組み合わせによる並列処理数の違い
前提知識・条件
- AWS Glue 5.0(Spark 3.5.4, Python 3.11)を使用
- Spark ジョブを対象に記載しています
- AWS Glue の基本的な概念については割愛します
AWS Glue のワーカーとは
AWS Glue の Spark ジョブは、複数のワーカーから構成されるクラスタ上で実行され、「Driver」と「Executor」の 2 つの役割があります。
簡単にワーカーのイメージ図を書いてみました。

また、ジョブ作成時に NumberOfWorkers パラメータでワーカーの総数を指定します。
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のソースは下記で公開しています。
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 のワーカー構成ごとの並列処理の挙動を、実際にジョブを実行して確認してみました。
少しイメージしづらい NumberOfWorkers や WorkerType の関係も理解することができました。
ポイントをまとめると以下のとおりです。
NumberOfWorkersには Driver が含まれるため、実際に処理を行う Executor はNumberOfWorkers - 1台- 並列処理数は Executor の vCPU 合計で決まる(デフォルト設定)
- 同じ並列処理数でもワーカータイプによって DPU(= コスト)が異なる
ジョブの設定を検討する際は、処理に必要なメモリ量と並列処理数のバランスを考慮して、ワーカータイプとワーカー数を選択するのが良さそうです。
なお、Gタイプはワーカータイプを上げても、1タスク(vCPU)あたりの平均メモリ割当量は約4GBのままです。
ワーカー全体のメモリが共有されるためOOMは発生しにくくなりますが、1つのタスクに処理が集中するような極端なデータの偏りがある場合は、引き続きOOMエラーに注意してください。