دسته بندی:

مفهوم MPM در Apache و انتخاب آن

مفهوم MPM در Apache و انتخاب آن

حدود ۷ دقیقه مطالعه

MPM یا Multi-Processing Module بخشی از هسته آپاچی است که تعیین می‌کند وب‌سرور چگونه اتصال‌های شبکه را بپذیرد و هر درخواست را به کدام پردازه یا نخ بسپارد. در هر لحظه فقط یک MPM می‌تواند فعال باشد و انتخاب بین prefork، worker و event مستقیماً روی مصرف رم و تعداد کاربر هم‌زمانی که سرور تحمل می‌کند اثر می‌گذارد؛ روی سرورهای امروزی که PHP با PHP-FPM اجرا می‌شود، event گزینه درست و متداول است.

MPM دقیقاً چه کاری انجام می‌دهد

آپاچی معماری ماژولار دارد، اما MPM یک ماژول معمولی مثل mod_rewrite نیست؛ لایه‌ای است که به پورت گوش می‌دهد، اتصال ورودی را می‌پذیرد و آن را به یک واحد پردازشی تحویل می‌دهد. چون هر سه MPM دقیقاً همین یک وظیفه را به روش‌های متفاوت انجام می‌دهند، فعال بودن هم‌زمان دو تای آن‌ها بی‌معنی است. به همین دلیل هم تنظیمات کارایی آپاچی مثل MaxRequestWorkers یا ThreadsPerChild به MPM فعال وابسته‌اند و با تعویض MPM باید بازبینی شوند.

سه MPM آپاچی و تفاوت واقعی آن‌ها

prefork

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

worker

مدل ترکیبی است: چند پردازه فرزند و داخل هر پردازه چند نخ. هر نخ یک اتصال را مدیریت می‌کند، پس برای پذیرش همان تعداد کاربر به پردازه‌های به‌مراتب کمتری نیاز است و مصرف رم پایین می‌آید. ایراد باقی‌مانده این است که نخ تا وقتی اتصال keep-alive باز است مشغول می‌ماند، حتی اگر کاربر هیچ درخواستی نفرستد.

event

همان ساختار worker است با یک تفاوت مهم: نخ جداگانه‌ای اتصال‌های بی‌کار و در حالت keep-alive را نگه می‌دارد و نخ‌های کارگر را آزاد می‌کند تا سراغ درخواست‌های جدید بروند. نتیجه این است که با همان مقدار رم، تعداد اتصال هم‌زمان بسیار بیشتری را پاسخ می‌دهید. از آپاچی ۲.۴ به بعد این MPM حالت آزمایشی ندارد و انتخاب پیش‌فرض بیشتر توزیع‌های امروزی است.

MPM مدل مصرف رم مناسب برای
prefork یک پردازه برای هر اتصال بالا وقتی mod_php یا ماژول غیر thread-safe دارید
worker پردازه + نخ متوسط ترافیک بالا بدون mod_php
event پردازه + نخ + مدیریت جدا keep-alive پایین حالت پیشنهادی همراه PHP-FPM

سه مدل پردازش همزمان در آپاچی⁦prefork⁩هر اتصال یک پروسه کامل؛ بیشترین مصرف رم، لازم برای mod_php⁦proc⁩⁦⁩⁦proc⁩⁦⁩⁦proc⁩⁦⁩⁦proc⁩⁦⁩⁦proc⁩⁦⁩⁦proc⁩⁦⁩⁦worker⁩چند نخ داخل هر پروسه؛ رم کمتر برای همان تعداد اتصال⁦proc⁩⁦proc⁩⁦proc⁩⁦event⁩نخ‌ها با اتصال‌های در حال انتظار درگیر نمی‌مانند؛ انتخاب پیش‌فرض امروز⁦proc + event loop⁩⁦proc + event loop⁩اگر PHP را با mod_php اجرا کنید مجبورید روی prefork بمانید؛با انتقال به PHP-FPM آزاد می‌شوید که event را فعال کنید وبا همان مقدار رم، اتصال‌های همزمان بیشتری را پاسخ دهید.سقف تعداد پروسه و نخ را هم بر اساس رمی که واقعاً داریدتنظیم کنید، نه بر اساس عددهای پیش‌فرض

هرچه از prefork به سمت event بروید، برای همان تعداد اتصال همزمان رم کمتری لازم است؛ تنها چیزی که شما را به prefork زنجیر می‌کند، اجرای PHP به شکل mod_php است.

چطور بفهمیم کدام MPM فعال است

روی سرورهای مبتنی بر RHEL، CentOS، AlmaLinux و همچنین سرورهای cPanel:

  • httpd -V | grep -i "Server MPM"
  • httpd -M | grep mpm

روی دبیان و اوبونتو:

  • apache2ctl -V | grep -i "Server MPM"
  • apache2ctl -M | grep mpm

خروجی خطی مثل Server MPM: event یا mpm_prefork_module (shared) به شما می‌گوید کدام حالت فعال است. اگر همین حالا PHP را هم بررسی می‌کنید، دستور php -i | grep "Server API" نشان می‌دهد PHP به‌صورت Apache 2.0 Handler اجرا می‌شود یا FPM/FastCGI؛ ریشه این نام‌ها به استاندارد قدیمی CGI برمی‌گردد که همین امروز هم پایه اجرای اسکریپت روی وب‌سرور است. انتخاب خود وب‌سرور هم مسئله جداگانه‌ای است و آپاچی را در مقایسه وب‌سرورهای Apache، LiteSpeed، Nginx و IIS کنار رقبایش گذاشته‌ایم.

اگر سرویس شما هاست اشتراکی است این دستورها در دسترس شما نیستند؛ MPM تنظیمی در سطح کل سرور است و از کنترل‌پنل کاربر تغییر نمی‌کند. انتخاب و تعویض MPM فقط روی سروری معنا دارد که دسترسی روت آن در اختیار خودتان باشد.

چرا mod_php شما را به prefork زنجیر می‌کند

وقتی PHP به شکل ماژول داخلی آپاچی (mod_php) اجرا شود، مفسر PHP داخل خود پردازه آپاچی زندگی می‌کند. بسیاری از افزونه‌های PHP و کتابخانه‌های سیستمی که به آن‌ها لینک می‌شوند thread-safe نیستند و اجرایشان داخل یک MPM نخ‌محور می‌تواند به خطاهای تصادفی و کرش منجر شود؛ به همین دلیل mod_php فقط با prefork توصیه می‌شود.

PHP-FPM این گره را باز می‌کند. در این مدل PHP در یک سرویس کاملاً جدا اجرا می‌شود و آپاچی از طریق mod_proxy_fcgi درخواست را به آن می‌سپارد. حالا آپاچی دیگر درگیر thread-safe بودن PHP نیست و می‌توانید سراغ event بروید؛ ضمن اینکه تعداد پردازه‌های PHP را مستقل از اتصال‌های وب تنظیم می‌کنید.

تغییر MPM در عمل

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

روی دبیان و اوبونتو، ابتدا اگر mod_php فعال است آن را غیرفعال و PHP-FPM را جایگزین کنید (شماره نسخه را با نسخه نصب‌شده خودتان عوض کنید):

  • a2dismod php8.1
  • a2enmod proxy_fcgi setenvif
  • a2enconf php8.1-fpm
  • a2dismod mpm_prefork
  • a2enmod mpm_event
  • apache2ctl configtest
  • systemctl restart apache2

روی RHEL و مشتقاتش دستور a2enmod وجود ندارد و انتخاب MPM داخل فایل /etc/httpd/conf.modules.d/00-mpm.conf انجام می‌شود: خط LoadModule mpm_prefork_module modules/mod_mpm_prefork.so را کامنت کنید و خط LoadModule mpm_event_module modules/mod_mpm_event.so را از کامنت خارج کنید، سپس apachectl configtest و در صورت سالم بودن خروجی systemctl restart httpd.

روی سرورهای cPanel این کار از مسیر WHM » EasyApache 4 انجام می‌شود و هندلر PHP هم در MultiPHP Manager روی php-fpm تنظیم می‌شود؛ اینجا دست‌کاری مستقیم فایل‌ها توصیه نمی‌شود چون در بازسازی بعدی بازنویسی می‌شوند. اگر ترجیح می‌دهید این مراحل را خودتان جلو نبرید، در سرور مجازی مدیریت‌شده ایران نصب و پیکربندی کنترل‌پنل و رفع اشکال نرم‌افزارهای نصب‌شده بر عهده تیم پشتیبانی است.

تنظیم MPM بر اساس رمی که واقعاً دارید

انتخاب MPM نصف کار است؛ نصف دیگر این است که سقف کارگرها را متناسب با حافظه سرور ببندید. ابتدا میانگین حافظه هر پردازه آپاچی را اندازه بگیرید:

  • ps -ylC httpd --sort:rss | awk 'NR>1 {s+=$8; n++} END {print s/n/1024" MB"}'

روی دبیان و اوبونتو به‌جای httpd از apache2 استفاده کنید. حالا حافظه‌ای که می‌خواهید به آپاچی اختصاص دهید (یعنی رم کل منهای سهم دیتابیس، PHP-FPM و سیستم‌عامل) را بر این میانگین تقسیم کنید تا سقف منطقی MaxRequestWorkers به دست بیاید.

در prefork این عدد مستقیماً یعنی تعداد پردازه‌ها. در worker و event باید مضربی از ThreadsPerChild باشد و ServerLimit هم دست‌کم برابر حاصل تقسیم MaxRequestWorkers بر ThreadsPerChild تنظیم شود، وگرنه آپاچی مقدار شما را نادیده می‌گیرد و در لاگ هشدار می‌دهد. یک پیکربندی نمونه برای event:

  • StartServers 3
  • ServerLimit 16
  • ThreadsPerChild 25
  • MaxRequestWorkers 400
  • MinSpareThreads 75
  • MaxSpareThreads 250
  • MaxConnectionsPerChild 10000

هشدار مهم: بالا بردن MaxRequestWorkers بدون رم کافی سرور را سریع‌تر از دست می‌دهد، نه سریع‌تر می‌کند. وقتی حافظه تمام شود سیستم به swap می‌افتد و در ادامه OOM Killer سرویس‌ها را می‌بندد؛ همین حالت روی دایرکت‌ادمین به شکل مصرف رم بالای آپاچی خودش را نشان می‌دهد. اگر با تنظیم درست هم به سقف می‌خورید، مشکل پیکربندی نیست و باید منابع را بالا ببرید؛ برای سایت‌های پربازدید و دیتابیس‌های سنگین، اجاره سرور اختصاصی کنترل کامل روی سخت‌افزار و پیکربندی را در اختیار شما می‌گذارد.

اشتباه‌های رایج

  • قرار دادن دستورهای مخصوص یک MPM بیرون از بلوک درست. مقادیر ThreadsPerChild باید داخل <IfModule mpm_event_module> باشند؛ اگر آن‌ها را زیر بلوک prefork بنویسید آپاچی یا نادیده می‌گیرد یا با خطا بالا نمی‌آید.
  • استفاده از نام قدیمی دستورها. از آپاچی ۲.۴ نام MaxClients به MaxRequestWorkers تغییر کرده است و مخلوط کردن این دو یکی از دلایل متداول خطای Invalid command MaxRequestWorkers است.
  • ری‌استارت بدون تست. همیشه قبل از systemctl restart دستور apachectl configtest را بزنید تا سرویس با فایل خراب پایین نماند.
  • فراموش کردن KeepAliveTimeout. روی prefork مقدار بالای این پارامتر پردازه‌ها را بی‌دلیل اشغال نگه می‌دارد؛ روی event فشار آن به‌مراتب کمتر است.

جمع‌بندی

تا وقتی mod_php دارید ناچار به prefork هستید؛ به‌محض جدا کردن PHP، گزینه درست برای اکثر سایت‌ها event است و worker عملاً فقط برای سازگاری با نصب‌های قدیمی معنا دارد. بعد از تعویض حتماً مقادیر کارگرها را با رم واقعی سرور هماهنگ کنید و رفتار حافظه را در ساعت‌های اوج ترافیک زیر نظر بگیرید؛ عددی که روی کاغذ درست به نظر می‌رسد را فقط بار واقعی تأیید یا رد می‌کند.

آموزش‌های مرتبط