ENECHANGE Developer Blog

ENECHANGE開発者ブログ

AWS Glue + Iceberg で電力データを取り込み、処理時間を計測してみた

はじめに

以下の記事で、AWS Glue と Iceberg を用いて分析基盤を作成してみました。 本記事では、この分析基盤に対して 1万〜15万件 のデータを取り込み、以下の観点で検証します。

  • Glue Job の処理時間(XML パース → Iceberg MERGE)の計測
  • データ量に対する処理時間のスケーリング傾向の把握
  • ワーカー数(並列度)による効果の確認

tech.enechange.co.jp

電力使用量データ量 と AWS Glue ワーカー数

1. 電力使用量データ量(ファイル数)

  • 1日分の需要家数を1万件、2万件、5万件、10万件、15万件と変動させます。
  • 1ファイル = 1万需要家(重複なし)分の 1日の電力使用量を保存しています。
ファイル数 需要家数
1 1万
2 2万
5 5万
10 10万
15 15万

2. Glue ワーカー数

Glueのワーカータイプ と バージョンを以下のように設定して、3回ずつ処理時間を計測していきます。

  • Glue ワーカータイプ : G.1X(4 vCPU , 16GB RAM )
  • Glue バージョン : 5.0
ワーカー数 DPU (G.1X)
2 2
5 5
10 10

テストケース

  • 上記の電力使用量データ量とAWS Glue ワーカー数のパターンを組み合わせると15個のテストケースができます。
  • 1テストケースごとに、3回ずつ処理時間を計測していきます。
# 需要家数 ファイル数 ワーカー数
1 1万 1 2
2 1万 1 5
3 1万 1 10
4 2万 2 2
5 2万 2 5
6 2万 2 10
7 5万 5 2
8 5万 5 5
9 5万 5 10
10 10万 10 2
11 10万 10 5
12 10万 10 10
13 15万 15 2
14 15万 15 5
15 15万 15 10

処理時間の取得方法

  • AWS Glue コンソールで実行時間を確認
  • または AWS CLI で取得:
aws glue get-job-runs --job-name consumption-xml-to-iceberg --max-results 10

検証手順

1. サンプルデータ生成

  • 以下の構造で、1万件分の電力使用量データを含むXMLファイルを生成します。
<?xml version="1.0" encoding="UTF-8"?>
<electricity_usage_report>
  <record>
    <external_id>CUST-001234</external_id>
    <target_date>2024-01-15</target_date>
    <updated_at>2024-01-16T06:30:00+09:00</updated_at>
    <usage_kwh>
      <slot time="00:00">1.2</slot>
      <slot time="00:30">1.1</slot>
      <!-- ... 48コマ ... -->
      <slot time="23:30">1.3</slot>
    </usage_kwh>
  </record>
  <record>
    <external_id>CUST-001235</external_id>
    <target_date>2024-01-15</target_date>
    <updated_at>2024-01-16T06:30:00+09:00</updated_at>
    <usage_kwh>
      <slot time="00:00">1.2</slot>
      <slot time="00:30">1.1</slot>
      <!-- ... 48コマ ... -->
      <slot time="23:30">1.3</slot>
    </usage_kwh>
  </record>
</electricity_usage_report>

2. テスト実行

テストは以下の手順で進めます。

  • S3 へアップロード
  • Iceberg テーブルのクリーンアップ
  • Glue Job 実行(ワーカー数を指定)
  • 処理時間の計測

3. 結果記録

処理時間を記録し、結果記録テーブルを更新します。

手順1〜3を各テストケースで繰り返します。

結果記録

# 需要家数 ワーカー数 1回目 2回目 3回目 平均
1 1万 2 122s 63s 65s 83s
2 1万 5 126s 138s 133s 132s
3 1万 10 133s 169s 176s 159s
4 2万 2 148s 140s 137s 142s
5 2万 5 132s 141s 130s 134s
6 2万 10 123s 137s 184s 148s
7 5万 2 190s 188s 191s 190s
8 5万 5 158s 156s 162s 159s
9 5万 10 149s 201s 154s 168s
10 10万 2 533s 544s 548s 542s
11 10万 5 260s 261s 268s 263s
12 10万 10 267s 269s 232s 256s
13 15万 2 753s 777s 749s 760s
14 15万 5 280s 325s 283s 296s
15 15万 10 259s 220s 225s 235s

結果サマリー

  • 需要家数が増えるほど処理時間が増加しますが、ワーカー数を増やすことで処理時間を短縮できます。特に10万件以上ではワーカー2と、ワーカー5・10の差が顕著になります。

  • 以下のグラフは、需要家数の増加に伴う処理時間の変化を可視化したものです。

需要家数 ファイル数 ワーカー2 ワーカー5 ワーカー10 最速
1万 1 83s 132s 159s ワーカー2
2万 2 142s 134s 148s ワーカー5
5万 5 190s 159s 168s ワーカー5
10万 10 542s 263s 256s ワーカー10
15万 15 760s 296s 235s ワーカー10

考察

ファイル数とワーカー数の関係

  • ファイル数 < ワーカー数 → 効果が出にくい
  • ファイル数 ≥ ワーカー数 → 並列処理の効果が発揮される

推奨設定(ファイル分割あり前提)

データ規模 推奨ワーカー数
〜2万件 2
2〜5万件 5
10万件以上 10

追加検証: ファイル分割 vs 1ファイル

検証目的

同じ需要家数でファイル数を変えた場合の処理時間を比較し、処理時間にどのような差が出るか観察する。

テストケース

# 需要家数 ファイル数 ワーカー数
1 2万 1 2
2 2万 1 5
3 2万 1 10
4 5万 1 2
5 5万 1 5
6 5万 1 10
7 10万 1 2
8 10万 1 5
9 10万 1 10
10 15万 1 2
11 15万 1 5
12 15万 1 10

結果記録

# 需要家数 ファイル数 ワーカー数 1回目 2回目 3回目 平均
1 2万 1 2 163s 164s 215s 181s
2 2万 1 5 156s 234s 145s 178s
3 2万 1 10 205s 153s 158s 172s
4 5万 1 2 312s 223s 274s 270s
5 5万 1 5 231s 221s 208s 220s
6 5万 1 10 209s 211s 234s 218s
7 10万 1 2 365s 353s 376s 365s
8 10万 1 5 320s 319s 317s 319s
9 10万 1 10 312s 319s 356s 329s
10 15万 1 2 502s 454s 468s 475s
11 15万 1 5 419s 427s 450s 432s
12 15万 1 10 448s 428s 440s 439s

比較結果

  • ファイル分割ありの場合、ワーカー5・10で処理時間が大きく短縮されています。一方、1ファイルの場合はワーカー数を増やしても処理時間の改善が限定的になります。

  • 以下のグラフは、同じ需要家数での「ファイル分割あり」と「1ファイル」の処理時間を比較したものです。

    • 青がファイル分割、赤が1ファイル です。

需要家数 ファイル数 ワーカー2 ワーカー5 ワーカー10 最速
2万 1 181s 178s 172s ワーカー10
2万 2 142s 134s 148s ワーカー5
5万 1 270s 220s 218s ワーカー10
5万 5 190s 159s 168s ワーカー5
10万 1 365s 319s 329s ワーカー5
10万 10 542s 263s 256s ワーカー10
15万 1 475s 432s 439s ワーカー5
15万 15 760s 296s 235s ワーカー10

追加検証のまとめ

発見事項

  • ワーカー2: 10万件以上で1ファイルの方が速い
  • ワーカー5: 全データサイズでファイル分割が優位
  • ワーカー10: 大規模データでファイル分割の効果が顕著

推奨設定(総合判断)

条件 推奨ワーカー数 理由
通常運用(ファイル分割あり) 5 コストと速度のバランス最良
大量データ急ぎ(10万件+、分割あり) 10 並列効果最大
1ファイルのみ 5 10にしても速度向上しない

Spark UI 分析

Stage 比較: 1ファイル vs 15ファイル分割

1ファイル (総処理時間: 440s)

Stage 時間 タスク数 処理内容
0 316.0s 1 XMLパース (repartition)
1 6.9s 20 count
3 3.6s 20 DynamicFrame変換
6 7.2s 20 SQL処理
7 10.8s 20 SQL処理
10 1.8s 36 SQL処理
14 4.4s 1 MERGE書き込み

15ファイル分割 (総処理時間: 259s)

Stage 時間 タスク数 処理内容
0 52.6s 15 XMLパース (count)
1 32.2s 15 DynamicFrame変換
3 53.4s 15 SQL処理
4 56.3s 15 SQL処理
6 2.2s 36 SQL処理
9 4.2s 1 MERGE書き込み

分析結果

項目 1ファイル 15ファイル 改善率
XMLパース時間 316s 53s 6倍高速
XMLパースタスク数 1 15 15並列化
総処理時間 440s 259s 41%短縮

ボトルネックの特定

  1. 1ファイルの場合: Stage 0 (XMLパース) が316秒で全体の72%を占める。タスク数が1のため、ワーカーを増やしても並列化できない。

  2. 15ファイル分割の場合: Stage 0 が15タスクで並列実行され、52.6秒に短縮。各ワーカーが独立してファイルを処理できる。

  3. 根本原因: glueContext.create_dynamic_frame.from_options でのXMLパースは、ファイル単位でしか並列化されない。1ファイル内のレコードは順次処理される。

参考: タスク分散の仕組み

  • G.1X ワーカー = 4 vCPU = 4 cores (4並列スロット)
  • 10ワーカー = 1 Driver + 9 Executor = 36並列スロット
  • 15ファイル → 15タスク → 4 Executor × 4 cores で同時実行

結論

  • ファイル分割が最重要: ワーカー数を増やすより、ファイル分割の方が効果大
  • ワーカー数はファイル数に合わせる: ワーカー数 ≤ ファイル数 が基本(余剰ワーカーは効果が出にくい)
  • ワーカー5が汎用的: ほとんどのケースで最適またはそれに近い性能
  • ワーカー10は条件付き: 10ファイル以上 × 10万件以上の場合のみ有効

本番運用に向けて

今回の検証はワーカー数(2/5/10)とファイル数(1〜15)の限られた範囲で実施しました。本番環境では、実際のデータ量・ファイル数・処理時間の要件に応じて、ワーカー数やワーカータイプのチューニングが必要です。

特に以下の点を考慮してください:

  • コストと速度のトレードオフ: ワーカー数やワーカータイプを上げれば速くなるがDPUコストも増加
  • ファイル数との関係: ファイル数以上にワーカーを増やしても効果は限定的
  • SLA要件: 処理時間の制約がある場合は、それに合わせた設定が必要

今後の課題

今回はSpark UIを用いてStage単位での処理時間を確認しましたが、正直なところSpark自体を触り始めたばかりで、まだまだ理解が浅い部分があります。

以下の点は今後学びながら深掘りしていきたいです。

  • Spark UIの詳細メトリクス(Scheduler Delay、GC Time、Shuffle Read/Write など)の読み方
  • ワーカー2で逆転現象が起きる原因の特定
  • ワーカータイプによる違い
  • Icebergのデータファイル形式(Parquet vs Avro)によるパフォーマンス差

引き続き検証を進めて、分かったことがあれば記事にしていきたいと思います。