PHP

PHP-FPM pool là gì? Tối ưu worker cho website ít RAM

Hiểu PHP-FPM pool và cách chọn process manager, tính pm.max_children, cấu hình socket, timeout và monitoring để website ít RAM chạy ổn định.

NHT
· 8 phút đọc
Minh họa PHP-FPM pool với các worker process, socket và biểu đồ RAM cho website ít tài nguyên

PHP-FPM pool là lớp cấu hình quyết định một website PHP dùng bao nhiêu worker, lắng nghe ở đâu và phản ứng thế nào khi request tăng. Nếu đặt quá thấp, request xếp hàng và người dùng gặp timeout. Nếu đặt quá cao trên máy ít RAM, các worker cùng phình lên có thể làm swap, OOM hoặc kéo theo lỗi 502/504. Vì vậy, tối ưu PHP-FPM không phải là copy một con số “chuẩn” từ Internet; đó là quá trình đo memory, chọn process manager và kiểm chứng bằng log/metrics.

Bài này giải thích pool, `pm = static/dynamic/ondemand`, `pm.max_children`, socket, timeout, status/ping endpoint và cách xây baseline cho website ít RAM chạy Nginx. PHP Manual xác định `pm.max_children` là giới hạn số child đồng thời và số request có thể phục vụ đồng thời; các chế độ process manager có trade-off khác nhau [1].

Công thức an toàn: RAM dành cho PHP-FPM chia cho RSS trung bình của một worker chỉ là điểm bắt đầu. Giá trị cuối cùng phải được kiểm tra bằng tải thật, memory limit, database, web server, queue và tình trạng swap/OOM.

1. PHP-FPM pool là gì?

PHP-FPM là FastCGI Process Manager. Một master process quản lý nhiều child process; mỗi pool có thể đại diện cho một website hoặc một nhóm workload có cùng user, socket và chính sách tài nguyên. Pool giúp tách cấu hình giữa các site: user/group, `listen`, process manager, timeout, slowlog, status endpoint và giới hạn file script. Khi Nginx nhận request PHP, nó chuyển request đến socket hoặc TCP listener của pool tương ứng.

Trong mô hình nhiều website, tách pool giúp truy vết và giới hạn rủi ro tốt hơn so với một pool dùng chung. Tuy nhiên, mỗi worker vẫn tiêu thụ RAM; tạo quá nhiều pool với `pm.start_servers` hoặc `pm.min_spare_servers` cao sẽ làm máy nhỏ cạn bộ nhớ ngay cả khi traffic thấp.

2. Ba chế độ process manager

Chế độCách hoạt độngPhù hợp khiRủi ro cần theo dõi
staticGiữ số child cố định theo `pm.max_children`Traffic ổn định, cần latency đều và RAM đủGiữ RAM ngay cả lúc rảnh
dynamicKhởi tạo một số child lúc start, tăng/giảm theo spare serversWebsite có traffic dao động và cần cân bằng latency/RAMCấu hình nhiều tham số, dễ đặt quá cao
ondemandChỉ tạo child khi có request, idle quá thời gian sẽ bị hủyWebsite ít traffic, nhiều site trên máy ít RAMCold start, process churn và latency lúc burst

Theo PHP Manual, `static` dùng số child cố định; `ondemand` spawn process khi có request; `dynamic` điều chỉnh dựa trên `pm.max_children`, `pm.start_servers`, `pm.min_spare_servers` và `pm.max_spare_servers` [1]. Không có chế độ nào luôn nhanh nhất. Mục tiêu là cân bằng tail latency, RAM và tần suất request của từng website.

3. `pm.max_children` giới hạn điều gì?

`pm.max_children` là số child tối đa khi pool dùng `dynamic` hoặc `ondemand`, và là số child cố định khi dùng `static`. PHP Manual mô tả nó như giới hạn số request đồng thời mà pool có thể phục vụ. Khi tất cả child đang bận, request mới phải chờ trong backlog hoặc bị timeout ở Nginx/PHP-FPM [1].

Đặt `pm.max_children = 50` không có nghĩa website sẽ luôn phục vụ 50 request nhanh. Nếu mỗi worker dùng 80 MB RSS, riêng PHP-FPM có thể cần khoảng 4 GB, chưa tính OS, Nginx, database, Redis, page cache và overhead. Trên máy ít RAM, giới hạn thấp nhưng đo được thường an toàn hơn con số lớn.

# Quan sát RSS của các worker PHP-FPM
ps -eo pid,user,comm,rss,cmd --sort=-rss | grep '[p]hp-fpm'

# Tổng quan RAM và swap
free -h
swapon --show
vmstat 1 5

4. Công thức baseline cho máy ít RAM

Hãy bắt đầu bằng việc xác định RAM thực sự có thể dành cho PHP-FPM. Ví dụ máy 2 GB không nên lấy toàn bộ 2 GB cho worker; cần chừa phần cho kernel, Nginx, database, cache, SSH, monitoring và đột biến. Một baseline thận trọng có thể dành 35–50% RAM cho PHP-FPM, sau đó chia cho RSS trung bình của worker trong giờ có tải.

RAM dành cho FPM = RAM tổng - OS - Nginx - database - cache - phần dự phòng
pm.max_children_baseline = floor(RAM dành cho FPM / RSS trung bình mỗi worker)

Ví dụ: nếu RAM dành cho FPM là 700 MB và worker có RSS trung bình 70 MB, baseline lý thuyết là 10 child. Đây không phải giá trị phải dùng ngay; hãy bắt đầu thấp hơn nếu database nằm cùng máy, kiểm tra p95 latency và tăng từng bước. RSS thay đổi theo framework, OPcache, route, thư viện ảnh, query và request đang xử lý.

Tình huốngBaseline nên ưu tiênCách xác nhận
Blog/CMS ít traffic`ondemand` hoặc `dynamic` nhỏĐo cold start, p95 và RSS sau vài giờ
Laravel có request nặng`dynamic` với max thấp và timeout rõTheo dõi slowlog, queue, DB latency và 502
Nhiều website nhỏPool riêng, `ondemand` và giới hạn từng poolSo sánh RSS idle/busy, tránh tổng max vượt RAM
Traffic đều, RAM đủ`static` hoặc `dynamic` ổn địnhLoad test và theo dõi saturation

5. Cấu hình pool mẫu cho website ít RAM

Đường dẫn file pool phụ thuộc distro và version PHP, thường nằm trong `/etc/php//fpm/pool.d/`. Hãy backup file hiện tại trước khi sửa, không ghi đè cấu hình production mà chưa lưu version. Ví dụ dưới đây dùng Unix socket, pool riêng cho một site và `ondemand` để giảm số process lúc rảnh.

[technt]
user = techntn2
group = techntn2
listen = /run/php/php8.3-fpm-techntn.sock
listen.owner = www-data
listen.group = www-data
listen.mode = 0660

pm = ondemand
pm.max_children = 6
pm.process_idle_timeout = 10s
pm.max_requests = 500

request_terminate_timeout = 60s
request_slowlog_timeout = 5s
slowlog = /var/log/php8.3-fpm-techntn-slow.log
catch_workers_output = yes
clear_env = yes
security.limit_extensions = .php .phar

Các giá trị trên là baseline minh họa cho máy ít RAM, không phải cấu hình universal. `pm.max_children = 6` chỉ phù hợp nếu RSS worker, workload và RAM còn lại cho phép. `pm.max_requests` có thể giúp recycle worker theo chu kỳ khi thư viện bên thứ ba có xu hướng tăng memory, nhưng nó không thay thế việc tìm memory leak. `request_terminate_timeout` cần đặt phù hợp với route hợp lệ, upload và job; đặt quá thấp có thể cắt request đúng.

6. Socket, quyền file và lỗi 502

PHP-FPM có thể listen trên TCP hoặc Unix socket. Unix socket thường tiện cho các service cùng máy, nhưng Nginx phải truy cập được socket. PHP Manual lưu ý `listen.owner`, `listen.group` và `listen.mode` kiểm soát quyền đọc/ghi khi dùng Unix socket [1]. Nếu Nginx trỏ tới socket không tồn tại, sai version hoặc không có quyền, người dùng có thể gặp 502 Bad Gateway.

sudo systemctl status php8.3-fpm --no-pager
ls -l /run/php/php8.3-fpm-techntn.sock
sudo nginx -t
sudo journalctl -u php8.3-fpm -n 80 --no-pager
tail -n 80 /var/log/nginx/error.log

Khi đổi version PHP, hãy kiểm tra đồng thời file pool, `listen`, `fastcgi_pass` trong Nginx và tên service. Không nên “chữa” bằng cách chmod 777 socket. Hãy đặt owner/group đúng theo web server và reload/restart có kiểm soát. Bạn có thể tham khảo bài [Nginx 502 Bad Gateway] để phân loại lỗi upstream và bài [chạy nhiều phiên bản PHP-FPM] khi tách socket theo version.

7. Monitoring: biết pool đang thiếu hay thừa worker

Không thể tối ưu bằng cách nhìn mỗi CPU. Hãy theo dõi số request đang chờ, active/idle process, max children reached, p95/p99 latency, 5xx, slowlog, RSS, swap, load average và database latency. PHP-FPM có `pm.status_path` để mở status page và `ping.path` để health check; chỉ expose các endpoint này qua mạng nội bộ hoặc allowlist, không mở công khai.

pm.status_path = /fpm-status
ping.path = /fpm-ping
ping.response = pong
# Sau khi cấu hình endpoint nội bộ
curl -sS http://127.0.0.1/fpm-ping
curl -sS http://127.0.0.1/fpm-status?full
# Tìm dấu hiệu chạm max_children
journalctl -u php8.3-fpm --since '1 hour ago' | grep -Ei 'max children|slow|error'

Nếu `max children reached` tăng nhưng RAM còn dư và latency cao, có thể tăng từng bước rồi đo lại. Nếu RAM hoặc swap đã tăng, giảm worker, tối ưu query/cache hoặc tách database trước khi mở giới hạn. Một pool bị nghẽn không nhất thiết cần thêm worker; request chậm do database hoặc API bên ngoài có thể làm toàn bộ child bị giữ lâu hơn.

8. Checklist tuning an toàn

  • Đo RSS trung bình và đỉnh của worker trong workload thực, không dùng số đo lúc idle.
  • Chừa RAM cho OS, Nginx, database, cache, monitoring và burst; tránh dùng toàn bộ RAM cho FPM.
  • Chọn `ondemand` cho site ít traffic hoặc nhiều pool nhỏ; chọn `dynamic` khi cần cân bằng latency và RAM; chỉ dùng `static` khi đã biết workload.
  • Đặt `pm.max_children` theo baseline rồi tăng từng bước, ghi lại latency, RSS và lỗi sau mỗi thay đổi.
  • Kiểm tra socket owner/group/mode, `fastcgi_pass`, service version và `nginx -t` khi đổi PHP.
  • Bật slowlog/status/ping ở phạm vi nội bộ, không expose endpoint monitoring ra Internet.
  • Luôn có backup file pool, lệnh rollback, cửa sổ thay đổi và cách restart/reload đã kiểm thử.

9. Kết luận

PHP-FPM pool là điểm giao giữa hiệu suất và an toàn bộ nhớ. Trên website ít RAM, cấu hình nhỏ nhưng có số liệu tốt hơn cấu hình lớn theo mẫu. Hãy bắt đầu với process manager phù hợp, tính `pm.max_children` từ RAM còn lại và RSS thực tế, sau đó kiểm chứng bằng status, slowlog, access log và tỷ lệ 5xx. Khi có nhiều version PHP hoặc nhiều website, tách pool/socket rõ ràng sẽ giúp chẩn đoán nhanh hơn và tránh một workload chiếm hết tài nguyên.

Nguồn tham khảo

[1] PHP Manual — FPM configuration; [2] PHP Manual — Installing PHP packages on Debian/Ubuntu; [3] NGINX — FastCGI module.