الگوی راکتور(Reactor pattern)

الگوی طراحی نرم‌افزار راکتور یک استراتژی مدیریت رویداد است که می‌تواند به بسیاری از درخواست‌های خدمات بالقوه به‌طور همزمان پاسخ دهد. مؤلفه کلیدی الگو یک حلقه رویداد است که در یک رشته یا فرایند اجرا می‌شود، که درخواست‌های دریافتی را از هم جدا می‌کند و آنها را به کنترل‌کننده درخواست صحیح ارسال می‌کند.

یک راکتور با تکیه بر مکانیسم های مبتنی بر رویداد به جای مسدود کردن I / O یا Multi Threading، می تواند بسیاری از درخواست های همزمان I / O محدود را با کمترین تاخیر انجام دهد. یک راکتور همچنین اجازه می دهد تا به راحتی روال های رسیدگی کننده درخواست های خاص را اصلاح یا گسترش دهد، اگرچه این الگو دارای اشکالات و محدودیت هایی است.

با تعادل سادگی و مقیاس پذیری، راکتور به یک عنصر معماری مرکزی در چندین برنامه کاربردی سرور و چارچوب های نرم افزاری برای شبکه تبدیل شده است. مشتقاتی مانند مولتی راکتور و پرواکتور نیز برای موارد خاصی وجود دارد که در آن توان عملیاتی، عملکرد یا پیچیدگی درخواست بیشتر ضروری است.

## بررسی اجمالی
ملاحظات عملی برای مدل مشتری-سرور در شبکه های بزرگ، مانند مشکل C10k برای وب سرورها، انگیزه اصلی برای الگوی راکتور بود.

یک رویکرد ساده‌لوحانه برای رسیدگی به درخواست‌های سرویس از بسیاری از نقاط پایانی بالقوه، مانند سوکت‌های شبکه یا توصیف‌کننده‌های فایل، گوش دادن به درخواست‌های جدید از درون یک حلقه رویداد، سپس خواندن سریع‌ترین درخواست است. هنگامی که کل درخواست خوانده شد، می توان آن را با تماس مستقیم با کنترل کننده مربوط پردازش و ارسال کرد. یک سرور کاملاً "تکرار شونده" مانند این، که یک درخواست را از شروع تا پایان در هر تکرار حلقه رویداد رسیدگی می کند، منطقا معتبر است. با این حال، زمانی که چندین درخواست را به صورت متوالی دریافت کند، عقب خواهد ماند. رویکرد تکراری نمی تواند مقیاس شود زیرا خواندن درخواست تنها رشته سرور را تا زمانی که درخواست کامل دریافت کند مسدود می کند و عملیات I / O معمولاً بسیار کندتر از سایر محاسبات است.

یک استراتژی برای غلبه بر این محدودیت، چند رشته ای است: با تقسیم فوری هر درخواست جدید به رشته کارگر خود، اولین درخواست دیگر حلقه رویداد را مسدود نمی کند، که می تواند بلافاصله درخواست دیگری را تکرار کرده و رسیدگی کند. این طرح «رشته در هر اتصال» نسبت به طرحی کاملاً تکراری مقیاس‌پذیرتر است، اما همچنان شامل ناکارآمدی‌های متعدد است و از یک نقطه عبور می‌کند. از نقطه نظر منابع سیستم زیربنایی، هر رشته یا فرایند جدید هزینه‌های سربار را در حافظه و زمان پردازش (به دلیل تغییر زمینه) تحمیل می‌کند. ناکارآمدی اساسی هر رشته ای که در انتظار اتمام I / O است نیز حل نشده است.

از نقطه نظر طراحی، هر دو رویکرد، مالتی پلکسر عمومی را با کنترل‌کننده‌های درخواست خاص نیز پیوند می‌دهند، و تغییر کد سرور را شکننده و خسته‌کننده می‌سازد. این ملاحظات چند تصمیم اصلی طراحی را نشان می دهد:

#   یک کنترل کننده رویداد تک رشته ای را حفظ کنید. چند رشته ای بدون حل مشکل واقعی مسدود کردن ورودی / خروجی، سربار و پیچیدگی را معرفی می کند.
#   از مکانیزم اعلان رویداد برای درخواست‌های دی مولتیپلکس فقط پس از تکمیل I / O استفاده کنید. (بنابراین I / O عملاً مسدود نمی‌شود)
#   برای تفکیک بهتر نگرانی‌ها، کنترل‌کننده‌های بازخوانی را به‌عنوان تماس‌های برگشتی با مدیریت رویداد ثبت کنید.

ترکیب این بینش ها منجر به الگوی راکتور می شود که مزایای تک رشته با توان عملیاتی و مقیاس پذیری بالا را متعادل می کند.

## استفاده
الگوی راکتور می تواند نقطه شروع خوبی برای هر مشکل همزمان و مربوط به رویداد باشد. این الگو به سوکت های شبکه نیز محدود نمی شود. ورودی / خروجی سخت‌افزار، دسترسی به سیستم فایل یا پایگاه داده، ارتباط بین پردازشی و حتی سیستم‌های ارسال پیام انتزاعی همگی موارد استفاده ممکن هستند.

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

Single-threading همچنین می تواند در موارد استفاده ای که به حداکثر توان عملیاتی نیاز دارند یا زمانی که درخواست ها شامل پردازش قابل توجهی می شوند، به یک اشکال تبدیل شود. طرح‌های چند رشته‌ای مختلف می‌توانند بر این محدودیت‌ها غلبه کنند، و در واقع، برخی هنوز از الگوی راکتور به عنوان یک جزء فرعی برای مدیریت رویدادها و I / O استفاده می‌کنند.

### برنامه های کاربردی
الگوی راکتور (یا گونه‌ای از آن) در بسیاری از وب سرورها، سرورهای کاربردی و چارچوب‌های شبکه جای خود را پیدا کرده است:

* محیط ارتباطی تطبیقی
* رویداد ماشین
* نتی
* Nginx
* Node.js
* محیط شیء پرل
* کتابخانه های ++POCO C
* Spring Framework (نسخه 5 به بعد)
* Twisted
* Vert.x

## ساختار
یک برنامه واکنشی از چندین بخش متحرک تشکیل شده است و به برخی مکانیسم های پشتیبانی متکی است:

#### رسیدگی
  یک شناسه و رابط برای یک درخواست خاص، با IO و داده. این اغلب به شکل سوکت، توصیفگر فایل یا مکانیزم مشابه است که باید توسط اکثر سیستم عامل های مدرن ارائه شود.

#### تقسیم کننده
  یک اعلان کننده رویداد که می تواند به‌طور مؤثر وضعیت یک دسته را نظارت کند، سپس سایر زیرسیستم ها را از تغییر وضعیت مربوط مطلع کند (معمولاً یک دسته IO "آماده خواندن" می شود). به‌طور سنتی این نقش با فراخوانی سیستم () انتخاب می‌شد، اما نمونه‌های امروزی‌تر شامل epoll، kqueue و IOCP است.

#### دیسپچر
  حلقه رویداد واقعی برنامه واکنش‌گرا، این مؤلفه رجیستری کنترل‌کننده‌های رویداد معتبر را حفظ می‌کند، سپس هنگامی که رویدادی مطرح می‌شود، کنترل‌کننده مناسب را فراخوانی می‌کند.

#### مدیریت رویداد
  که به عنوان کنترل کننده درخواست نیز شناخته می شود، این منطق خاص برای پردازش یک نوع درخواست خدمات است. الگوی راکتور پیشنهاد می کند که اینها را به صورت پویا با دیسپاچر به عنوان تماس برگشتی برای انعطاف پذیری بیشتر ثبت کنید. به‌طور پیش فرض، یک راکتور از چند رشته استفاده نمی کند بلکه یک کنترل کننده درخواست را در همان رشته ای فراخوانی می کند که توزیع کننده است.

#### رابط مدیریت رویداد
  یک کلاس واسط انتزاعی که ویژگی ها و روش های کلی یک کنترل کننده رویداد را نشان می دهد. هر کنترل کننده خاص باید این رابط را پیاده سازی کند در حالی که توزیع کننده از طریق این رابط روی کنترل کننده های رویداد کار می کند.

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

یکی از اصلاحات اساسی این است که برای همزمانی بیشتر، کنترل‌کننده‌های رویداد را در رشته‌های خودشان فراخوانی کنیم. اجرای هندلرها در یک استخر نخ، به جای چرخاندن رزوه های جدید در صورت نیاز، باعث ساده تر شدن بیشتر رشته ها و به حداقل رساندن سربار می شود. این موضوع باعث می شود که در بسیاری از موارد استفاده از استخر نخ مکملی طبیعی برای الگوی راکتور باشد.

یکی دیگر از راه‌های به حداکثر رساندن توان عملیاتی این است که تا حدودی رویکرد سرور «رشته در هر اتصال» را مجدداً معرفی کنید، با حلقه‌های توزیع‌کننده  /  رویداد تکراری که همزمان اجرا می‌شوند. با این حال، به جای تعداد اتصالات، تعداد دیسپاچر را برای مطابقت با هسته‌های CPU موجود سخت‌افزار اصلی پیکربندی می‌کند.

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

برای خدمات به خصوص پیچیده، که در آن نیازهای همزمان و ناهمزمان باید با هم ترکیب شوند، یکی دیگر از گزینه‌های الگوی پرواکتور است. این الگو از یک راکتور پیچیده تر است، با جزئیات مهندسی خاص خود، اما همچنان از یک جزء فرعی راکتور برای حل مشکل مسدود کردن IO استفاده می کند.

## همچنین ببینید

* مشکل C10k
*   برنامه نویسی رویداد محور
*   ورودی/خروجی
*   آزاد
*   برنامه نویسی واکنشی

#### الگوهای مرتبط:

* شیء فعال
*   الگوی ناظر
*   الگوی پرواکتور، که امکان اختلاط همزمان را فراهم می کند.

## یادداشت
گفته می‌شود، یک قانون سرانگشتی در طراحی نرم‌افزار این است که اگر تقاضای برنامه‌ها به‌طور بالقوه بتواند از حد مفروض گذشته افزایش یابد، باید انتظار داشت که روزی افزایش یابد.

## منابع

# Schmidt, Douglas C. (1995). "Chapter 29: Reactor: An Object Behavioral Pattern for Demultiplexing and Dispatching Handles for Synchronous Events" (PDF). In Coplien, James O. (ed.). Pattern Languages of Program Design. Vol. 1 (1st ed.). Addison-Wesley. ISBN 9780201607345.
# Devresse, Adrien (20 June 2014). "Efficient parallel I/O on multi-core architectures" (PDF). 2nd Thematic CERN School of Computing. CERN. Archived (PDF) from the original on 8 August 2022. Retrieved 14 September 2023.
# Escoffier, Clement; Finnegan, Ken (November 2021). "Chapter 4. Design Principles of Reactive Systems". Reactive Systems in Java. O'Reilly Media. ISBN 9781492091721.
# Garrett, Owen (10 June 2015). "Inside NGINX: How We Designed for Performance & Scale". NGINX. F5, Inc. Archived from the original on 20 August 2023. Retrieved 10 September 2023.
# Kegel, Dan (5 February 2014). "The C10k problem". Dan Kegel's Web Hostel. Archived from the original on 6 September 2023. Retrieved 10 September 2023.
# Bonér, Jonas (15 June 2022). "The Reactive Patterns: 3. Isolate Mutations". The Reactive Principles. Retrieved 20 September 2023.
# "Network Programming: Writing network and internet applications" (PDF). POCO Project. Applied Informatics Software Engineering GmbH. 2010. pp.&nbsp;21–22. Retrieved 20 September 2023.
# Stoyanchev, Rossen (9 February 2016). "Reactive Spring". Spring.io. Retrieved 20 September 2023.

رده:رایانش همروند
رده:رویدادها (رایانش)
رده:الگوهای طراحی نرم‌افزار