Skip to Content

چگونه PHP-FPM را برای سرور بهینه کنیم؟ تنظیم Pool، Worker، Queue و Memory

PHP-FPM را با اندازه‌گیری حافظه worker، concurrency، queue، slow log و ظرفیت CPU/RAM تنظیم کنید و تغییرات را مرحله‌ای و قابل بازگشت اجرا کنید.

نویسنده مدیر کل تاریخ انتشار
این پست را به اشتراک بگذارید

بهینه‌سازی PHP-FPM با کپی کردن یک مقدار بزرگ برای pm.max_children انجام نمی‌شود. pool باید میان concurrency، حافظه هر worker، CPU، زمان درخواست و ظرفیت دیتابیس تعادل ایجاد کند. worker کم صف می‌سازد؛ worker زیاد RAM را تمام، cache CPU را شلوغ و dependencyها را اشباع می‌کند.

پاسخ سریع: ابتدا نرخ درخواست dynamic، p95 زمان PHP، queue و اندازه واقعی workerها را اندازه بگیرید. سپس process manager مناسب را انتخاب و سقف worker را داخل بودجه RAM/CPU تنظیم کنید. slow request را به URL و Query وصل کنید؛ config را اعتبارسنجی و تغییر را مرحله‌ای با rollback و monitoring اجرا کنید.

PHP-FPM چه چیزی را مدیریت می‌کند؟

PHP-FPM مجموعه processهایی است که درخواست FastCGI را اجرا می‌کنند. وب‌سرور درخواست PHP را به socket یا TCP pool می‌فرستد. تنظیم pool ظرفیت اجرای هم‌زمان را کنترل می‌کند، اما کد کند، Query بد یا API بیرونی را سریع نمی‌کند. مقاله تأثیر PHP-FPM بر سرعت وردپرس معماری درخواست را توضیح می‌دهد.

قبل از تغییر چه داده‌ای لازم است؟

  • CPU و RAM قابل‌اختصاص پس از سهم دیتابیس و سیستم
  • اندازه RSS/PSS workerهای واقعی در workload عادی و اوج
  • نرخ و concurrency درخواست‌های PHP
  • p50/p95/p99 زمان پردازش
  • طول queue و رسیدن به سقف child
  • نرخ 502/504 و restart processها
  • مسیرهای کند، cron و jobهای طولانی

میانگین حافظه ممکن است workerهای سنگین را پنهان کند. نمونه باید پس از warm شدن برنامه و در سناریوهای admin، API و Checkout گرفته شود. داده production را بدون cookie، query حساس یا اطلاعات مشتری منتشر نکنید.

سه حالت Process Manager

static

تعداد ثابت child نگه می‌دارد. رفتار ظرفیت قابل‌پیش‌بینی است اما در زمان بیکاری نیز حافظه رزرو می‌شود. برای workload پایدار و ظرفیت دقیق می‌تواند مناسب باشد، به شرط بودجه RAM روشن.

dynamic

بین حداقل و حداکثر، بر اساس spare processها child می‌سازد یا کم می‌کند. برای ترافیک متغیر رایج است، اما مقادیر start/min/max spare باید با الگوی burst هماهنگ باشند.

ondemand

هنگام درخواست process ایجاد می‌کند و idleها را می‌بندد. برای سایت کم‌ترافیک حافظه را آزاد می‌کند، ولی cold start و burst سریع باید سنجیده شود. هیچ حالت به‌صورت جهانی برتر نیست.

pm.max_children چگونه تعیین شود؟

ابتدا RAMی را که پس از kernel، وب‌سرور، دیتابیس، cache، agent و headroom باقی می‌ماند مشخص کنید. سپس آن را با توزیع واقعی حافظه workerها بسنجید، نه یک عدد اینترنتی. سقف حاصل باید با تعداد core، latency و ظرفیت دیتابیس نیز محدود شود. RAM تنها قید نیست.

اگر هر child درخواست CPU-bound اجرا کند، صدها child روی چند core فقط context switch و queue پایین‌دست می‌سازند. اگر درخواست‌ها بیشتر منتظر I/O هستند، concurrency بالاتر ممکن است مفید باشد، ولی timeout و dependency باید کنترل شوند.

Spare Serverها و Burst

در حالت dynamic، processهای آماده باید burst معمول را بدون fork storm پاسخ دهند، اما تعداد زیاد idle حافظه را نگه می‌دارد. نرخ ورود درخواست و زمان ساخت child را اندازه بگیرید. تغییرات کوچک و مشاهده queue بهتر از جهش بزرگ در چند پارامتر است.

pm.max_requests چه کاربردی دارد؟

بازیافت دوره‌ای worker می‌تواند اثر رشد حافظه کتابخانه یا extension را محدود کند، اما درمان leak نیست. مقدار بسیار پایین overhead ساخت process و cache warming را بالا می‌برد؛ مقدار بسیار بالا leak را طولانی‌تر نگه می‌دارد. روند حافظه و هزینه restart معیار انتخاب‌اند.

Status Page را امن فعال کنید

status pool می‌تواند active/idle process، queue و سقف ظرفیت را نشان دهد. endpoint نباید عمومی باشد؛ آن را فقط از شبکه یا authentication مانیتورینگ در دسترس قرار دهید و proxy rule را محدود کنید. داده status را با latency و request rate روی یک timeline جمع کنید.

Slow Log برای درخواست‌های طولانی

request_slowlog_timeout و slowlog می‌توانند stack درخواست طولانی را ثبت کنند. threshold باید آن‌قدر پایین نباشد که log flood بسازد و آن‌قدر بالا نباشد که فقط timeout نهایی را ببیند. log ممکن است مسیر کد و داده حساس داشته باشد؛ permission و retention لازم است.

Timeout و پایان دادن به Request

سقف اجرای PHP، timeout FPM، Nginx و client لایه‌های متفاوت‌اند. افزایش همه آن‌ها برای import طولانی worker را بیشتر اشغال می‌کند. عملیات طولانی را تا حد امکان به queue/CLI منتقل کنید. kill اجباری request ممکن است write نیمه‌تمام بسازد؛ idempotency و transaction اهمیت دارد.

Pool جدا برای Workload متفاوت

سایت‌ها یا مسیرهای با سطح اعتماد و الگوی منابع متفاوت می‌توانند pool جدا با user، socket و limit مستقل داشته باشند. این جداسازی blast radius را کم می‌کند، اما مجموع سقف poolها باید در ظرفیت host جا شود. ساخت چند pool بدون بودجه مشترک overcommit را پنهان می‌کند.

Socket، Permission و Nginx

listen pool باید دقیقاً با fastcgi_pass وب‌سرور مطابق باشد. مالکیت و mode socket باید حداقل دسترسی لازم را بدهد؛ 777 راه‌حل نیست. پس از ارتقای PHP، مسیر socket و unit فعال را بررسی کنید. خطای 502 Nginx اغلب از همین مرز ظاهر می‌شود.

OPcache و FPM

OPcache از کامپایل تکراری bytecode جلوگیری می‌کند و تنظیم آن به اندازه codebase، deploy و حافظه بستگی دارد. کمبود فضای cache می‌تواند churn بسازد؛ اختصاص بیش‌ازحد نیز RAM سایر سرویس‌ها را می‌گیرد. invalidation و restart در deploy باید روشن باشد تا کد قدیمی یا downtime ناخواسته ایجاد نشود.

PHP Memory Limit را اشتباه تفسیر نکنید

memory_limit برای هر اجرای PHP اعمال می‌شود و سقف کل pool نیست. بالا بردن آن ممکن است یک request را نجات دهد اما ریسک مصرف هم‌زمان را بالا ببرد. خطای memory باید به plugin، dataset یا مسیر کد وصل شود؛ سپس سقف لازم با ظرفیت pool هماهنگ گردد.

دیتابیس و Downstream را فراموش نکنید

افزایش child می‌تواند connection و Query بیشتری به دیتابیس بفرستد و latency را بدتر کند. Redis، API پرداخت و filesystem نیز سقف دارند. هنگام آزمون FPM، connection pool، slow query، dependency latency و error rate را هم‌زمان ببینید.

روش تغییر امن

  1. config و metric baseline را ذخیره کنید.
  2. یک فرضیه و یک گروه پارامتر مرتبط انتخاب کنید.
  3. syntax را با binary همان نسخه PHP اعتبارسنجی کنید.
  4. تغییر را ابتدا در staging یا بخشی از ترافیک اعمال کنید.
  5. reload کنترل‌شده و وضعیت childها را بررسی کنید.
  6. صف، latency، RAM، CPU و خطا را مقایسه کنید.
  7. اگر معیار بدتر شد با config نسخه‌دار rollback کنید.

نام binary و unit میان توزیع‌ها و نسخه‌های PHP فرق دارد؛ فرمان نسخه حدسی را در production اجرا نکنید. مسیر config مؤثر را از همان سرویس فعال به دست آورید.

چگونه بفهمیم Worker کم است؟

رسیدن مکرر به max active، صف رو‌به‌رشد و latency انتظار با CPU/RAM دارای headroom سرنخ است. اگر workerها خودشان بسیار کندند، افزودن child ممکن است فقط backlog را به دیتابیس منتقل کند. زمان queue و زمان execution را جدا اندازه بگیرید.

چگونه بفهمیم Worker زیاد است؟

swap، OOM، context switch، CPU saturation و افت latency در concurrency بالا نشانه‌اند. اگر مجموع memory سقف poolها از RAM عبور می‌کند، خطر حتی در ترافیک عادی پنهان است. راهنمای مصرف RAM سرور برای تفکیک cache و pressure مفید است.

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

  • کپی عدد pm.max_children از سرور دیگر
  • محاسبه بر اساس RAM کل بدون سهم دیتابیس
  • افزایش child برای رفع Query کند
  • عمومی کردن status page
  • slow log دائمی و بدون retention
  • تغییر چند پارامتر هم‌زمان
  • reload بدون syntax test و rollback
  • یکی دانستن memory_limit با حافظه کل FPM

چه زمانی کمک تخصصی لازم است؟

اگر سایت میان صف طولانی، 502 و OOM جابه‌جا می‌شود، تنظیم یک عدد مشکل را به لایه دیگری منتقل می‌کند. مدیریت ماهانه سرور می‌تواند FPM، Nginx، دیتابیس و memory budget را با workload واقعی اندازه‌گیری و مرحله‌ای تنظیم کند.

پرسش‌های متداول

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

عدد عمومی ندارد؛ حافظه واقعی worker، RAM قابل‌اختصاص، CPU، latency و ظرفیت downstream تعیین‌کننده‌اند.

Dynamic بهتر است یا Ondemand؟

به الگوی ترافیک و حساسیت cold start بستگی دارد. با workload واقعی و metric queue تصمیم بگیرید.

آیا افزایش worker سایت را سریع می‌کند؟

فقط اگر صف ناشی از کمبود concurrency باشد و منابع و downstream ظرفیت داشته باشند؛ کد یا Query کند را اصلاح نمی‌کند.

آیا برای تغییر FPM باید سرور reboot شود؟

معمولاً مدیریت همان سرویس کافی است، اما روش دقیق به توزیع و نسخه وابسته است؛ syntax و رفتار reload را بررسی کنید.

OOM Killer چیست و چرا سرویس‌ها را می‌بندد؟ تشخیص فشار حافظه و جلوگیری از تکرار
OOM Killer را از لاگ kernel، cgroup و روند RAM تشخیص دهید؛ process قربانی را از عامل فشار جدا کنید و ظرفیت، limit و concurrency را اصولی اصلاح کنید.