برنامه نویسی تابعی (Functional Programming) در حال تبدیل شدن به الگوی تازه برای ساخت سیستم های پردازش کلان داده است، به عنوان مثال، چارچوب های اخیر مانند Spark و Flink هر دو از رابط های کاربردی برای تسهیل برنامه نویسان برای نوشتن برنامه های داده محور به روشی آسان کمک می گیرند. در این مدل برنامه نویسی، محاسبات و پردازش ها، به عنوان محاسبه و انجام تابع ها تلقی می شوند.

ویژگی های برنامه نویسی تابعی

برنامه نویسی اعلانی

برنامه‌نویسی اعلانی (Declarative Programming) یک پارادایم برنامه‌نویسی است که در آن منطق و هدف محاسبات بدون شرح چگونگی انجام آن‌ها بیان می‌شود. در این پارادایم تلاش می‌شود که با توصیف عملیات مورد نیاز بجای توضیح چگونگی انجام عملیات، اثر جانبی برنامه‌ها را کاهش یا به کل ازمیان برداشت که از لحاظ اولویت‌های عملیاتی در تناقض کامل با شیوه (برنامه‌نویسی دستوری )می‌باشد. (ویکی پدیا فارسی). بنابراین در در برنامه نویسی تابعی، توسعه دهندگان برنامه ها را با مشخص کردن منطق معنایی (Semantic Logic) محاسبات به جای جریان کنترل رویه ها، می سازند.

تابع ها

تابع ها، بنیاد و پایه در برنامه نویسی تابعی هستند. مقدمات برنامه نویسی، به شیوه تابع ها فراهم می شوند. ایده برنامه نویسی تابعی این است که یک تابع ورودی تابعی دیگر باشد. برای نمونه یک تابع دست نویس برنامه نویس، می تواند توابع دیگری را به عنوان ورودی دریافت کند. 

در برنامه نویسی تابعی اجازه اشتراک گذاری حالت ها (State) داده نمی شود، به این معنی که متغیرها در برنامه نویسی تابعی تغییر ناپذیر هستند. بنابراین، هیچ عوارض جانبی برای فراخوانی توابع وجود ندارد. این باعث می شود نوشتن برنامه های درست تابعی را ساده و آسان می کند. در برنامه نویسی تابعی، بسیاری از حلقه ها به صورت فراخوانی بازگشتی (Recursively Calling) نمایش داده می شوند.

موازی سازی

از آنجا که به طور کلی هیچ وضعیتی (State) در برنامه نویسی تابعی وجود ندارد،بنابراین می توانیم با استفاده از موازی سازی را بر روی زیر ساخت های چند هسته ای یا سیستم توزیع شده پیاده سازی کنیم. یک سیستم توزیع شده، دربرگیرنده چندین گره (سرور – واحدهای پردازشی) است که می توان یک کار سنگین را بر روی این سرورها توزیع کرد و هر واحد کوچکتر را به موازات یکدیگر انجام داد.

اسپارک چیست

اسپارک به برنامه نویسان یک الگوی برنامه نویسی تابعی با رابط های برنامه نویسی داده محور (Data Centric) مبتنی بر یک مدل داده درونی خود اسپارک به نام داده های توزیع شده انعطاف پذیر (Resilient Distributed Dataset یا RDD) می دهد. ساخت و توسعه اسپارک، در پاسخ به محدودیت های MapReduce است. چارچوب نگاشت کاهش، داده ها تکه تکه شده و بر روی سرورهایی توزیع می شوند و سپس به یک دنباله نگاشت دهنده (Mapper) و کاهش دهنده (Reducer) فرستاده می شوند.

API های اسپارک که برای همه توسعه دهندگان برنامه ها فراهم شده اند تا با به کارگیری از رابط های استاندارد API، برنامه های مبتنی بر Spark را بنویسند. API های اسپارک برای زبان های برنامه نویسی اسکالا ، جاوا ، آر (R) و پایتون فراهم شده اند. در کنار اینکه اسپارک از زبان های گوناگون پشتیبانی می کند، درون اسپارک یک پوسته به نام Read-Evaluate-Print-Loop (یا REPL) فراهم شده است.

اسپارک یک چارچوب نرم افزاری برای نوشتن برنامه های پردازش و تحلیل داده محور کلان داده است و در شکل زیر می توانید مولفه های گوناگون آن را ببینید. در این بخش برخی از مؤلفه های مهم اسپارک به همراه مکانیزم اجرای آنها توضیح داده می شود تا بتوانیم درک بهتری از کارکرد و ساخت برنامه های اسپاراک داشته باشیم.

درایور برنامه

پوسته اسپارک (Spark Shell) یکی از برنامه های درون اسپارک است. درایور برنامه (Driver Program) فرایندی است که درون JVM (یا Java Virtual Machine) و نقش آن، اجرای تابع های اصلی کاربران است. مولفه درایور برنامه، دارای یک شی درونی به نام SparkContext است که نقش آن برقراری ارتباط با کلاستر اسپارک است. یک برنامه اسپارک زمانی آغاز می شود که درایور برنامه آغاز شده باشد و زمانی پایان می یابد که درایور برنامه پایان یافته باشد. درایور اسپارک به کمک SparkContext، همه فرایندهای درون یک برنامه اسپارک را هماهنگ (Coordinates) می کند.

مجموعه داده های توزیع شده انعطاف پذیر

مجموعه داده های توزیع شده انعطاف پذیر (RDD یا Resilient Distributed Datasets) مجموعه ای از شی های توزیع شده غیر قابل تغییر (Immutable) است. RDD یک مرجع منطقی از یک مجموعه داده است که در بسیاری از دستگاه های سرور در کلاستر پارتیشین و پخش می شوند. RDD ها که مجموعه ای از اشیا هستند، غیر قابل تغییر و دارای قابلیت خود بازیابی (Self Recovery) در زمان ازکار افتادگی هستند. یک RDD اسپارک که مرجع منطقی به یک مجموعه داده ها است، می تواند از هر منبعی مانند فایل های متنی، CSV و پایگاه داده های رابطه ای به کمک JDBC و دیگر باشد.

پارتیشن های RDD

RDD می تواند مجموعه ای از داده های گوناگون باشد ولی این داده ها نمی توانند بر روی یک سرور باشند و از این رو باید بر روی چندین سرور پارتیشن و بخش شوند. هر چه شمار پارتیشن ها بیشتر، موازی سازی نیز بیشتر و از این رو پردازش داده ها تندتر انجام می شود. پارتیشن های RDD باید بر روی همه گره های درون شبکه توزیع شوند.

عملگرهای RDD

برای RDD دو گونه از عملگرها به نام Transformation و Action هست. عملگرهای Transformation، در برگیرنده تابع هایی هستند که به RDD اعمال می شوند و سپس یک RDD تازه ساخته می شود. با توجه به غیر قابل تغییر بودن RDD، با اعمال عملگرهای Transformation آن RDD تابع به آن اعمال شد تغییری نمی کند. در شکل زیر فهرست برخی از عملگرهای Transformation مانند map,filter, reduceByKey join, cogroup و randomSplit نشان داده شده است. بنابراین این عملگرها تنها یک RDD تازه می سازند.

در سطح بالا، دو دسته عملیات Transformation هست که می تواند بر روی RDD ها اعمال شوند، که ۱) تبدیل محدود (Narrow Transformation) و ۲) تبدیل گسترده (Wide Transformation) نام دارند. تحولات گسترده نام دارند. اساساً به مرزهای مرحله منجر می شود. در تبدیل های محدود، نیازی نیست که داده ها در بین پارتیشن ها جابجا شوند (Shuffled). برای نمونه می توان به تابع های ()map و ()filter اشاره کرد. در برابر این، تبدیل های گسترده، همانند تابع reduceByKey نیاز دارند تا تابع ها میان پارتیشن ها جابجا شوند.

پوسته اسپارک

پوسته اسپارک چیزی نیست جز رابط ارائه شده توسط زبان اسکالا و پایتون. به نظر می رسد بسیار همانند به هر پوسته تعاملی (Interactive Shell) دیگر باشد. پوسته اسپارک شی SparkContext دارد که اجازه می دهد کلاستر توزیع شده را بکار بگیرید. گفتیم که SparkContext شی Driver Program است که با کلاستر و در واقع با Cluster Manager ارتباط دارد. شما می توانید اسکریپت های پیچیده خود را قدم به قدم از طریق پوسته و بدون عبور از چرخه کامپایل-ساخت-اجرا، اجرا کنید.

SparkContext

SparkContext نقطه ورود موتور Spark core است. این شیء برای ایجاد و دستکاری RDD ها و ایجاد متغیرهای مشترک روی یک خوشه مورد نیاز است. شی SparkContext به یک مدیر کلاستر (Cluster Manager) متصل می شود ، که وظیفه تخصیص منابع را بر عهده دارد. اسپارک همراه با مدیر کلاستر مستقل (Standalone) خود است. از آنجایی که مدیر کلاستر یک عنصر قابل جابجایی در Spark است ، می توان آن را از طریق مدیران کلاسترها بیرونی مانند Apache Mesos یا YARN مدیریت کرد.

Worker Node

گره های کارگر (Worker Node) گره هایی هستند که کد برنامه را درون کلاستر اجرا می کنند و از درایور برنامه پیروی می کنند. در واقع کار واقعی بدست گره های کارگر اجرا می شود. هر گره (ماشین) درون کلاستر شاید دارای یک یا چند نمونه کارگر باشد ولی پیش فرض تنها یک گره کارگر است.

گره های کارگر دارای یک مؤلفه به نام مدیر بلاک (Block Manager) هستند، که نقش مدیریت بلاک های داده را بر عهده دارد. این بلاک ها را می توان داده های RDD کَش شده، داده های جابجا شده میانی (Intermediate Shuffled Data) یا داده های پخش شده فراگیر (Broadcast data) باشند. زمانی که حافظه اصلی (RAM۹ در دسترس نباشد، خودکار برخی از بلاک های داده را به دیسک منتقل می کند. تکثیر داده ها (Data Replication) در گره ها یکی دیگر از مسئولیت های مدیر بلاک است.

Executor ها

هر برنامه دارای مجموعه ای از فرآیندهای مجری (Executor) است. مجریان یا Executor ها در گره های کارگر ساکن شده و سر راست با درایور برنامه و به کمک مدیر کلاستر ارتباط برقرار می کنند. همه مجریان توسط SparkContext اداره می شوند. یک Executor، نمونه ای از JVM است که به عنوان یک تک برنامه اسپارک عمل می کند. نقش مجری، مدیریت محاسبات از کارها (Task ها)، انجام ذخیره سازی و کَش کردن بر روی هر گره کارگر است. همانگونه که در شکل بالا می بینید، یک Executor می تواند چندین Task (کار یا وظیفه) همزمان را انجام دهد.