تنظیم PHP-FPM برای وردپرس یعنی هم‌خوان‌کردن تعداد فرآیندهای آماده، مقدار حافظه هر فرآیند و زمان پاسخ سرور با الگوی واقعی ترافیک سایت؛ کاری که اثرش از هر افزونه کش روی زمان پاسخ داینامیک بیشتر است.

بیشتر سایت‌هایی که روی سرور قدرتمند کند هستند، در لایه استخر PHP-FPM گلوگاه دارند، نه در سخت‌افزار.

سه متغیر اصلی تعیین‌کننده‌اند: pm.max_children، pm.max_requests و مقدار حافظه هر فرآیند PHP.

انتخاب اشتباه در هر یک از این سه، یا باعث ورود سرور به Swap می‌شود یا باعث خطاهای 502 در ساعات اوج.

هدف این نوشته رسیدن از پیکربندی پیش‌فرض به تنظیمی است که زیر بار واقعی قابل دفاع بماند.

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

PHP-FPM دقیقاً کجای معماری نشسته است

وقتی مرورگر یک صفحه وردپرس را درخواست می‌کند، درخواست اول به وب‌سرور می‌رسد. اگر مسیر به یک فایل PHP اشاره کند، وب‌سرور آن را از طریق یک سوکت Unix یا پورت TCP به PHP-FPM می‌سپارد. PHP-FPM یک مخزن از فرآیندهای آماده نگه می‌دارد تا هزینه ساخت فرآیند برای هر درخواست حذف شود.

PHP-FPM (FastCGI Process Manager) خودش کد وردپرس را تفسیر نمی‌کند؛ این کار را فرآیندهای PHP انجام می‌دهند. نقش FPM مدیریت چرخه حیات آن فرآیندهاست: ساخت، بازنشستگی، جایگزینی و کنترل تعداد همزمان.

لایه‌های بالاتر و پایین‌تر باید با همین دید دیده شوند. اگر بهینه‌سازی Nginx برای وردپرس انجام شود اما استخر PHP-FPM تنظیم‌نشده باقی بماند، وب‌سرور سریع‌تر پاسخ می‌دهد اما به همان سقف قبلی می‌خورد. اگر وب‌سرور Apache باشد، هم‌خوانی با Apache و پیکربندی Apache برای وردپرس به همان اندازه تعیین‌کننده است.

ساختار استخر و پارامترهای پایه

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

ساختار پیکربندی معمولاً در مسیر /etc/php/8.2/fpm/pool.d/ قرار می‌گیرد و برای هر استخر یک فایل مشخص ساخته می‌شود. تنظیمات پایه شامل کاربر اجرا، گروه، سوکت گوش‌دادن و حالت مدیریت فرآیند است.

[wordpresskar]
user = www-data
group = www-data
listen = /run/php/php8.2-fpm-wpk.sock
listen.owner = www-data
listen.group = www-data
listen.mode = 0660

pm = dynamic
pm.max_children = 25
pm.start_servers = 5
pm.min_spare_servers = 3
pm.max_spare_servers = 10
pm.max_requests = 500

انتخاب مسیر سوکت Unix به‌جای پورت TCP، سرباری شبکه محلی را حذف می‌کند. این تغییر کوچک در سایت‌های پربازدید، اثر قابل اندازه‌گیری روی زمان پاسخ دارد.

مقدار listen.mode را باید دقیق تنظیم کرد؛ دسترسی بیش‌ازحد به سوکت، یک شکاف امنیتی واقعی است. در همین راستا، درست‌کردن خطای Permission در فایل‌های وردپرس پیش از شروع تنظیم PHP-FPM ضروری است، چون مجوزهای اشتباه می‌توانند ظاهر مشکل را به سمت دیگری ببرند.

محاسبه درست pm.max_children

پرتکرارترین اشتباه در تنظیم PHP-FPM، انتخاب یک عدد سرراست است بدون توجه به حافظه. مقدار pm.max_children تعیین می‌کند چه تعداد فرآیند PHP همزمان در حال پردازش باشد. اگر این عدد بزرگ‌تر از ظرفیت حافظه سرور باشد، فرآیندها به Swap می‌روند و کندی سرور از یک سرور اشباع‌شده هم بیشتر می‌شود.

محاسبه صحیح از یک رابطه ساده بیرون می‌آید:

pm.max_children = (Total RAM - RAM for OS, DB, Nginx/Apache) / Average PHP Process Size

برای نمونه، سروری با ۸ گیگابایت حافظه که ۲ گیگابایت آن در اختیار سیستم‌عامل و پایگاه داده است، حدود ۶ گیگابایت حافظه قابل استفاده دارد. اگر میانگین مصرف هر فرآیند PHP حدود ۸۰ مگابایت باشد، سقف منطقی حدود ۷۵ فرآیند خواهد بود. اما در عمل باید حاشیه امن نگه داشت و از ۷۰ درصد این عدد استفاده کرد.

مقدار میانگین مصرف هر فرآیند را باید اندازه گرفت، نه حدس زد. ابزارهای خط فرمان این عدد را مستقیماً گزارش می‌دهند. بدون این اندازه‌گیری، تنظیم pm.max_children یک حدس است.

سقف فرآیندها عدد جادویی ندارد؛ نسبتی است میان حافظه آزاد و مصرف واقعی هر فرآیند.

در پروژه‌هایی که با محدودیت حافظه روبه‌رو بوده‌ام، ریشه اغلب در افزونه‌های سنگین یا قالب‌های پرمصرف بوده است. اجرای رفع خطای Memory Limit در وردپرس پیش از تنظیم PHP-FPM می‌تواند تصویر واقعی از نیاز حافظه بدهد.

static یا dynamic یا ondemand

سه حالت مدیریت فرآیند وجود دارد و هر یک رفتار متفاوتی زیر بار دارند. انتخاب اشتباه، یا حافظه را هدر می‌دهد یا زمان پاسخ را افزایش می‌دهد.

حالت static همه فرآیندها را از ابتدا می‌سازد. تأخیر راه‌اندازی صفر است اما حافظه به‌طور دائم اشغال می‌ماند. برای سرورهای اختصاصی با ترافیک پایدار گزینه خوبی است.

حالت dynamic فرآیندها را بر حسب نیاز می‌سازد و میان حداقل و حداکثر نگه می‌دارد. متعادل‌ترین گزینه برای بیشتر سایت‌های وردپرسی است.

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

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

pm.max_requests و مهار نشتی حافظه

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

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

مقدار پیشنهادی مرسوم بین ۳۰۰ تا ۱۰۰۰ است. مقدار پایین‌تر، حافظه پایدارتری می‌دهد اما هزینه راه‌اندازی مجدد فرآیند را افزایش می‌دهد. مقدار بالاتر، هزینه راه‌اندازی را کم می‌کند اما نشتی حافظه را بیشتر آشکار می‌کند.

اندازه‌گیری دقیق این عدد، مستلزم مشاهده مصرف حافظه فرآیندها در بازه‌های طولانی است. مانیتورینگ سرور در این مرحله ابزار اصلی تصمیم‌گیری است.

Timeout ها و رفتار زیر بار سنگین

دو تنظیم زمانی در PHP-FPM اهمیت دارند: request_terminate_timeout و request_slowlog_timeout. اولی سقف زمانی اجرای یک درخواست را تعیین می‌کند و دومی آستانه ثبت لاگ درخواست‌های کند است.

request_terminate_timeout = 120
request_slowlog_timeout = 10
slowlog = /var/log/php-fpm/www-slow.log

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

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

لاگ درخواست‌های کند ارزشمندتر از هر ابزار مانیتورینگ گران‌قیمت است؛ چون دقیقاً می‌گوید وقت سرور کجا سوخته.

PHP-FPM بدون OPcache پیکربندی ناقصی است. OPcache کد کامپایل‌شده PHP را در حافظه نگه می‌دارد و از کامپایل مجدد در هر درخواست جلوگیری می‌کند. اگر این لایه به‌درستی تنظیم نشود، هر فرآیند PHP زمان زیادی را صرف کامپایل مجدد می‌کند و ظرفیت مؤثر سرور کاهش می‌یابد.

جزئیات این هم‌خوانی خودش موضوعی مستقل است و در تنظیم بهینه OPcache در وردپرس به‌طور کامل بررسی شده است. نکته کلیدی این است که مقدار حافظه OPcache با تعداد فرآیندهای PHP-FPM رابطه مستقیم دارد.

در لایه کش، هماهنگی با افزونه‌های کش وردپرس نیز اهمیت دارد. سایت‌هایی که از بهترین افزونه‌های کش وردپرس استفاده می‌کنند، بار داینامیک را کاهش می‌دهند و سقف منطقی فرآیندهای PHP-FPM را پایین می‌آورند. این برهم‌کنش باید در محاسبه لحاظ شود.

Process Manager و چرخه حیات فرآیند

Process Manager در PHP-FPM مسئول ساخت، بازنشستگی و جایگزینی فرآیندهاست. این چرخه حیات باید با رفتار واقعی سایت هم‌خوان باشد، در غیر این صورت نوسان‌های ناگهانی در ترافیک، سرور را دچار کندی می‌کنند.

مقدار pm.start_servers تعداد فرآیندهایی است که در آغاز راه‌اندازی FPM ساخته می‌شود. مقدار pm.min_spare_servers حداقل فرآیندهای بی‌کار و pm.max_spare_servers حداکثر آن‌ها را تعیین می‌کند.

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

جداسازی استخر برای سایت‌های چندگانه

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

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

نکته دوم: روی هر استخر باید سقف منابع دقیق‌تری اعمال شود. اگر سرور مجموعاً ۸ گیگابایت حافظه دارد و پنج سایت روی آن اجرا می‌شود، هر استخر باید سقفی متناسب با سهم خود داشته باشد، نه سقف کل حافظه.

پایش و اندازه‌گیری واقعی

PHP-FPM یک صفحه وضعیت داخلی دارد که با پیکربندی زیر فعال می‌شود. این صفحه وضعیت دقیق صف، تعداد فرآیندهای فعال و نرخ اشباع را نمایش می‌دهد.

pm.status_path = /status
ping.path = /ping

location ~ ^/(status|ping)$ {
    allow 127.0.0.1;
    deny all;
    include fastcgi_params;
    fastcgi_pass unix:/run/php/php8.2-fpm-wrk.sock;
}

مقدار listen queue مهم‌ترین عدد در این صفحه است. اگر صف پر شود، به این معناست که سقف فرآیندها به پایان رسیده است. این عدد باید در شرایط عادی نزدیک صفر بماند. بالا رفتن مداوم آن، نشانه روشنی است که pm.max_children کمتر از نیاز واقعی است.

در لایه تجربه کاربر نیز معیارهای Core Web Vitals باید اندازه‌گیری شوند. بهبود زمان پاسخ داینامیک، مستقیماً روی بهبود LCP در سایت‌های وردپرسی اثر می‌گذارد و این معیار یکی از سیگنال‌های کیفیت تجربه صفحه است.

برای دیدن تصویر کامل، ترکیب داده PHP-FPM با داده سطح سرور و سطح کاربر ضروری است. این ترکیب، همان مسیری است که در بهینه‌سازی سرور برای افزایش سرعت سایت به‌طور کامل توضیح داده شده است.

جدول تصمیم‌گیری تنظیمات کلیدی

تنظیممقدار محافظه‌کارانهمقدار تهاجمیریسک
pm.max_children۷۰٪ ظرفیت حافظهنزدیک سقف حافظهورود به Swap و افت شدید
pm.max_requests1000300هزینه راه‌اندازی مکرر
request_terminate_timeout120300اشغال طولانی فرآیند
pm.start_servers310مصرف حافظه اولیه بالا

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

نخستین اشتباه، انتخاب pm.max_children بدون محاسبه حافظه است. عددی که روی یک سرور ۱۶ هسته‌ای جواب می‌دهد، روی سرور ۲ هسته‌ای به فاجعه تبدیل می‌شود.

دومین اشتباه، بی‌توجهی به نشتی حافظه در افزونه‌های ضعیف است. مقدار pm.max_requests ابزار مهار این نشتی است، نه یک پارامتر تزئینی.

سومین اشتباه، اجرای همه سایت‌ها روی یک استخر مشترک است. این انتخاب، اثر پروانه‌ای یک سایت مشکل‌دار روی همه سایت‌ها را ممکن می‌سازد.

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

پنجمین اشتباه، فراموش‌کردن لایه پایگاه داده است. اگر کوئری‌ها کند باشند، هر فرآیند PHP زمان بیشتری در اختیار می‌گیرد و اشباع سریع‌تر رخ می‌دهد. در مسیر بهینه‌سازی کوئری‌های MySQL بخش مهمی از همین گلوگاه پوشش داده می‌شود.

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

پرسش‌های پرتکرار درباره تنظیم PHP-FPM برای وردپرس

مقدار مناسب pm.max_children چقدر است؟

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

حالت dynamic بهتر است یا ondemand؟

برای سرورهای اختصاصی با ترافیک پایدار، dynamic گزینه متعادل‌تری است. برای سرورهای اشتراکی با حافظه محدود، ondemand از رقابت بر سر حافظه جلوگیری می‌کند.

چرا سایت در ساعات اوج خطای 502 می‌دهد؟

خطای 502 در ساعات اوج معمولاً از اشباع استخر PHP-FPM می‌آید. مقدار pm.max_children کمتر از نیاز واقعی است یا فرآیندها به دلیل طولانی بودن اجرا، جای خالی برای درخواست‌های جدید باقی نمی‌گذارند.

آیا افزایش pm.max_children همیشه راه‌حل است؟

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

چگونه مطمئن شوم که PHP-FPM درست تنظیم شده است؟

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

آیا این تنظیمات روی سایت‌های اشتراکی هم اعمال می‌شود؟

روی هاست‌های اشتراکی، دسترسی به فایل پیکربندی PHP-FPM معمولاً وجود ندارد. در این حالت باید به انتخاب سرویس مناسب‌تر فکر کرد؛ مقایسه انتخاب هاست مناسب برای وردپرس نقطه شروع درست است.

یک نکته برای ادامه مسیر

تنظیم PHP-FPM یک چرخه است. پیکربندی را می‌سنجید، یک متغیر را تغییر می‌دهید، دوباره می‌سنجید و در صورت لزوم برمی‌گردانید. هر تغییری که بدون اندازه‌گیری اعمال شود، در نهایت به یک معما تبدیل می‌شود.

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