وقتی دربارهی Apache Spark صحبت میکنیم، درواقع دربارهی یک «موتور پردازش توزیعشده» حرف میزنیم که آمده است محدودیتهای پردازش کلسترهای بزرگ را ساده کند. اسپارک مثل یک کارخانه عظیم است: شما یک سفارش (برنامه) تحویلش میدهید، خودش مواد خام را در واحدهای مختلف تقسیم میکند، هر واحد را مسئول بخشی از کار میکند، جریان کار را مدیریت میکند، خروجیها را ترکیب میکند و نتیجه نهایی را پس میدهد. همین معماری ماژولار و توزیعشده است که باعث شده اسپارک در مقیاس ترابایتی و پتابایتی همچنان سریع، پایدار و قابل مدیریت بماند.

برای اینکه بفهمیم اسپارک چگونه یک برنامه را اجرا میکند، باید با سلسلهمراتب اجرای آن آشنا شویم. این چهار لایه به شما کمک میکنند بدانید اسپارک چطور کار را مرحلهبهمرحله خرد کرده و روی کلاستر اجرا میکند.
همان کدی است که شما مینویسید و اجرا میکنید.
مثلاً یک اسکریپت پایتون یا برنامه اسکالا که در آن یک SparkSession ساختهاید.
در اسپارک تا زمانی که اکشن اجرا نشود، کاری انجام نمیشود (Lazy Evaluation).
هر وقت یکی از اکشنها مثل:count()، show()، collect()، write()
صدا زده شود، اسپارک یک Job جدید میسازد.
count() بزنید، سه Job ساخته میشود.هر Job به چند Stage تقسیم میشود.
هر Stage شامل چندین Task است.
Task کوچکترین بخش قابل اجرای یک Job است.
Taskها همان بخشهایی هستند که روی Executorها اجرا میشوند.
Task: کارهای ریز که روی پارتیشنها اجرا میشوند
App: کل برنامه شما
Job: هر بار که یک اکشن اجرا میکنید
Stage: بخشهای داخلی هر Job

from pyspark.sql import SparkSession
spark = SparkSession.builder \
.appName("HierarchyExample") \
.getOrCreate()
df = spark.read.csv("sales.csv", header=True, inferSchema=True)
# Job 1
count_all = df.count()
# Job 2
avg_price = df.groupBy("product_id").avg("price").count()
spark.stop()
| بخش | توضیح |
|---|---|
| Application | کل اسکریپت |
| Job 1 | دستور count |
| Job 2 | groupBy + avg + count |
| Stageها | جاب ۱، یک استیج و جاب ۲ حداقل ۲ استیج |
| Taskها | برابر با تعداد پارتیشنها |
Driver همان جایی است که برنامهٔ اسپارک شما اجرا میشود.
وقتی کد اسپارک را run میکنید، اولین چیزی که ساخته میشود Driver است.
Driver نقش «مغز برنامه» را دارد.
Driver خودش پردازش سنگین روی داده انجام نمیدهد؛
تنها هماهنگکننده و برنامهریز عملیات است.
در Spark 4 و Spark Connect، Driver میتواند از کلاینت جدا باشد،
اما نقش آن همان «فرمانده کل عملیات» باقی میماند.
Master در حالت Standalone یا Docker، مسئول مدیریت منابع است.
Master هیچ پردازش دادهای انجام نمیدهد.
Worker همان ماشین (یا کانتینر) است که کارهای واقعی روی آن انجام میشود.
یک Worker میتواند چندین Executor همزمان داشته باشد.
تشبیه:
Executor فرآیند اجرایی داخلی است که روی Worker قرار دارد.
تمام پردازش سنگین در Executor انجام میشود.
| بخش | نقش |
|---|---|
| Driver | تحلیل برنامه، ساخت Job/Stage/Task، ارسال کار |
| Master | مدیریت منابع، زمانبندی، هماهنگی |
| Worker | میزبانی Executorها |
| Executor | اجرای واقعی Taskها روی دادهها |

به ازای هر اکشن، گراف پردازش داده از اولین RDD تا حصول نتیجه، ایجاد شده و به ازای هر بخشی از گراف پیشنیازی وظایف (DAG) که امکان موازی سازی و توزیع در شبکه را داشته و منتظر نتایج مراحل قبل نیست، یک Stage تعریف میشود. در مورد RDD ها در ادامه صحبت میکنیم اما به طور خلاصه،
هر دادهای که قرار است پردازش شود، در اسپارک تبدیل به موجودیتی می شود با نام RDD که این RDD مجموعه ای است از پارتیشنهای داده و در کل کلاستر اسپارک بین اجرا کنندهها توزیع میشود. تمام پردازشها روی یک RDD که در کل کلاستر توزیع شده است انجام می شود و یکی از بنیادی ترین مفاهیم اسپارک است.

هر دیتایی که می خواهیم پردازش کنیم، ابتدا در قالب یک RDD اولیه توسط اسپارک بارگذاری می شود و سپس مجموعه ای از تبدیل ها روی آن انجام می شود. هر تبدیل یا پردازش، نسخه جدیدی از RDD را در حافظه ایجاد میکند. تا نهایتا به یک اکشن برسیم و نتیجه را به کاربر برگردانیم یا در دیتابیس یا فایل ذخیره کنیم. بنابراین هر جاب ما در اسپارک، مجموعه ای از RDD ها و تبدیلات انجام گرفته روی آنها و نهایتا ایجاد نتیجه نهایی (اکشن) است. گراف پردازش کارها در اسپارک، ترتیب این کارها و تسک های لازم برای پردازش ها را مشخص میکند.

DAG یک Directed Acyclic Graph است:
Driver با ساخت DAG میتواند برنامه را بهینه، موازی و مرحلهبهمرحله اجرا کند.

وقتی یک برنامهٔ اسپارک نوشته میشود، سیستم آن را فوراً اجرا نمیکند. ابتدا باید بفهمد چه عملیاتی باید انجام شود و سپس تصمیم بگیرد چگونه آن عملیات را با بهترین روش اجرا کند.
این فرآیند تحلیل و برنامهریزی توسط Driver انجام میشود؛ بخشی که نقش مغز و هماهنگکنندهٔ کل برنامه را دارد.
Logical Plan نمایش مفهومی و منطقی عملیات است. این بخش فقط توضیح میدهد که شما چه میخواهید، بدون اینکه هنوز روش اجرای آن مشخص شده باشد.
Logical Plan شامل دو مرحله است:
در این مرحله اسپارک هنوز ستونها، جداول یا منابع را دقیقاً نمیشناسد.
این طرح بیشتر شبیه یک نقشهٔ خام است.
بعد از بررسی Schema و متادیتا، تمام ارجاعات شفاف میشوند و اسپارک میفهمد هر ستون و هر منبع از کجاست.
اما همچنان این مرحله غیر اجرایی است و فقط توصیفی.
بعد از کامل شدن پلن منطقی، Driver تصمیم میگیرد بهترین روش برای اجرای عملیات چیست.
در Physical Plan تمام جزئیات اجرایی مشخص میشود.
Physical Plan همان طرح واقعی است که بعداً به Stage و Task تبدیل میشود و وارد اجرای واقعی میگردد.
Driver تمامی مراحل برنامهریزی و هماهنگی را مدیریت میکند:
Driver برنامهریز، هماهنگکننده و کنترلکنندهٔ کل چرخهٔ اجراست، و Executorها بخش عملیاتی را انجام میدهند.
| مرحله | مسئولیت | توضیح |
|---|---|---|
| Logical Plan | Driver | درک عملیات و توصیف آن بدون تصمیم اجرایی |
| Resolved Logical | Driver | تطبیق طرح با Schema و تکمیل جزئیات منطقی |
| Physical Plan | Driver | تعیین روش اجرای واقعی |
| Stage / Task | Driver | خرد کردن عملیات به واحدهای قابل اجرا |
| Executor | اجرای واقعی | اجرای Taskها روی پارتیشنها |
| Master | مدیریت منابع | ایجاد Executor بر اساس درخواست Driver |

Shuffling زمانی رخ میدهد که برای ادامهٔ یک عملیات، رکوردهای مربوط به یک کلید خاص باید کنار هم قرار بگیرند؛ اما این رکوردها در حال حاضر روی چند Executor (و معمولاً روی چند Worker) پخش شدهاند.
در این صورت اسپارک مجبور میشود دادهها را بین Executorها و در صورت نیاز بین نودها جابهجا کند.
این جابهجایی همان Shuffling است.
فرض کنید میخواهیم کمترین مقدار یک ستون را پیدا کنیم.
هیچ نیازی به جابهجایی دادهها بین Executorها یا Workerها نیست؛
بنابراین Shuffle اتفاق نمیافتد و عملیات بسیار سریع است.
حالا فرض کنید میخواهیم میانگین فروش هر کالا را محاسبه کنیم.
بنابراین اسپارک مجبور میشود:
حتی اگر چند Executor روی یک Worker باشند، باز هم Shuffle بین آنها انجام میشود.
در این حالت Shuffle به صورت Local (داخل همان ماشین) است،
هزینهٔ آن کمتر از Shuffle بین Workerهای مختلف است اما هنوز شامل I/O و مرتبسازی فایلهای موقت میشود.
این بازتوزیع دادهها همان Shuffle است.
به همین دلیل همیشه تلاش میکنیم تعداد Shuffle را تا حد ممکن کم کنیم، مثلاً با:
| حالت | آیا Shuffle رخ میدهد؟ | توضیح |
|---|---|---|
| یک Executor روی Worker | فقط بین Workerها در صورت نیاز | Shuffle شبکهای کامل |
| چند Executor روی یک Worker | بله، به صورت Local | Shuffle داخل همان ماشین، هزینه کمتر ولی شامل I/O است |
| رکوردهای پراکنده بین Workerها | بله | پرهزینهترین حالت، نیازمند شبکه و دیسک |
فرض کنید:
مثال برنامه:
from pyspark.sql import SparkSession
spark = SparkSession.builder \
.appName("DataJourney") \
.getOrCreate()
df = spark.read.csv("sales.csv", header=True, inferSchema=True)
df.createOrReplaceTempView("sales")
result = spark.sql("""
SELECT product_id, AVG(price) AS avg_price
FROM sales
GROUP BY product_id
""")
result.show()
وقتی دستور SparkSession.builder.getOrCreate() اجرا میشود:
برای هر Worker، میتوان مشخص کرد:
spark.executor.cores)spark.executor.memory)مثال:
| Worker | CPU | RAM | Executor | RAM/Executor | Core/Executor |
|---|---|---|---|---|---|
| Worker1 | ۸ | 16GB | ۲ | 8GB | ۴ |
| Worker2 | ۸ | 16GB | ۲ | 8GB | ۴ |
این تنظیمات تضمین میکند که هر Executor منابع کافی داشته باشد و چندین Task بتوانند بهصورت موازی اجرا شوند.
وقتی فایل CSV خوانده میشود:
df = spark.read.csv("sales.csv", header=True)
spark.sql.files.maxPartitionBytes تقسیم میشود (مثلاً 128MB)هر Task یک بخش از پارتیشن دادهها را پردازش میکند و در نهایت Driver نتیجه نهایی را جمعآوری میکند.
در مثال ما:
SELECT product_id, AVG(price)
FROM sales
GROUP BY product_id
product_id ممکن است روی چندین Executor پخش شده باشندنکته: بازتوزیع دادهها پرهزینه است، زیرا دادهها ممکن است بین Executorها حرکت کنند. به همین دلیل در طراحی کوئریها همیشه سعی میکنیم از بازتوزیع غیرضروری جلوگیری کنیم.
سفر داده در این مثال به صورت خلاصه:
معماری اسپارک بر پایه تفکیک وظایف بین چند جزء کلیدی طراحی شده است تا پردازش دادهها بهصورت توزیعشده و مقیاسپذیر انجام شود. Driver مغز برنامه است که کد شما را تحلیل کرده، Logical و Physical Plan میسازد، آن را به Stage و Task تقسیم میکند و پس از آماده شدن Executorها، نتایج را جمعآوری میکند. Master مدیر منابع کلاستر است و وظیفه تخصیص CPU و RAM، زمانبندی Taskها و نظارت بر Workerها را بر عهده دارد.
Workerها ماشینهایی هستند که منابع واقعی پردازشی را فراهم میکنند و میزبان یک یا چند Executor هستند. Executorها Taskها را اجرا میکنند، دادههای کش و فایلهای Shuffle را مدیریت میکنند و نتایج را به Driver میفرستند. اجرای برنامه از Application → Job → Stage → Task پیروی میکند و هنگام نیاز به کنار هم جمع شدن دادهها بین Executorها یا Workerها، Shuffle اتفاق میافتد که پرهزینهترین مرحله است و معمولاً گلوگاه عملکرد اسپارک محسوب میشود.
🎬 محتوای ویدئویی : مفاهیم پایه اسپارک – بخش اول، معماری و جایگاه اسپارک
در بخش زیر، مفاهیم پایه اسپارک به صورت یک ویدئو آموزشی همراه با اسلایدهای مناسب ارائه شده است تا به شما کمک کند به شکل تصویری و مرحلهای با اصول اولیه، اصطلاحات کلیدی و نقش اسپارک در پردازش داده آشنا شوید.
⚠️ نکته: اگر ویدئو در قسمت زیر برای شما بارگذاری یا نمایش داده نمیشود، ابتدا مطمئن شوید که با آیپی ایران صفحه را مشاهده میکنید (فیلترشکن خاموش باشد) و در صورت نیاز، یک اینترنت پروایدر دیگر را امتحان کنید.