STEP 2:Apache Sparkアーキテクチャ

⚡ STEP 2: Apache Sparkアーキテクチャ

Sparkの内部構造を理解して、効率的なコードを書けるようになる

📋 このステップで学ぶこと

  • Sparkのアーキテクチャ全体像
  • Driver、Executor、Cluster Managerの役割
  • マスターとワーカーの関係
  • Spark Coreの理解
  • RDD、DataFrame、Datasetの位置づけ

🎯 1. Sparkのアーキテクチャ全体像

1-1. なぜアーキテクチャを学ぶのか

Sparkのコードを書く前に、「Sparkがどのように動いているか」を理解することが大切です。アーキテクチャを理解していると、以下のようなメリットがあります。

📝 アーキテクチャを学ぶメリット

✅ エラーが発生したときに、原因を特定しやすくなる
✅ パフォーマンスを改善するポイントがわかる
✅ メモリ不足などの問題を事前に防げる
✅ クラウド環境でのリソース設定が適切にできる

1-2. 身近な例で理解するSparkの構造

Sparkの構造を、「オーケストラの演奏」に例えて説明します。

🎼 指揮者 = Driver(ドライバー)

オーケストラ全体を統率する存在。

・楽譜(コード)を読み解く
・各楽器(Executor)に演奏指示を出す
・全体のタイミングを調整する
・演奏が完成したら聴衆に届ける

🎻 演奏者 = Executor(エグゼキューター)

実際に音を出す存在。

・指揮者の指示に従って演奏する
・自分の楽譜(データ)を処理する
・他の演奏者と並行して演奏
・複数人が同時に演奏して美しい音楽を作る

🏢 劇場マネージャー = Cluster Manager

演奏環境を整える存在。

・会場や楽器を準備する
・演奏者を手配・配置する
・演奏者が足りなければ追加する
・演奏者が倒れたら代役を用意する

1-3. Sparkクラスターの全体図

Sparkは、「マスター・ワーカー型」のアーキテクチャを採用しています。1台のマスター(司令塔)が、複数のワーカー(作業員)を管理します。

※以下の図は横スクロールできます(スマートフォンの場合)

【Sparkクラスターの構成図】

■ Driver Program(指揮者)
├ あなたのコードを実行
├ ジョブを小さなタスクに分割
├ Executorにタスクを割り当て
└ 結果を集めてまとめる

↓ 「このタスクをやって」

■ Cluster Manager(劇場マネージャー)
└ リソース(CPU・メモリ)を管理

↓ Executorを起動

■ Worker 1〜3(作業マシン)
┌─────────────┬─────────────┬─────────────┐
│ Worker 1   │ Worker 2   │ Worker 3   │
│ Executor   │ Executor   │ Executor   │
│(演奏者)  │(演奏者)  │(演奏者)  │
│ Task 1, 4   │ Task 2, 5   │ Task 3, 6   │
└─────────────┴─────────────┴─────────────┘

↓ 「処理が終わりました」

→ Driver に結果を返却

1-4. 処理の流れを順番に追う

Sparkアプリケーションが実行されるとき、内部では以下の順番で処理が進みます。

【Sparkアプリケーションの実行フロー】

STEP 1: アプリケーション起動
あなた → Pythonでsparkのコードを実行
Driver → SparkSession(Sparkとの接続)を初期化

STEP 2: リソース確保
Driver → 「4コア、8GBメモリください」
Cluster Manager → 利用可能なWorkerを確認
Cluster Manager → 各WorkerでExecutorを起動

STEP 3: ジョブの分割と実行
Driver → ジョブを小さなTaskに分割
Driver → 各ExecutorにTaskを割り当て
Executor → Taskを並列で実行(ここで高速化!)
Executor → 処理した中間結果をメモリに保存

STEP 4: 結果の集約
Executor → 処理結果をDriverに送信
Driver → 全Executorの結果を統合
Driver → 最終結果をあなたに返す

STEP 5: リソース解放
Driver → 「処理完了しました」
Cluster Manager → Executorを停止
Driver → SparkSessionを終了

💡 ポイント

Sparkが速い理由は、STEP 3で複数のExecutorが並列で処理するからです。
10台のExecutorがあれば、理論上10倍速く処理できます。

🎭 2. Driver、Executor、Cluster Managerの役割

2-1. Driver(ドライバー)を詳しく理解する

Driverは、Sparkアプリケーションの「脳」です。あなたが書いたコードはすべてDriverで実行され、Driverが全体を制御します。

🧠 Driverの主な仕事

1. SparkSessionの管理
Sparkクラスターとの接続を確立し、維持する

2. ジョブの分割
大きな処理を小さなタスクに分割する

3. DAG(処理計画)の作成
処理の順番と依存関係を整理する

4. タスクの割り当て
どのExecutorにどのタスクをやらせるか決める

5. 結果の集約
各Executorから返ってきた結果をまとめる

Driverで実行されるコード例

以下は、Driverで実行される典型的なSparkコードです。

from pyspark.sql import SparkSession

# ━━━ ここからDriverで実行 ━━━

# SparkSessionを作成(Sparkとの接続を確立)
spark = SparkSession.builder \
    .appName("MyApp") \
    .getOrCreate()

# データを読み込む(この時点では「計画」だけ)
df = spark.read.csv("data.csv")

# データを加工(まだ実行されない)
result = df.filter(df['age'] > 30) \
           .groupBy('city') \
           .count()

# show()を呼ぶと、ここで初めて処理が実行される
result.show()

# SparkSessionを終了
spark.stop()
⚠️ Driverの注意点

1. Driverが止まると全体が止まる
Driverは「脳」なので、これが停止するとアプリケーション全体が停止します。

2. Driverに大量データを集めない
collect()で全データをDriverに集めると、メモリ不足になります。
例:1億行のデータをdf.collect()すると、Driverがダウンします。

3. ネットワーク通信が重要
DriverとExecutor間の通信が遅いと、全体のパフォーマンスが落ちます。

2-2. Executor(エグゼキューター)を詳しく理解する

Executorは、実際にデータを処理する「手足」です。Driverからの指示を受けて、並列でタスクを実行します。

🦾 Executorの主な仕事

1. タスクの実行
Driverから受け取ったタスクを処理する

2. データの保持
処理中の中間データをメモリに保存する

3. キャッシュの管理
頻繁に使うデータをメモリに保存して再利用

4. 結果の送信
処理が終わったらDriverに結果を返す

Executorの内部構造

1つのExecutorは、以下のような構造になっています。

【Executor 1 の内部構造】

■ Executor 1(Worker Node 1 上で動作)

CPU Cores: 4コア
└ 同時に4つのTaskを実行可能

Memory: 8GB
├ Execution Memory(約60%): 4.8GB
│ └ タスクの実行に使用(ソート、結合、集計など)
└ Storage Memory(約40%): 3.2GB
  └ キャッシュデータの保存(cache()で保存したデータ)

現在実行中のTask:
├ Task 1: データ読み込み中
├ Task 2: フィルター処理中
├ Task 3: 集計処理中
└ Task 4: 待機中

💡 ExecutorとTaskの関係

1つのExecutorは、CPUコア数と同じ数のTaskを同時実行できます。

例:4コアのExecutorの場合
・4つのTaskを同時に実行可能
・5つ目のTaskは、1つが終わるまで待機

つまり:コア数が多いほど、並列処理能力が高い!

2-3. Cluster Manager(クラスターマネージャー)を詳しく理解する

Cluster Managerは、クラスター全体の「リソース管理者」です。CPUやメモリの割り当てを管理し、Executorの起動・停止を行います。

🎛️ Cluster Managerの種類

Sparkは複数のCluster Managerに対応しています。

1. Local → 開発・学習用(1台のPC)
2. Standalone → Spark専用の軽量版
3. YARN → Hadoop環境で最も一般的
4. Kubernetes → コンテナ環境で人気上昇中
5. Mesos → 大規模クラスター向け

Cluster Manager 特徴 使用場面
Local 1台のPCで動作
セットアップ不要
学習、開発、テスト
Standalone Spark専用
シンプルで軽量
小規模クラスター
YARN Hadoopと統合
複数アプリ共存
AWS EMR、GCP Dataproc
Kubernetes コンテナベース
柔軟なスケーリング
クラウドネイティブ環境
💡 このコースでの学習順序

Part 1〜5: Localモード(自分のPC)で基礎を学習
Part 6: AWS EMR(YARN)とGCP Dataproc(YARN)で本番環境を体験

👥 3. マスターとワーカーの関係

3-1. マスター・ワーカーモデルとは

マスター・ワーカーモデルは、分散システムで最も一般的なアーキテクチャです。「司令塔が1つ、作業員が複数」という構造です。

【マスター・ワーカーモデルの構成】

■ Master Node(マスターノード)
├ Driver Program
└ Cluster Manager

↓ 指示を出す

■ Worker Nodes(ワーカーノード)
┌─────────────┬─────────────┬─────────────┐
│ Worker 1   │ Worker 2   │ Worker 3   │
│(ワーカー1)│(ワーカー2)│(ワーカー3)│
│ Executor   │ Executor   │ Executor   │
│ Data 1/3   │ Data 2/3   │ Data 3/3   │
└─────────────┴─────────────┴─────────────┘

3-2. データの分散配置

ビッグデータは1台のマシンには収まりません。そこでSparkは、データをパーティション(区画)に分割して、各ワーカーに分散配置します。

📝 パーティションとは

パーティションとは、データを小分けにした「塊」のことです。

例:1億行のデータがある場合
→ 100個のパーティションに分割(各パーティションは100万行)
→ 各ワーカーが担当するパーティションを処理
→ 並列で処理するため高速!

【データ分散の具体例】

元データ: 1億レコード(100GB)

━━━ パーティション分割 ━━━

Worker 1 が処理:
├ パーティション 1(1,000万レコード、10GB)
├ パーティション 4(1,000万レコード、10GB)
└ パーティション 7(1,000万レコード、10GB)

Worker 2 が処理:
├ パーティション 2(1,000万レコード、10GB)
├ パーティション 5(1,000万レコード、10GB)
└ パーティション 8(1,000万レコード、10GB)

Worker 3 が処理:
├ パーティション 3(1,000万レコード、10GB)
├ パーティション 6(1,000万レコード、10GB)
├ パーティション 9(1,000万レコード、10GB)
└ パーティション 10(1,000万レコード、10GB)

━━━ 結果 ━━━

1台で処理: 約60分
3台で処理: 約20分(3倍高速!)

3-3. 障害発生時の動作

分散システムでは、どこかのマシンが故障することは珍しくありません。Sparkは、障害が発生しても処理を継続できるように設計されています。

⚠️ 障害発生時の対応

1. Executorが故障した場合
→ Driverが検知して、別のExecutorでタスクを再実行
→ 処理は継続される

2. Workerノードが故障した場合
→ そのノード上の全Executorを他のノードで再起動
→ データの系譜(Lineage)から再計算

3. Driverが故障した場合
→ アプリケーション全体が停止
→ 最初から再実行が必要

💡 Lineage(系譜)による耐障害性

Sparkは、データがどのように作られたかの「履歴」を記録しています。

例えば「データAをフィルターして、グループ化して、集計した」という履歴があれば、
途中でデータが失われても、元のデータから再計算できます。

これにより、高い耐障害性(Fault Tolerance)を実現しています。

⚙️ 4. Spark Coreの理解

4-1. Spark Coreとは

Spark Coreは、Sparkの「基盤」となるコンポーネントです。すべてのSpark機能は、このSpark Coreの上に構築されています。

【Sparkのアーキテクチャ階層】

■ 高レベルAPI(ユーザーが使う部分)
├ Spark SQL / DataFrame
├ MLlib(機械学習)
└ Structured Streaming

↓ 内部で使用

■ Spark Core(基盤)
├ RDD(基本データ構造)
├ タスクスケジューリング
├ メモリ管理
└ 障害復旧

↓ 実行基盤

■ Cluster Manager(YARN / Kubernetes等)

4-2. Spark Coreの主要機能

1️⃣ RDD(基本データ構造)

Resilient Distributed Dataset(耐障害性分散データセット)の略。

・分散データの基本単位
・不変(Immutable)
・障害に強い

2️⃣ タスクスケジューリング

ジョブを効率的に実行するための仕組み。

・ジョブをステージに分割
・ステージをタスクに分割
・データの場所を考慮して割り当て

3️⃣ メモリ管理

高速処理のためのメモリ活用。

・インメモリ処理で高速化
・キャッシュの管理
・メモリ不足時のディスク退避

4️⃣ 障害復旧

データの系譜(Lineage)を記録。

・障害時は失われた部分のみ再計算
・チェックポイントで復旧を高速化
・高い耐障害性を実現

4-3. TransformationsとActions(最重要概念)

Sparkを使う上で最も重要な概念が、「Transformations(変換)」と「Actions(アクション)」の違いです。

🔄 Transformations(変換)とは

データを「変換」する操作。すぐには実行されない(計画を立てるだけ)。

例:filter、map、groupBy、select、join など

特徴:
・新しいDataFrame/RDDを返す
・遅延評価(Lazy Evaluation)
・「こういう処理をする」という計画を立てるだけ

▶️ Actions(アクション)とは

結果を取得したり保存したりする操作。ここで初めて実行される

例:show、count、collect、save、first など

特徴:
・結果を返す(数値、リスト、画面表示など)
・Transformationsをまとめて実行
・実際にExecutorが動き始める

# ━━━ Transformations(変換)━━━
# この時点では「計画を立てているだけ」で、実際の処理は行われない

df = spark.read.csv("data.csv")           # 計画1: CSVを読む
df2 = df.filter(df['age'] > 30)           # 計画2: 30歳以上でフィルター
df3 = df2.groupBy('city')                  # 計画3: 都市でグループ化
df4 = df3.count()                           # 計画4: カウント

# ↑ここまで、実際には何も処理されていない!
#   Sparkは「こういう処理をする予定」という計画を立てているだけ

# ━━━ Actions(アクション)━━━
# show()を呼んだ瞬間、上記の計画が一気に実行される

df4.show()  # ← ここで初めて処理が実行される!
💡 なぜ遅延評価(Lazy Evaluation)を使うのか

理由1: 最適化ができる
Sparkは処理全体を見てから最適な実行計画を立てます。
例:フィルター処理を先に実行して、処理するデータ量を減らす

理由2: 無駄な処理を省ける
必要な結果を得るために本当に必要な処理だけを実行します。

理由3: メモリ効率が良い
中間結果を必要以上にメモリに保持しません。

📊 5. RDD、DataFrame、Datasetの位置づけ

5-1. Sparkのデータ抽象化の進化

Sparkには、データを扱うための3つの方法(API)があります。それぞれ登場した時期と特徴が異なります。

【Sparkのデータ抽象化の歴史】

2012年:RDD 登場
└「低レベルで柔軟だけど、ちょっと難しい…」



2013年:DataFrame 登場
└「Pandasみたいで使いやすい!SQLも使える!」



2015年:Dataset 登場(Scala/Javaのみ)
└「型安全で、コンパイル時にエラーチェック!」
 ※Pythonでは使えない



現在:DataFrameが主流
99%のケースでDataFrameを使えばOK!

5-2. RDD(Resilient Distributed Dataset)

RDDは、Sparkの最初のデータ構造です。低レベルで柔軟性が高いですが、使いこなすには知識が必要です。

📦 RDDの特徴

良い点:
・細かい制御ができる(低レベルAPI)
・任意のPythonオブジェクトを格納できる
・障害に強い(自動で再計算)

悪い点:
・使い方が難しい
・自動最適化が効かない
・SQLが使えない

RDDのコード例

from pyspark import SparkContext

# SparkContextを作成
sc = SparkContext("local", "RDD Example")

# リストからRDDを作成
rdd = sc.parallelize([1, 2, 3, 4, 5])

# Transformation: 各要素を2倍にする(まだ実行されない)
rdd2 = rdd.map(lambda x: x * 2)

# Action: 結果を取得(ここで実行される)
result = rdd2.collect()
print(result)

sc.stop()
[2, 4, 6, 8, 10]

5-3. DataFrame(最も推奨)

DataFrameは、Pandasに似た高レベルなAPIです。使いやすく、自動最適化も効くため、最も推奨されます。

📊 DataFrameの特徴

良い点:
・Pandasに似た直感的なAPI
・スキーマ(列名と型)が明確
・自動最適化が効く(Catalyst Optimizer)
・SQLクエリが使える
・Python、Scala、Java、Rすべてで使える

悪い点:
・RDDほど細かい制御はできない
・構造化データ向け(非構造化データは苦手)

DataFrameのコード例

from pyspark.sql import SparkSession

# SparkSessionを作成
spark = SparkSession.builder.appName("DataFrame Example").getOrCreate()

# データを用意(リストのリスト)
data = [
    (1, "Alice", 30),
    (2, "Bob", 25),
    (3, "Charlie", 35)
]

# DataFrameを作成(列名も指定)
df = spark.createDataFrame(data, ["id", "name", "age"])

# Transformation: 28歳以上でフィルター
df_filtered = df.filter(df.age > 28)

# Action: 結果を表示
df_filtered.show()

spark.stop()
+---+-------+---+
| id|   name|age|
+---+-------+---+
|  1|  Alice| 30|
|  3|Charlie| 35|
+---+-------+---+

5-4. Dataset(Scala/Javaのみ)

Datasetは、DataFrameに型安全性を追加したものです。ただし、Pythonでは使えません

⚠️ Pythonユーザーへの注意

PythonではDatasetは使えません。DataFrameを使ってください

実は、PySparkのDataFrameは内部的には「Dataset[Row]」(Rowという型のDataset)です。
つまり、PythonでDataFrameを使うことは、Datasetの一種を使っているのと同じです。

5-5. RDD vs DataFrame 比較表

項目 RDD DataFrame
抽象化レベル 低レベル 高レベル
使いやすさ ⭐⭐(難しい) ⭐⭐⭐⭐⭐(簡単)
パフォーマンス 最適化なし 自動最適化
スキーマ なし あり(列名と型)
SQL対応 ❌ 不可 ✅ 可能
推奨度 特殊な用途のみ ★ 推奨 ★
💡 結論:どれを使うべきか

99%のケースでDataFrameを使ってください。

RDDは、DataFrameでは実現できない特殊な処理が必要な場合のみ使います。
例えば、非構造化データや、独自のオブジェクトを扱う場合などです。

このコースでは:
Part 2: RDDの概念を理解(4時間)
Part 3以降: DataFrameに集中して学習

📝 STEP 2 のまとめ

✅ このステップで学んだこと

1. Sparkの3大コンポーネント
・Driver = 指揮者(コードを実行、タスクを割り当て)
・Executor = 演奏者(実際にデータを処理)
・Cluster Manager = 劇場マネージャー(リソースを管理)

2. マスター・ワーカーモデル
・1台のマスターが複数のワーカーを管理
・データはパーティションに分割して分散配置
・障害時はLineage(系譜)から再計算

3. Spark Core
・すべてのSpark機能の基盤
・RDD、スケジューリング、メモリ管理、障害復旧を担当

4. TransformationsとActions
・Transformations = 計画を立てる(すぐには実行されない)
・Actions = 実行する(ここで初めて処理が走る)

5. データ構造の選択
・RDD = 低レベル、特殊用途向け
・DataFrame = 高レベル、99%これを使う
・Dataset = Scala/Javaのみ(Pythonでは使えない)

💡 最重要ポイント

「TransformationsとActions」の違いを理解することが、Sparkを使いこなす第一歩です。

Transformationsはすぐには実行されず、Actionを呼んだときに初めて実行されます。
この「遅延評価(Lazy Evaluation)」がSparkの高速化の秘密です。

🎯 次のステップの予告

次のSTEP 3では、「Spark環境構築」を行います。

いよいよ実際に手を動かします!ローカルPCにSparkをインストールして、初めてのSparkコードを実行しましょう!

📝

学習メモ

ビッグデータ処理(Apache Spark) - Step 2

📋 過去のメモ一覧
#artnasekai #学習メモ
LINE