ماژول های پردازش موازی در وب سرور آپاچی

ماژول های پردازش موازی در وب سرور آپاچی

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

یک مجموعه از ماژول های مهم و کلیدی در وب سرور آپاچی، ماژول های پردازش موازی یا Multi-Processing Moduleها هستند که به اختصار MPM نامیده می شوند. این ماژول ها مسئول اتصال به پورت های شبکه، دریافت کانکشن ها و ریکوئست های رسیده و اجرای پردازه های مختلف برای پردازش آنها هستند. در واقع این ماژول ها این وظیفه را از طریق رویکردهای مختلف در بحث پردازش موازی، به شکل همزمان برای ریکوئست های رسیده در یک زمان، انجام می دهند و از این طریق وب سرور را برای پاسخگویی به ریکوئست های همزمانِ دریافت شده، مجهز می کنند. از این طریق وب سرور آپاچی این امکان را دارد تا به شکل همزمان چندین ریکوئست ارسالی را مدیریت کرده و به آنها پاسخ دهد. تا با استفاده از این امکان، سایت های پر ترافیک مشکلی برای پاسخگویی مناسب به کاربران خود در هنگام لود بالا نداشته باشند. البته انتخاب صحیح از بین ماژول های پردازش موازی مختلفِ فراهم شده در وب سرور آپاچی، در کنار کانفیگ مناسب هر کدام، نقش مهمی در آماده کردن وب سرور برای پاسخگویی مناسب در تمامی شرایط ترافیکی سایت دارد.

وب سرور آپاچی دارای سه ماژول پردازش موازی است که بر اساس رویکردهای چند پردازه ای (multi-process) و چند رشته ای (multi-threaded) کار می کنند. این ماژول ها (که همزمان تنها یکی از آنها می تواند فعال باشد) عبارتند از: prefork، worker و event که در ادامه به توضیح هر کدام از آنها خواهیم پرداخت.

اما قبل از آن لازم به ذکر است که برای یافتن MPM فعال بر روی وب سرور آپاچی، می توان از دستور زیر با کاربر root استفاده کرد:

a2query -M

ماژول پردازش موازی prefork

این ماژولِ پردازش موازی تنها از روش چند پردازه ای (multi-process)، برای پردازش همزمان و موازی ریکوئست های دریافتی استفاده می کند. درنتیجه این ماژول از امکان پردازش چند رشته ای (multi-threaded) استفاده نمی کند و یک ماژول با پیاده سازی non-threaded است. در این ماژول یک پردازه والد و اصلی وجود دارد که کار مدیریت و اجرای پردازه های فرزند یا فرعی را برای پاسخگویی به ریکوئست ها، بر عهده دارد. هر پردازه فرزند در این ماژول تنها وظیفه پاسخگویی به یک ریکوئست را بر عهده دارد و پردازه والد، وظیفه ی مدیریت تعداد پردازه های فرزند، اجرا و یا از بین بردن آنها را بر عهده دارد.

این ماژول زمانی که قصد کار با کتابخانه هایی را داریم که امکان کار در حالت چند رشته ای با آنها وجود ندارد یا به اصطلاح non-thread-safe هستند توصیه می شود. همچنین در این ماژول هر ریکوئست از سایر ریکوئست ها به شکل کاملاً مجزا و ایزوله پردازش می شود و ریکوئست ها بر روی هم اثر گذار نیستند. در نتیجه بروز مشکل در یک ریکوسئت بر روی سایر ریکوئست های در حال پردازش اثری نخواهد کرد.

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

اکنون به روش فعال سازی و کانفیگ این ماژول می رسیم. برای فعال کردن این ماژول (در صورتی که هم اکنون فعال نیست) از دستورات زیر استفاده می کنیم. ابتدا با استفاده از دستور زیر ماژول فعال را شناسایی می کنیم:

a2query -M

اگر ماژول فعال برروی سرور، غیر از ماژول prefork بود، آن را با یکی از دستورات زیر غیر فعال می کنیم:

a2dismod mpm_worker

در صورتی که ماژول فعال Worker باشد و یا دستور

a2dismod mpm_event

اگر ماژول فعال event باشد.

سپس برای فعال شدن ماژول prefork از دستور زیر استفاده می کنیم:

a2enmod mpm_prefork

در نهایت سرور آپاچی را با دستور زیر ریستارت می کنیم:

/etc/init.d/apache2 restart

این ماژول طبق گفته مستندات رسمی سایت آپاچی بسیار self-regulating است و نیاز به تنظیم خاصی ندارد اما برای آشنایی بهتر با نحوه عملکرد آن، پارامتر های مختلف قابل تنظیم آن را مختصراً بررسی می کنیم. برای باز کردن فایل تنظیمات این ماژول از دستور زیر استفاده می کنیم:

nano /etc/apache2/mods-available/mpm_prefork.conf 

تنظیمات این ماژول به شکل زیر است:

# prefork MPM
# StartServers: number of server processes to start
# MinSpareServers: minimum number of server processes which are kept spare
# MaxSpareServers: maximum number of server processes which are kept spare
# MaxRequestWorkers: maximum number of server processes allowed to start
# MaxConnectionsPerChild: maximum number of requests a server process serves

<IfModule mpm_prefork_module>
        StartServers                 5
        MinSpareServers              5
        MaxSpareServers              10
        MaxRequestWorkers            150
        MaxConnectionsPerChild       0
</IfModule>

# vim: syntax=apache ts=4 sw=4 sts=4 sr noet

پارامتر های StartServers، MinSpareServers، MaxSpareServers و MaxRequestWorkers توسط پردازه والد برای چگونگی اجرای پردازه های فرزند جهت رسیدگی به ریکوئست ها مورد استفاده قرار می گیرد.

مهمترین پارامتر در این بین، پارامتر MaxRequestWorkers است که نشان دهنده حداکثر تعداد ریکوئست های همزمانی است که وب سرور آپاچی باید به آنها (به شکل همزمان) رسیدگی نماید. این مقدار باید به شکلی تنظیم شود (آنقدر بزرگ باشد) که بتواند به حداکثر تعداد ریکوئست های همزمانی که انتظار داریم به سرور ما برسند رسیدگی نماید و از طرف دیگر (آن قدر کوچک باشد که) منابع سیستم، مانند رم، توان اجرای همزمان این مقدار پردازه را داشته باشند.

پارامتر StartServers نشان دهنده تعداد پردازه های فرزندی است که در هنگام شروع پردازه والد ایجاد می شوند.

پارامتر های MinSpareServers و MaxSpareServers مشخص کننده حد بالا و پایین تعداد پردازه های فرزند بیکار و آماده به کار هستند که منتظرند تا ریکوئست های جدید برای پاسخگویی برسند. در واقع این دو پارامتر مشخص کننده حجم مجموعه یا استخر پردازه های فرزند بیکار و آماده پاسخگویی هستند که باید همیشه توسط پردازه والد محیا و آماده باشند.

در صورتی که مقادیر بالا را تغییر دهید (که در بیشتر مواقع نیازی نیست زیرا این تنظیمات، حالت بهینه هستند). نیاز است تا بعد از تغییر سرویس آپاچی ریستارت شود.

ماژول پردازش موازی worker


این ماژول پردازش موازی، از ترکیب دو روش چند پردازه ای و چند رشته ای برای رسیدگی به کانکشن ها استفاده می کند. این ترکیب باعث می شود ماژول با درگیر کردن منابع کمتری از سیستم نظیر رم، به تعداد بالاتری از کانکشن ها به شکل همزمان پاسخ دهد. در این ماژول، وظیفه رسیدگی به هر کانکشن به عهده یک رشته (thread) و نه کل پردازه ی فرزند است. پردازه ی والد در این ماژول چند پردازه ی فرزند را ایجاد می کند که در هر کدام، یک رشته برای گوش کردن به کانکشن ها وجود دارد و تعدادی رشته ی worker که وظیفه ی رسیدگی به کانکشن ها را دارند. رشته ی گوش کننده به کانکشن ها وظیفه دارد تا به محض دریافت کانکشن جدید، آن را به رشته ی worker بیکار برای پردازش تحویل دهد.
از این ماژول تنها زمانی می توان استفاده کرد که با کتابخانه های thread safe کار می کنیم.

تفاوت پردازه با رشته در این است که هر پردازه address space یا فضای حافظه مخصوص به خود را دارد و از پردازه دیگر کاملاً مجزا بوده و روی یکدیگر اثری ندارند و به اصطلاح پردازه ها از هم ایزوله هستند. اما رشته ها در یک پردازه دارای فضای حافظه اشتراکی هستند و در صورت عدم استفاده از کتابخانه های thread safe می توانند روی هم اثر گذار بوده و حتی ایجاد مشکل در یک رشته، می تواند سایر رشته های موجود در پردازه ی مشترکشان را نیز دچار مشکل کند. از آنجایی که رشته های موجود در یک پردازه دارای فضای حافظه مشترک، که در واقع همان فضای حافظه پردازه آنهاست هستند، منابع کمتری از سیستم به ویژه رم را اشغال می کنند.

برای فعال کردن این ماژول (در صورتی که هم اکنون فعال نیست) از دستورات زیر استفاده می کنیم. ابتدا با استفاده از دستور زیر ماژول فعال را شناسایی می کنیم:

a2query -M

اگر این ماژول غیر از ماژول worker بود، آن را با یکی از دستورات زیر غیر فعال می کنیم:

a2dismod mpm_prefork

یا

a2dismod mpm_event

سپس برای فعال شدن ماژول worker از دستور زیر استفاده می کنیم:

a2enmod mpm_worker

در نهایت سرور آپاچی را با دستور زیر ریستارت می کنیم:

/etc/init.d/apache2 restart

این ماژول نیز طبق گفته مستندات رسمی سایت آپاچی بسیار self-regulating است و نیاز به تنظیم خاصی ندارد اما برای آشنایی بهتر با نحوه عملکرد آن، پارامتر های مختلف قابل تنظیم آن را مختصراً بررسی می کنیم. برای باز کردن فایل تنظیمات این ماژول از دستور زیر استفاده می کنیم:

nano /etc/apache2/mods-available/mpm_worker.conf 

تنظیمات این ماژول به شکل زیر است:

# worker MPM
# StartServers: initial number of server processes to start
# MinSpareThreads: minimum number of worker threads which are kept spare
# MaxSpareThreads: maximum number of worker threads which are kept spare
# ThreadLimit: ThreadsPerChild can be changed to this maximum value during a
#                         graceful restart. ThreadLimit can only be changed by stopping
#                         and starting Apache.
# ThreadsPerChild: constant number of worker threads in each server process
# MaxRequestWorkers: maximum number of threads
# MaxConnectionsPerChild: maximum number of requests a server process serves

<IfModule mpm_worker_module>
        StartServers                     2
        MinSpareThreads                  25
        MaxSpareThreads                  75
        ThreadLimit                      64
        ThreadsPerChild                  25
        MaxRequestWorkers                150
        MaxConnectionsPerChild           0
</IfModule>

# vim: syntax=apache ts=4 sw=4 sts=4 sr noet

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

عبارت های MinSpareThreads و MaxSpareThreads هم همانند ماژول prefork، حجم استخر worker های آماده برای پردازش کانکشن های دریافتی را مشخص می کنند که این پارامتر ها توسط پردازه والد برای مدیریت تعداد پردازه ها و رشته هایی که باید ایجاد شوند و آماده به کار باشند استفاده می شود.

پارامتر MaxRequestWorkers نیز دقیقاً همانند ماژول prefork تعداد حداکثر worker های در حال کار که به شکل همزمان در حال پاسخگویی به کانکشن های مختلف هستند را مشخص می کند و در واقع این پارامتر تعیین کننده تعداد کانکشن هایی است که همزمان می توانند توسط سرور رسیدگی شوند.

پارامتر MaxRequestWorkers نیز دقیقاً همانند ماژول prefork تعداد حداکثر worker های در حال کار که به شکل همزمان در حال پاسخگویی به کانکشن های مختلف هستند را مشخص می کند و در واقع این پارامتر تعیین کننده تعداد کانکشن هایی است که همزمان می توانند توسط سرور رسیدگی شوند.

پارامتر ThreadLimit نیز حداکثر تعداد رشته ی worker ها به ازای یک پردازه ی فرزند را مشخص می کند که مقدار ThreadsPerChild در شرایط خاصی می تواند به این مقدار تغییر کند.
پارامترهای StartServers و MaxConnectionsPerChild نیز دقیقاً نظیر همانهایی هستند که در ماژول prefork توضیح داده شدند.

ماژول پردازش موازی event


این ماژول پیاده سازی دیگری از ماژول worker است با این تفاوت اساسی که در این ماژول رشته ی worker تنها به کانکشن هایی اختصاص داده می شود که فعالیتی برای پردازش دارند. در واقع در این ماژول رشته worker تنها به ریکوئست دریافت شده اختصاص داده می شود نه به کل کانکشن باز که ممکن است در حالت listen باشد اما ریکوئستی برای پردازش نداشته باشد.
مبنای کار در این ماژول به این شکل است که بعد از پردازش ریکوئست دریافتی توسط رشته ی worker، این رشته کانکشن را دوباره به رشته ی گوش کننده ی پردازه ی فرزند برمی گرداند. در نتیجه رشته ی worker برای پردازش، یک ریکوئست دیگر خالی و آماده می شود. از این طریق در این ماژول با مصرف منابع کمتری از سیستم نسبت به ماژول worker می توان به ریکوئست های همزمان بیشتری پاسخ داد.
از این ماژول تنها زمانی می توان استفاده کرد که با کتابخانه های thread safe کار می کنیم.
برای فعال کردن این ماژول (در صورتی که هم اکنون فعال نیست) از دستورات زیر استفاده می کنیم. ابتدا با استفاده از دستور زیر ماژول فعال را شناسایی می کنیم:

a2query -M

اگر این ماژول غیر از ماژول event بود، آن را با یکی از دستورات زیر غیر فعال می کنیم:

a2dismod mpm_prefork

یا

a2dismod mpm_worker

سپس برای فعال شدن ماژول event از دستور زیر استفاده می کنیم:

a2enmod mpm_event

در نهایت سرور آپاچی را با دستور زیر ریستارت می کنیم:

/etc/init.d/apache2 restart

این ماژول نیز همانند دو ماژول قبلی، بسیار self-regulating است و نیاز به تنظیم خاصی ندارد اما برای آشنایی بهتر با نحوه عملکرد آن، پارامتر های مختلف قابل تنظیم آن را مشاهده می کنیم. برای باز کردن فایل تنظیمات این ماژول از دستور زیر استفاده می کنیم:

nano /etc/apache2/mods-available/mpm_event.conf 

تنظیمات این ماژول به شکل زیر است:

# event MPM
# StartServers: initial number of server processes to start
# MinSpareThreads: minimum number of worker threads which are kept spare
# MaxSpareThreads: maximum number of worker threads which are kept spare
# ThreadsPerChild: constant number of worker threads in each server process
# MaxRequestWorkers: maximum number of worker threads
# MaxConnectionsPerChild: maximum number of requests a server process serves

<IfModule mpm_event_module>
        StartServers                     2
        MinSpareThreads                  25
        MaxSpareThreads                  75
        ThreadLimit                      64
        ThreadsPerChild                  25
        MaxRequestWorkers                150
        MaxConnectionsPerChild           0
</IfModule>

# vim: syntax=apache ts=4 sw=4 sts=4 sr noet

پارامتر های قابل تنظیم در این ماژول دقیقا مانند ماژول worker میباشد که توضیح داده شد.

PHP و ماژول های پردازش موازی آپاچی


در سایت رسمی PHP اکیداً توصیه شده است تا از MPM های مبتنی بر پردازش چند رشته ای آپاچی به همراه PHP استفاده نشود. MPM توصیه شده در سایت رسمی PHP، ماژول prefork است که تنها مبتنی بر پردازش چند پردازه ای است.

علت این موضوع در سایت رسمی PHP اینگونه عنوان شده است:

همانطور که مشاهده می شود، سایت رسمی PHP علت این موضوع را به وجود آمدن اختلال در مکانیزم عملکرد PHP هنگام خطا یابی و رفع آن به علت پیچیده شدن فرآیند پردازش در بستری که PHP بر روی آن کار می کند عنوان کرده است. این پیچیدگی از طریق فرآیند پردازش موازی مبتنی بر پردازش چند رشته ای که در آن فضای حافظه بین رشته ها به اشتراک گذاشته می شود به وجود می آید. در کنار توصیه PHP به استفاده از ماژول prefork، همچنین توصیه شده است که اگر تحت هر شرایطی می خواهید از ماژول های مبتنی بر پردازش چند رشته ای آپاچی استفاده کنید، حتماً از مکانیزم fastCGI برای ارتباط بین آپاچی و PHP استفاده کنید که در آن اسکریپت های PHP در فضای حافظه مخصوص به خود اجرا میشوند. در نتیجه پیچیدگی های فضای پردازش چند رشته ای آپاچی را ندارند.

در صورتی که به شکل پیش فرض از حالت معمول mod_php به عنوان نحوه ارتباط آپاچی با PHP استفاده شود و نه هر کدام از روش های CGI و یا fastCGI، از آنجایی که PHP استاندارد بر روی سرورها، امکان Thread Safety را ندارند یا به اصطلاح ویژگی Thread Safety در آن غیر فعال است، این مورد نیز مشکلی دیگر در استفاده از ماژول های worker و event به همراه PHP استاندارد است. در نتیجه اگر قصد استفاده از ماژول های پردازش موازی مبتنی بر پردازش چند رشته ای آپاچی را در قالب ارتباطی mod_php دارید، بایستی PHP را با امکان Thread Safety روشن در آن کامپایل و نصب کنید. اما کماکان PHP اکیداً این کار را جهت استفاده از PHP در قالب وب سرور توصیه نمی کند. استفاده از ویژگی Thread Safety در PHP فقط در قالب استفاده از CLI پیشنهاد می شود.
برای آگاهی از فعال بودن یا نبودن ویژگی Thread Safety در PHP می توانید به اطلاعات آمده در خروجی تابع phpinfo() مراجعه کرده و یا از دستور زیر استفاده کنید:

php -i|grep Thread

از آنجایی که علت استفاده از ماژول های پردازش موازی، بالا بردن توان پاسخگویی به ریکوئست های همزمان در سایت هایی با ترافیک بالا و در عین حال کاهش استفاده از منابع سخت افزاری سیستم است، یک راه جایگزین مناسب، استفاده از fastCGI به عنوان Server API یا همان رابط بین آپاچی و PHP است. PHP-FPM یا همان FastCGI Process Manager که توسط PHP ارائه شده است، یک SAPI یا Server API مبتنی بر پروتکل fastCGI است که در آن زمان اجرا و پردازش به شدت کاهش پیدا کرده و به نسبت پروتکل CGI سرعت و مزایای متعددی دارد. ویژگی مطلوب دیگر PHP-FPM در آن است که با استفاده از آن اسکریپت های PHP در فضای حافظه ی مخصوص به خود اجرا شده و مشکلی با ماژول های مبتنی بر پردازش چند رشته ای آپاچی نیز ندارند (بر خلاف mod_php که در آن PHP به عنوان بخشی از پردازه آپاچی اجرا می شود و نه در پردازه مخصوص به خود)؛ اگرچه کماکان توصیه بر استفاده از ماژول prefork است. اما در این منبع نحوه نصب آپاچی به همراه PHP-FPM بر روی سرور دبیان 10 آموزش داده شده است.

منابع

 http://httpd.apache.org/docs/2.4/mpm.html
 http://httpd.apache.org/docs/2.4/mod/prefork.html
 http://httpd.apache.org/docs/2.4/mod/worker.html
 http://httpd.apache.org/docs/2.4/mod/event.html
 https://www.php.net/manual/en/install.unix.apache2.php
 https://www.php.net/manual/en/faq.installation.php#faq.installation.apache2
 https://www.php.net/manual/en/install.fpm.php
https://tecadmin.net/install-apache-php-fpm-debian-10
 https://help.superhosting.bg/en/cgi-common-gateway-interface-fastcgi.html
 https://www.quora.com/Why-do-we-use-PHP-FPM
 https://askubuntu.com/questions/524770/apache-enable-worker-mpm
 https://www.geeksforgeeks.org/what-is-thread-safe-or-non-thread-safe-in-php/
 https://www.programmerinterview.com/operating-systems/thread-vs-process/
 https://stackoverflow.com/questions/200469/what-is-the-difference-between-a-process-and-a-thread
 https://blog.programster.org/ubuntu16-04-compile-php-7-2-with-pthreads
 https://stackoverflow.com/questions/34969325/how-to-install-php7-zts-pthreads-on-ubuntu-14-04
https://www.quora.com/What-is-the-meaning-of-TS-and-NTS-in-PHP

نظرات
اگر login نکردی برامون ایمیلت رو بنویس: