Data platformProcessingApache SparkSpark Application Lifecycle

Spark Application Lifecycle

Học Spark từ cách một application được chạy: driver, executor, job, stage và task.

Why This Page Exists

Khi học một tool mới, tớ thường muốn trả lời câu hỏi đầu tiên rất thực dụng: mình chạy nó như thế nào, và khi chạy thì chuyện gì xảy ra bên trong?

Với Spark cũng vậy. Trước khi học DataFrame API, SQL, shuffle, partition hay tuning, tớ muốn có một bức tranh đơn giản về một Spark application bình thường:

mình submit một chương trình Spark
  -> Spark tạo driver
  -> driver xin executor
  -> executor chạy task
  -> job xong thì application kết thúc

Page này chỉ tập trung vào baseline đó. Không bàn Databricks, không bàn managed platform, không đi sâu security/runtime đặc biệt. Chỉ là: học Spark bình thường như một processing tool.

Starting Point

Giả sử mình có một file Python rất nhỏ:

from pyspark.sql import SparkSession

spark = SparkSession.builder.appName("example").getOrCreate()

df = spark.read.parquet("/data/events")
result = df.groupBy("country").count()
result.show()

spark.stop()

Rồi chạy:

spark-submit app.py

Nhìn như đang chạy một script Python. Nhưng với Spark, script này trở thành một Spark application.

Đó là điểm bắt đầu cần nhớ: Spark không chỉ chạy code local. Nó dựng một application có process điều phối và các process worker để xử lý data phân tán.

Spark Application

Spark application là toàn bộ một lần chạy chương trình Spark.

Trong ví dụ trên, từ lúc spark-submit app.py bắt đầu cho tới khi spark.stop() hoặc process kết thúc, đó là một application.

Một application thường có:

  • một driver;
  • nhiều executors;
  • một cluster manager đứng ra cấp resource;
  • nhiều jobs, stages, tasks phát sinh trong lúc chạy.

Cách nhớ ngắn:

Application = toàn bộ lần chạy Spark
Driver      = process điều phối
Executor    = process chạy task
Job         = việc được trigger bởi action
Stage       = phần của job, thường chia bởi shuffle
Task        = đơn vị chạy trên một partition

Driver

Driver là process chạy chương trình chính của mình.

Trong app.py, những dòng như:

spark = SparkSession.builder.getOrCreate()
df = spark.read.parquet(...)
result = df.groupBy(...).count()
result.show()

được bắt đầu từ driver.

Driver không phải nơi xử lý toàn bộ data. Với data lớn, driver không tự đọc hết data rồi xử lý. Driver giống chỗ điều phối hơn:

  • tạo SparkSession / SparkContext;
  • phân tích computation cần chạy;
  • chia computation thành job, stage, task;
  • gửi task xuống executor;
  • nhận trạng thái và kết quả từ executor.

Cách nhớ:

Driver biết toàn bộ kế hoạch.
Executor làm từng phần việc cụ thể.

Executor

Executor là process worker chạy trên các machine/container trong cluster.

Executor nhận task từ driver, chạy task trên một phần dữ liệu, rồi báo kết quả lại.

Ví dụ một file parquet có nhiều partition. Khi chạy groupBy().count(), Spark có thể chia dữ liệu ra thành nhiều task. Mỗi executor nhận một số task và xử lý phần dữ liệu tương ứng.

Executor thường làm các việc như:

  • chạy task;
  • giữ data cache nếu mình gọi cache();
  • giữ shuffle data trung gian;
  • gửi heartbeat/status về driver.

Một điểm dễ nhầm:

machine/node != executor

Node là máy hoặc container/pod nơi process chạy. Executor là process Spark chạy trên node đó.

Cluster Manager

Spark cần một hệ thống để cấp tài nguyên. Hệ đó gọi là cluster manager.

Cluster manager có thể là:

  • Spark Standalone;
  • YARN;
  • Kubernetes;
  • local mode khi chạy trên máy mình.

Role của nó là cấp CPU/memory và launch executor cho application.

Flow đơn giản:

driver asks for resources
  -> cluster manager allocates executors
  -> executors start and connect back to driver
  -> driver sends tasks to executors

Cluster manager không quyết định query chạy thế nào. Nó cấp resource. Driver mới là nơi điều phối execution logic.

Transformations and Actions

Spark có một điểm hơi lạ lúc mới học: nhiều dòng code không chạy ngay.

Ví dụ:

df = spark.read.parquet("/data/events")
filtered = df.filter(df.country == "VN")
grouped = filtered.groupBy("city").count()

Các dòng này chủ yếu tạo ra một plan. Spark chưa nhất thiết chạy distributed computation ngay.

Đến khi gặp action như:

grouped.show()

Spark mới thật sự chạy job.

Một số action thường gặp:

  • show();
  • count();
  • collect();
  • take();
  • write / save;
  • saveAsTable().

Cách nhớ:

Transformation = mô tả muốn làm gì
Action         = bắt Spark thật sự chạy

Job, Stage, and Task

Khi action chạy, Spark tạo job.

Một job có thể được chia thành nhiều stage. Stage thường bị tách ra khi có shuffle, ví dụ groupBy, join, repartition.

Mỗi stage lại gồm nhiều task. Task thường tương ứng với một partition dữ liệu.

Action: show()
  -> Job
      -> Stage 1
          -> Task 1
          -> Task 2
          -> Task 3
      -> Stage 2
          -> Task 4
          -> Task 5

Ở mức mới học, chưa cần tối ưu vội. Chỉ cần nhớ thứ tự này để đọc Spark UI đỡ rối:

Application > Job > Stage > Task

A Simple Lifecycle

Ghép lại, một Spark application bình thường có lifecycle như sau:

spark-submit app.py
  -> driver process starts
  -> user code creates SparkSession
  -> SparkContext starts
  -> driver asks cluster manager for executors
  -> executors start
  -> action triggers job
  -> job is split into stages
  -> stages are split into tasks
  -> executors run tasks
  -> result/status goes back to driver
  -> application finishes
  -> SparkContext stops
  -> executors stop
  -> driver exits

Nếu chỉ nhớ một flow trong page này thì nhớ flow này.

Local Mode vs Cluster Mode

Khi mới học Spark, mình có thể chạy local mode:

pyspark
# hoặc
spark-submit --master local[*] app.py

Lúc này driver và executor-like worker threads có thể nằm trên cùng một máy. Nó tiện để học API và test logic.

Nhưng mental model vẫn nên giữ như cluster:

driver điều phối
worker/executor chạy task

Vì khi chuyển sang cluster thật, code vẫn dựa trên model đó, chỉ khác là executor chạy trên nhiều process/machine hơn.

What Happens When Something Fails?

Ở mức cơ bản, chỉ cần phân biệt hai loại failure.

Nếu executor chết:

  • task đang chạy trên executor đó fail;
  • driver có thể retry task trên executor khác;
  • cache/shuffle data trên executor đó có thể mất;
  • application chưa chắc chết ngay.

Nếu driver chết:

  • SparkContext mất;
  • scheduling state mất;
  • executors không còn nơi nhận lệnh;
  • application thường fail.

Cách nhớ:

Executor chết: mất worker, có thể retry.
Driver chết: mất đầu não của application.

What to Remember

Sau page này, tớ cần nhớ mấy ý:

  • Spark application là một lần chạy chương trình Spark.
  • Driver là process chính, giữ SparkContext và điều phối execution.
  • Executor là process worker, nhận task và xử lý dữ liệu.
  • Cluster manager cấp resource và launch executor.
  • Transformation thường lazy; action mới trigger computation.
  • Một action tạo job; job chia thành stage; stage chia thành task.
  • Executor failure có thể retry; driver failure thường làm application fail.

Next Questions

Sau khi hiểu lifecycle cơ bản, các câu hỏi tiếp theo nên là:

  • SparkSessionSparkContext khác nhau như thế nào?
  • DataFrame transformation được build thành plan ra sao?
  • Shuffle là gì và vì sao nó tạo stage boundary?
  • Partition ảnh hưởng thế nào tới số task?
  • Spark UI đọc như thế nào để hiểu application/job/stage/task?

On this page