بهینه سازی آپاچی و PHP
بهینه سازی Apache
روش های مختلفی به جهت بهینه سازی وب سرور آپاچی وجود دارد که در ذیل به چندین مورد آن اشاره می نماییم:
-
آپاچی را به آخرین ورژن آپدیت نمایید.
-
در صورتی که از نسخه کرنل 2.4 و یا قدیمی تر استفاده می نمایید حتما نسبت به آپگرید اقدام نمایید.
-
انتخاب ماژول MultiProcessing Module – MPM
آپاچی نسخه 2.4 با توجه به نیاز شما سه mpm مختلف را انتخاب می نماید:
Perfork MPM
Worker MPM
Event MPM
preforkMPM
استفاده از چندین پروسه ی فرزند بدون نخ. هر فرایند یک اتصال را در یک زمان بدون ایجاد موضوعات جداگانه برای هر یک از آن ها انجام می دهد. بدون در نظر گرفتن جزئیات بسیار، می توانیم بگوییم که از این MPM فقط در هنگام اشکالزدایی یک برنامه کاربردی استفاده میشوپ، یا اگر برنامه شما نیاز به استفاده از، ماژول های غیر ایمن مانند mod_php داشته باشد. زیرا این ماژول جز ابزار ها و کتابخانه های بدون نخ یا non-threaded هستند
مراجع درمورد این موضوع نظر یکسانی دارند نقل قول می کنم
Avoid using MPM Prefork whenever possible. It’s inability to scale well with increased traffic will quickly outpace the available hardware on most system configurations.
workerMPM
یک حالت preforkin چندگانه با قابلیت multithreaded, multiprocessing . مانند حالت قبل یک پردازش مستر درون یک serverpool فرزندان این پردازش را اجرا میکند ولی برخلاف نوع قبلی این فرزندان از جمله پردازش های multithreaded هستند. این یک انتخاب خوب برای سرورهای ترافیک بالا است زیرا اجازه می دهد که اتصالات همزمان همزمان با RAM کمتری نسبت به موارد قبلی داشته باشند.
eventMPM
MPM پیش فرض در بیشتر آپاچی برای نسخه 2.4 و بالاتر است.
این ماژول از یک نخ listener جدا برای هر child استفاده می کند که وظیفه هدایت درخواست به نخ های idle را برعهده میگیرد که مشکل لاک شدن نخ های حالت worker را حل می کند. این روش مطمین میشود که worker ها حداکثر درخواست ها را قبول کنند
اما با یک مزیت: آن باعث می شود که اتصالات غیر فعال (در حالی که در آن حالت باقی می ماند) با یک موضوع واحد انجام شود، بنابراین حافظه آزاد می شود به موضوعات دیگر اختصاص داده شود. این MPM برای استفاده با ماژول های غیر ایمن مانند mod_php مناسب نیست ، بلکه باید جایگزینی چنین PHP-FPM را استفاده کرد.
اینا جز اصلی ترین mpm ها بودند علاوه بر این سه مورد mpm های ذیگه هم هستن که بررسیشون نمیکنیم.
کدام mpm را انتخاب کنیم
بشدت سوال مهمی است.اینطور نیست که بگیم مثلا mpm-event برای همه مناسب است زیرا به جنبه های مختلفی بستگی دارد از جمله کد برنامه ترافیک نوغ سرور هندلر پی اچ پی و …
به عنوان مثال اگه کد برنامتون multi-threading پشتیبانی نمی کنه پس از prefork استقاده کنین بهتره یا در زمان استفاده از DSO مثل mod_php هم بهتره که از prefork استفاده بشه
برای برنامه های برپایه api مدل worker بهتز میتونه بهره وری بهتون بده ولی برای مقیاس پذیری و میزبانی دامین های مختلف mpm-event بهتر می تواند فعالیت کند
برای تغییر آن میتوان از دستورات a2enmod و a2dismod استفاده کرد.
شما در هر لحظه فقط می توانید از یکی از این ماژول های mpm استفاده کنید
لذا همگی را اول غیرفعال و یکی را فعال کنید بعد از فعال سازی میبایست سرویس apache2 ریستارت شود
هرکدام از این ماژول ها دارای یک مکان برای پیکربندی است به عنوان مثال بعد از تغییر ماژول mpm از prefork به event می توانیم در فایل etc/apache2/mods-enabled/mpm_event.conf/ تنظیمات آن زا تغییر دهیم
المان های عمومی آپاچی
یکی از المان های مهم آپاچی Timeout است که میزان زمان انتظار برای رخداد های I/O را نشان میدهد که باید به درستی ست شود.پیشفرض آن 60 است. المان های بعدی KeepAlive ، MaxKeepAliveRequests و KeepAliveTimeout هستند که KeepAlive باید مقدار on را بگیرد تا فعال باشد و MaxKeepAliveRequests که میزان حداکثر درخواست های keepalive را برای یک کانکشن مشخص میکند که پیشفرض ۱۰۰ هست و KeepAliveTimeout که حداکثر زمان انتظار برای یک پکت keepalive را مشخص میکند
نظر مراجع
Large timeouts above 1 minute, open the server to SlowLoris style DOS attacks and foster a long wait in the browser when it encounters a problem. Lower timeouts allow Apache to recover from errant stuck connections quickly. It becomes necessary to strike a balance between the two extremes
المان های mpm آپاچی
برای تنظیمات ماژول های apache از عبارت IfModule استفاده می شود به عنوان مثال
<ifModule mpm_prefork_module>...... </ifModule>
درزیر به بررسی المان های mpm چه event و چه worker می پردازیم که نقش اصلی ای در افزایش بهره وری دارند
در mpm نوع worker المان های ServerLimit, ThreadsPerChild, و MaxRequestWorkers خیلی بهم مرتبط هستند و مهمه که نقش هرکدوم رو درک کنیم
دوتا از مهمترین ماژول های mpm همین worker و event هستند که میشه گفت اصلی ترین تفاوتشون در مدیریت keepalive درخواست ها هست.
نظز بزرگان :
The MPM Worker locks threads for the duration of the KeepAlive process and directly affects the number of available threads able to handle new requests. The MPM Event uses a Listener thread for each child. These Listener threads handle standard requests, and KeepAlive requests alike meaning thread locking will not reduce the capacity of the server. Without thread locking, MPM Event is the superior choice but only in Apache 2.4. Before Apache 2.4 the MPM Event was unstable and prone to problems.
ServerLimit
این مقدار حداکثر تعداد مجاز فرزندان برای apache را مشخص می کند استفاذه منطقی از این مورد برای ساخت یک سقف سخت برای آپاچی در برابر مشکلات input به کمک MaxRequestWorkers است. این قابلیت ار افزایش تغداد فرزندانی که بیش از توان سیستم هست جلوگیری میکند
ServerLimit = MaxRequestWorkers = (Total RAM – Memory used for Linux, DB, etc.) / process size [5MB]
پیشفرض ۱۶ هست
برای محاسبه مقدار رم مصرفی فعلی می توانید از این اسکریپت استفاده کنید
wget https://raw.githubusercontent.com/pixelb/ps_mem/master/ps_mem.py chmod a+x ps_mem.py sudo python ps_mem.py
ThreadsPerChild
مشخص کننده تعداد نخ های هر فرزند آپاچی. هر نخ به یک درخواست جواب میدهد. پیشفرض آن ۲۵ است که در بیشتر مواقع همین مقدار درست کار می کند. ThreadLimit یک مقدار ماکسیموم برای این المان است که مقدار پیشفرض ۶۴ را دارد. اگه سرور به صورت dedicated هست می توانید این مقدار را افزایش دهید ولی در صورت اشتراکی بودن ممکن است یک هاست روی عملکرد هاست های دیگه تاثیر بذارد.
MinSpareThreads
حداقل تعداد نخ هایی که همیشه باز می مانند و منتظر درخواست اند و نباید از MaxSpareThreads بزرگتر باشد
سخن مراجع:
Set MinSpareThreads to equal 50% of MaxRequestWorkers.
MaxSpareThreads
حداکثرتعداد نخ که سرور مجاز است بر روی همه فرزندان ایجاد کند پیشفرض ۲۵۰ هست
StartServers
تعداد آپاچی های پدر که در حین ریستارت سرویس ایجاد میشود. بهتر است که این مقدار برابر تعداد هسته های سیستم باشد
MaxConnectionsPerChild
حداکثر تعداد درخواست های یک نمونه آپاچی بر روی همه نخ هایی که در حال اجرا دارد مقدار پیشفرض آن صفر به معنای بدون محدودیت هست
شاید مهم ترین مورد سخت افزاری که باید در نظر گرفته شود مقدار رم برای هر پردازش آپاچی است. در حالی که شما نمی توانید این را به طور مستقیم کنترل کنید، می توانید تعداد فرآیندهای فرزند را از طریق دستور MaxRequestWorkers (که قبلا MaxClients در Apache 2.2 شناخته می شود ) محدود کرده باشید و محدودیت استفاده Apache از RAM را محدود می کند. باز هم می توانید این مقدار را در هر میزبان یا هر میزبان مجازی تنظیم کنید.
یک پروژه apache2buddy هست که خیلی باحله و عیب و ایرادات سرویس آپاچی رو میگه
curl -sL https://raw.githubusercontent.com/richardforth/apache2buddy/master/apache2buddy.pl | sudo perl
بهینه سازی php-fpm
روش های استفاده از PHP
وب سرورها، با سه روش زیر میتوانند از موتور پردازشگر PHP استفاده کنند. هر یک از این روشها، خوبیها و بدیهای خاص خودش را دارد که به آن میپردازیم.
۱- اتصال به صورت CGI
قدیمی ترین روش اتصال و استفاده از صفحه های پویا سی-جی-آی است که مفهوم بسیار ساده ایست و مختص زبان PHP به طور خاص نیست.
۲- اتصال به صورت افزونه (ماژول) – modphp
این روش در وب سرور Apache پشتیبانی میشود و جزو یکی از روش های سنتی و البته استاندارد برای پردازش فایل های PHP به شمار میرود. در این روش، موتور پردازشگر PHP به صورت یک کتابخانهی نرم افزاری به وب سرور Apache متصل میشود. این یعنی که Apache در فضای حافظهی خودش به PHP اجازهی فعالیت میدهد. با این روش، قاعدتا ارتباط بین این دو بسیار نزدیک بوده و Apache به راحتی میتواند تنظیمات دلخواه شما را دریافت کرده و به موتور پردازشگر PHP ارایه کند.
یکی دیگر از مواردی که در این بخش ممکن است شما را با مشکل مواجه کند این است که پردازش های PHP تحت اجازه های کاربری همان وب سرور انجام میشوند. به عنوان مثال اگر برنامهی apache تحت نام کاربری و مجوز www-data در حال اجرا باشد، فایلهایی که برنامهی PHP شما میسازد نیز با همین نام کاربری ساخته میشود. این مورد برای سناریوهایی که چندین سایت را میخواهید به صورت ایزوله بر روی یک رایانه میزبانی کنید، مشکل زا خواهد بود.
۳- اتصال به صورت FastCGI
همانطور که از اسم این روش هم بر میآید، FastCGI یک نسخهی بهتر از روش اول است. منطق FastCGI بسیار ساده است اما در عین حال بسیار گسترش پذیر است و بسیاری از مشکلات دو روش قبل را برطرف میکند. در این روش، برنامه های پردازشگر زبان PHP از همان ابتدا اجرا شده و در حافظه جا خوش میکنند. هر گاه درخواستی از سمت کاربران بیاید، وب سرور با استفاده از قراردادهایی تحت همین نام، با برنامهی مسئول FastCGI ارتباط برقرار کرده و درخواست پردازش یک صفحه را مینماید. برنامهی مسئول با یکی از برنامه هایی که سرش خلوت است، جواب مورد نیاز را تهیه کرده و برمیگرداند. در این روش، به جای اینکه تعداد مشخصی برنامهی از پیش اجرا شده وجود داشته باشد، برنامه های مدیریتی مانند php-fpm میتوانند با توجه به تعداد درخواست ها، به صورت خودکار تعداد برنامه های پاسخگو را بیشتر کرده و روند پردازش را تسریع کنند.
php-fpm یک پیاده سازی دیگر از PHP FastCGI بوده و برای سابتهای heavy-load مناسب است و دارای یکسری ویژگی های خوبه که اینجا جای بحثش نیست
یک سری مکانیزم های بهینه سازی هستند که بنظر من و اکثر بزرگان در این زمینه خیلی مهمه که رعایت بشه علاوه بر بهینه سازی apache و php .ی چنتاشو این پایین میارم
بهینه سازی ۱ – استفاده از Varnish Cache در بیرونیترین لایه بهینه سازی ۲ – استفاده از Memcached برای ذخیره سازی Session ها بهینه سازی ۳ – جدا سازی سرویس ها و ارتقای منابع سخت افزاری بهینه سازی ۳ – وجود کلاسترینگ در لایه های مختلف
این نمونه عکسی ک تقریبا اینارو شامل میشه
PHP-FPM نیز همانند دیگر نرمافزارها باید برای محیطی که در آن کار میکند بهینه شود. بهینه سازی یا Tunnig یعنی تعیین دقیق پارامترهای نرمافزار با توجه به کاربرد، کانفیگ سخت افزاری سرور شامل RAM و CPU، تعداد درخواستهای روی سرور و …
php-fpm یکسری تنظیمات عمومی و یک سری تنظیمات خاص داره
مکان این تنظیمات می تونه متفاوت باشه توی سیستم مثلا در زیرساخت فعلی ما در /etc/php/7.2/fpm/ قرار داره . پیشنهاد میشه خطوط زیر به تنظیمات اصلی php-fpm در etc/php/7.3/fpm/php-fpm.conf/ اضافه بشه
emergency_restart_threshold = 10 emergency_restart_interval = 1m process_control_timeout = 10s
دوتای اول میگه که اگه php-fpm در یک دقیقه ۱۰ تا فرزند داشت که به خطا خورده اند پردازش اصلی خودش رو ریستارت کنه که منطقیه.
المان process_control_timeout مشخص می کنه که فرزندان این پردازش باید این زمان صبر کن بعد اقدام به اجرای سیگنال دریافتی از پردازش پدر کنند مثلا پردازش پدر یک سیگنال kill میفرستد پردازش فرزند ۱۰ ثانیه وقت دارد تا تمامی بند و بساطش رو جمع کنه بعد سیگنال دریافتی رو اجر کنه. بهتر است که برای هر دامین یک pool جدا در نظر گرفته شود که تداخلی بین دامین ها ایجاد نشود مکان این تنظیمات در etc/php/7.3/fpm/pool.d/*.conf/ می باشد
فایل های درون این دایرکتوری دارای المان هایی هست که با هم مهمترینشون رو بررسی میکنیم
[www] user = www-data group = www-data listen = /run/php/php7.3-fpm.sock / IP listen.owner = www-data listen.group = www-data listen.mode = 0660 listen.allowed_clients = 127.0.0.1 process.priority = -19 ## process manager (pm) setting pm = dynamic pm.max_children = 329 pm.start_servers = 24 pm.min_spare_servers = 12 pm.max_spare_servers = 24 pm.max_requests = 1000 pm.process_idle_timeout = 5s env[HOSTNAME] = $HOSTNAME env[TMP] = #TMP-dir env[TMPDIR] = #TMP-dir env[TEMP] = #TMP-dir env[PATH] = /usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin php_admin_value[open_basedir] = # allowed dir path php_admin_value[session.save_path] = php_admin_value[upload_tmp_dir] = php_admin_value[sendmail_path] = "/usr/sbin/sendmail -t -i -f [email protected]"
بیشتر این تنظیمات خیلی واضحه فقط قسمت مهم و جای بحثش همون بخش process manager است
pm
این المان مشخص کننده نوع process manager هست که می تواند یکی از موارد static,on-demand و dynamic را داشته باشد. در حالت داینامیک تعداد پردازش های فرزند بر اساس المان های دیگر به صورت پویا و با توجه به pm.max_children, pm.start_servers,pm.min_spare_servers, pm.max_spare_servers مشخص میشود . در حالت static تعداد پردازش های فرزند ثابت می باشد و برابر مقدار pm.max_children است.در حالت on-demand هم پردازش php-fpm در صورت لزوم (بار زیاد) اقدام به ساخت پردازش های فرزند می کند, برخلاف dynamic که از همان ابتدا شروع به ساخت پرداش فرزند میکند برای گرفتن حداکثر بهره وری بهتر است از مدل static استفاده کرد این مدل خیلی به میزان خالی رم متکی هست اگر مشکل رم در سرور دارید حتما مدل های dynamic یا on-demand را انتخاب کنید. اگر که فضای رم دارید برای گرفتن حداکثر کارایی از مدل static استفاده کنید
در تصویر بالا مدلی که برای pm انتخاب شده static با pm.max_children = 100 هست که ۱۰ گیگ رم از ۳۲ گیگ سرور استفاده کرده.
pm.max_children
مشخص کننده حداکثر تعداد فرزندان پردازش که از فرمول زیر استفاده میشود (total RAM – (DB etc) / process size) مثلا برای زیرساخت ما: ( 8000 MB – 1200 MB ) 15MB = 453
برای محاسبه مقدار رم اشغالی توسط همه پردازش ها می توانید از اسکریپت زیر استفاده کنید(ی بار دیگه هم بش اشاره کردیم بالاتر)
wget https://raw.githubusercontent.com/pixelb/ps_mem/master/ps_mem.py chmod a+x ps_mem.py sudo python ps_mem.py
pm.start_servers
مشخص کننده تعداد فرزندان پردازش ایجاد شده در زمان استارت سرویس که بهتر است از فرمول زیر استفاده شود
(cpu cores * 4) به عنوان مثال در زیر ساخت ما
6G * 4 = 24
pm.min_spare_servers و pm.max_spare_servers
مشخص کننده حداقل و حداکثر تعداد پردازش های idle که بهتر است از فرمول های زیر استفاده شود
pm.min_spare_servers (cpu cores * 2) pm.max_spare_servers (cpu cores * 4)
pm.max_requestsمشخص کننده حداکثر تعداد ذرخواست هایی است که یک نخ از پردازش می تواند هندل کند
فعال سازی slowlog
یکی از موارد مهمی که از طریق آن میتوانیم هاستی که لود بالایی را دارد شناسایی کنیم.
request_slowlog_timeout = 6s slowlog = /var/log/php-fpm/slowlog-site.log
درون این فایل var/log/php-fpm/slowlog-site.log/ تمامی درخواست هایی که بیش از request_slowlog_timeout (در این مثال ۶ ثانیه ) طول کشیده است ذخیره میشود. با بررسی و تحلیل این فایل می توانیم به نتایج خوبی برسیم
امیدوارم مفید بوده باشه
یا حق
منابع:
https://www.liquidweb.com/kb/apache-performance-tuning-mpm-directives
http://php.net/manual/en/install.fpm.configuration.php
https://bobcares.com/blog/php-fpm-tuning-high-load/
https://haydenjames.io/php-fpm-tuning-using-pm-static-max-performance/
https://dev.to/jake/configuring-php-fpm-for-high-network-traffic-47le