۱. مقدمه: فراتر از سادگی ظاهری Serverless
رایانش بدون سرور (Serverless) با وعدههایی چون سادگی استفاده و صورتحساب مبتنی بر مصرف، دنیای توسعه نرمافزار را متحول کرده است. توسعهدهندگان دیگر نگران مدیریت سرورها نیستند و پلتفرمهای ابری این وظایف را به صورت خودکار انجام میدهند. این مدل برای اپلیکیشنهای ساده فوقالعاده کارآمد است. اما سالهاست که پاسخ صنعت به پیچیدگی اپلیکیشنهای serverless، افزودن یک لایه جدید بوده است: ارکستریتور مستقل.
اما اگر این راهحل نهتنها ناقص، بلکه اساساً غیرضروری و ناکارآمد باشد چه؟ وقتی صحبت از ساخت اپلیکیشنهای پیچیده با صدها فانکشن به هم پیوسته میشود، چالشها نمایان میشوند. برای حل این مشکل، سرویسهایی مانند AWS Step Functions معرفی شدند. اما پژوهشهای پیشگامانه نشان میدهند که کل این مدل ممکن است اشتباه باشد. این ارکستریتورها که برای حل مشکل آمده بودند، خود به گلوگاهی پنهان و پرهزینه تبدیل شدهاند.
این مقاله بر اساس یک رساله جامع، پنج نکته کلیدی و قدرتمند را آشکار میکند که رویکرد متداول به ارکستریشن (orchestration) را به چالش میکشد و راهکاری کارآمدتر، سریعتر و ارزانتر را پیش روی ما قرار میدهد.
۲. نکته اول: ارکستریتورهای مستقل، یک گلوگاه پنهان و پرهزینه هستند
معماری ارکستریتورهای مستقل ذاتاً یک بدهی فنی پنهان ایجاد میکند. این سرویسها با اینکه برای سادهسازی گردشکارها (workflows) طراحی شدهاند، محدودیتهای جدی در عملکرد، هزینه و انعطافپذیری به وجود میآورند.
پژوهشها سه مشکل اساسی را در این معماری شناسایی کردهاند:
- گلوگاههای عملکردی (Performance Bottlenecks): این سرویسها میتوانند عملکرد اپلیکیشنهای با موازیسازی بالا را محدود کنند. برای مثال، AWS Step Functions در الگوی
Mapخود، تعداد شاخههای همزمان را به ۴۰ عدد محدود میکند. این محدودیت، مقیاسپذیری اپلیکیشنهایی مانند پردازش ویدئو را که نیاز به هزاران پردازش موازی دارند، به شدت کاهش میدهد. - هزینههای بالا (High Costs): هزینه استفاده از ارکستریتورها به طرز شگفتآوری بالاست. در حالی که AWS Lambda برای هر یک میلیون فراخوانی فانکشن حدود ۰.۲ دلار هزینه دریافت میکند، AWS Step Functions برای هر یک میلیون «تغییر وضعیت» (state transition) حدود ۲۷.۴ دلار هزینه دارد. این تفاوت هزینه باعث میشود که در اپلیکیشنهای پیچیده، بخش عمدهای از هزینه نهایی مربوط به خود ارکستریتور باشد، نه اجرای واقعی کد.
- عدم انعطافپذیری (Lack of Flexibility): ارکستریتورها یک راهحل «یکسان برای همه» ارائه میدهند که مانع از بهینهسازیهای خاص اپلیکیشن میشود. برای مثال، اگر یک اپلیکیشن از فانکشنهای قطعی (deterministic) تشکیل شده باشد، نیازی به ضمانت اجرای «دقیقاً یکباره» (exactly-once) ندارد. اما ارکستریتورهای مستقل این سربار اضافی را تحمیل میکنند و به توسعهدهنده اجازه نمیدهند از این ویژگی برای افزایش سرعت و کاهش هزینه بهرهبرداری کند.
۳. نکته دوم: برای ارکستریشن به سرویس جدیدی نیاز ندارید؛ راهحل در خود اپلیکیشن است
ایده اصلی این پژوهش این است که ارکستریشن را میتوان از یک سرویس جداگانه به یک کتابخانه (library) منتقل کرد که درون خود فانکشنهای FaaS اجرا میشود. این رویکرد که «ارکستریشن در سطح اپلیکیشن» (application-level orchestration) نامیده میشود، نیازی به هیچ سرویس جدیدی از سوی ارائهدهنده ابر ندارد.
این مدل تنها با استفاده از دو API پایهای و موجود در تمام پلتفرمهای serverless کار میکند: فراخوانی فانکشن (function invocation) و عملیات پایه روی یک پایگاه داده (data store). به عبارت دیگر، هماهنگی بین فانکشنها به جای اینکه توسط یک کنترلر مرکزی مدیریت شود، به صورت غیرمتمرکز و توسط خود فانکشنها انجام میگیرد.
این رویکرد قدرتمند در مقدمه رساله به این صورت بیان شده است:
این رساله نشان میدهد که ارکستریتورهای مستقل اضافی برای اپلیکیشنهای بدون سرور غیرضروری هستند. علاوه بر این، ما استدلال میکنیم که ارکستریشن در سطح اپلیکیشن هم برای ارائهدهندگان ابر و هم برای توسعهدهندگان بهتر است.
تأثیر این تغییر نگرش بسیار عمیق است: این رویکرد پشته ابری (cloud stack) را سادهتر میکند و کنترل کامل را به توسعهدهنده بازمیگرداند.
۴. نکته سوم: ارکستریشن غیرمتمرکز، سریعتر و تا ۹ برابر ارزانتر است
وقتی ارکستریشن به سطح اپلیکیشن منتقل میشود، معیارهای کلیدی عملکرد و هزینه به شکل چشمگیری بهبود مییابند. سیستم پیادهسازیشده در این پژوهش با نام «Unum» این مزایا را به وضوح نشان میدهد.
بر اساس ارزیابیهای انجامشده، اپلیکیشنهایی که با Unum اجرا میشوند، بین ۱.۳۵ تا ۹ برابر ارزانتر از اجرای همان اپلیکیشنها روی AWS Step Functions هستند. در گردشکارهایی که به شدت موازی هستند، مانند اپلیکیشن Wordcount، سیستم Unum بیش از ۲ برابر سریعتر عمل میکند.
دلیل این صرفهجویی بزرگ در هزینهها، حذف «تغییرات وضعیت» پرهزینه ارکستریتور است. در Step Functions، این تغییرات وضعیت میتوانند تا ۹۹.۵٪ از کل هزینه را در برخی اپلیکیشنها تشکیل دهند. در مقابل، هزینههای Unum مستقیماً از سرویسهای ارزانتری مانند زمان اجرای Lambda و عملیات DynamoDB ناشی میشود که به مراتب بهینهتر هستند.
۵. نکته چهارم: انعطافپذیری، کلید دستیابی به عملکرد بالاتر است
ارکستریتورهای مستقل با ارائه الگوهای از پیش تعریفشده، انعطافپذیری را قربانی سادگی میکنند. این محدودیت میتواند به گلوگاههای عملکردی غیرمنتظره منجر شود. اپلیکیشن پردازش ویدئوی ExCamera یک مطالعه موردی عالی برای این موضوع است.
در AWS Step Functions، الگوی Map که برای پردازش موازی استفاده میشود، ایجاب میکند که تمام شاخههای موازی به پایان برسند تا مرحله بعدی (تجمیع نتایج یا fan-in) بتواند آغاز شود. این ویژگی عملاً بخشی از فرآیند را سریال میکند. برای مثال، یک وظیفه نمیتواند پردازش مرحله دوم خود را شروع کند مگر اینکه تمام وظایف دیگر پردازش مرحله اول خود را تمام کرده باشند، حتی اگر به نتیجه آنها نیازی نداشته باشد.
در مقابل، رویکرد Unum به توسعهدهنده اجازه میدهد منطق وابستگی سفارشی را پیادهسازی کند. هر وظیفه میتواند به محض آماده شدن وابستگیهای خاص خود شروع شود، بدون اینکه منتظر تکمیل سایر وظایف غیرمرتبط بماند. این انعطافپذیری به تنهایی باعث شد که پیادهسازی ExCamera با Unum ۱۶.۷٪ سریعتر از نسخه Step Functions باشد. این افزایش سرعت ۱۶.۷ درصدی، تنها یک بهینهسازی عملکردی نیست؛ بلکه نمایش دقیقی است از اینکه چگونه محدودیتهای ارکستریتورهای مستقل (نکته اول) به طور مستقیم به هزینههای بالاتر و کارایی پایینتر (نکته سوم) منجر میشود.
۶. نکته پنجم: هماهنگی پیچیده (Fan-in) بدون نیاز به یک هماهنگکننده مرکزی امکانپذیر است
یکی از بزرگترین چالشها در سیستمهای غیرمتمرکز، الگوی «fan-in» است: چگونه میتوان یک فانکشن را تنها پس از تکمیل موفقیتآمیز چندین فانکشن دیگر فراخوانی کرد، بدون اینکه یک کنترلر مرکزی منتظر همه آنها بماند؟
راهحل ارائهشده در این پژوهش، هوشمندانه و ساده است: استفاده از یک پایگاه داده با سازگاری قوی (strongly consistent data store) به عنوان نقطه هماهنگی. مکانیزم به این صورت عمل میکند:
۱. یک فضای مشترک (مثلاً یک “Set” در پایگاه داده) برای تمام شاخههای موازی ایجاد میشود. ۲. هر شاخه پس از اتمام کارش، وضعیت تکمیل خود را در این Set ثبت میکند. ۳. هر شاخهای که Set را بهروز میکند، اندازه آن را نیز بررسی میکند. شاخهای که متوجه میشود Set کامل شده است (یعنی همه شاخهها کارشان را تمام کردهاند)، مسئولیت فراخوانی فانکشن نهایی (aggregation function) را بر عهده میگیرد.
این راهکار نه تنها هوشمندانه است، بلکه اثبات میکند که پیچیدهترین الگوهای هماهنگی را میتوان با استفاده از همان دو جزء اصلی serverless—فراخوانی فانکشن و پایگاه داده—پیادهسازی کرد و به هیچ سرویس اضافهای نیاز نیست.
۷. نتیجهگیری: آیا باید در مورد افزودن سرویسهای جدید به ابر تجدیدنظر کنیم؟
شواهد روشن است: با گنجاندن ارکستریشن در خود اپلیکیشن، سیستمهایی سریعتر، ارزانتر و انعطافپذیرتر میسازیم. چالش پیش روی معماران ابر و ارائهدهندگان دیگر این نیست که چه چیزی بسازند، بلکه چگونه بسازند. ما باید در برابر تمایل پیشفرض به افزودن سرویسهای مدیریتشده بیشتر مقاومت کنیم و در عوض، پتانسیل عظیم و دستنخوردهای را که در اجزای اصلی serverless که از قبل در اختیار داریم نهفته است، آزاد کنیم.