- Tác giả

- Name
- Nguyễn Đức Xinh
- Ngày xuất bản
- Ngày xuất bản
Cấu Hình PHP, PHP-FPM Và PHP CLI Chuẩn Production
Rất nhiều người khi setup một server PHP thường nghĩ đơn giản: cài php, cài php-fpm, cài nginx, trỏ server_name, restart service là xong — web chạy được, vậy là "deploy thành công". Nhưng đó chỉ là điều kiện cần, không phải điều kiện đủ.
Một hệ thống chạy PHP thực sự "hoạt động tốt" phải đáp ứng được ba yếu tố cùng lúc: đúng với phần cứng (RAM, CPU, disk I/O của server), đúng với workload (bao nhiêu request/giây, request nặng hay nhẹ, có nhiều upload file lớn hay không, có chạy background job bằng CLI hay không), và quan trọng không kém là phải được theo dõi (monitoring) và điều chỉnh liên tục theo thời gian. Cấu hình mặc định của PHP và PHP-FPM sau khi cài đặt gần như luôn là cấu hình "an toàn cho mọi máy", tức là không tối ưu cho bất kỳ máy nào cụ thể.
Bài viết này sẽ đi sâu vào các nhóm setting quan trọng nhất của PHP, PHP-FPM và PHP CLI, giải thích cơ chế hoạt động bên dưới, và hướng dẫn cách tính toán con số phù hợp với server thật của bạn thay vì copy-paste một file config mẫu trên mạng.
Nội dung chính:
- PHP hoạt động khác nhau thế nào giữa CLI, FPM và module Apache
- Cách kiểm tra cấu hình thực tế với
phpinfo()vàphp -i - Nhóm setting về memory và upload file
- PHP-FPM Process Manager: static, dynamic, ondemand
- Công thức tính
pm.max_childrentheo RAM thật - PHP CLI vs PHP-FPM: vì sao cùng một
php.ininhưng hành xử khác nhau - OPcache và ảnh hưởng đến performance
- Theo dõi hệ thống: FPM status page, slow log, log phân tích
- Bảng cấu hình mẫu theo từng loại server
- Các lỗi thường gặp và cách chẩn đoán
PHP Hoạt Động Khác Nhau Thế Nào Giữa CLI, FPM Và Module
Trước khi chỉnh bất kỳ setting nào, cần hiểu PHP không chỉ chạy một cách. Có ba "SAPI" (Server API) phổ biến:
- PHP CLI (
php): chạy trực tiếp trong terminal, dùng cho script, cron job, queue worker, Artisan command... Mỗi lần chạy là một process độc lập, khởi động rồi thoát. - PHP-FPM (FastCGI Process Manager): chạy như một service thường trực (daemon), giữ sẵn một pool các process con (worker) để xử lý request HTTP đến từ Nginx/Apache qua giao thức FastCGI.
- Module (mod_php): PHP nhúng trực tiếp vào Apache worker, ngày nay ít dùng cho production vì kém linh hoạt hơn FPM.
Điểm mấu chốt: CLI và FPM đọc hai file cấu hình khác nhau, dù cùng là PHP. Mỗi SAPI có thư mục ini riêng:
php --ini
# Loaded Configuration File: /etc/php/8.3/cli/php.ini
# Scan for additional .ini files in: /etc/php/8.3/cli/conf.d
php-fpm8.3 -i | grep "Loaded Configuration File"
# Loaded Configuration File: /etc/php/8.3/fpm/php.ini
Đây là lý do rất nhiều người "tăng memory_limit rồi mà vẫn lỗi" — họ sửa nhầm file cli/php.ini trong khi web chạy qua fpm/php.ini, hoặc ngược lại.
Kiểm Tra Cấu Hình Thực Tế Với phpinfo() Và php -i
Đừng bao giờ giả định file .ini bạn sửa là file đang thực sự được load. Có ba cách xác minh:
<?php
// info.php — CHỈ dùng tạm khi debug, xoá ngay sau khi dùng xong
phpinfo();
phpinfo() khi truy cập qua trình duyệt sẽ cho biết chính xác SAPI đang chạy (Server API => FPM/FastCGI), đường dẫn php.ini đã load, danh sách file trong conf.d được include, và giá trị hiệu lực (Local Value) so với giá trị mặc định (Master Value) của từng directive.
# Xem toàn bộ thông tin build + config qua CLI
php -i | less
# Xem nhanh một setting cụ thể
php -i | grep -i "memory_limit"
# Kiểm tra pool FPM đang chạy dùng config nào
php-fpm8.3 -tt
Cảnh báo bảo mật: file
info.phpđể lộ đường dẫn hệ thống, phiên bản PHP, biến môi trường... Chỉ đặt tạm thời trên môi trường không public, và xoá ngay sau khi kiểm tra xong.
Cách Thay Đổi Cấu Hình
Biết setting cần sửa là chưa đủ, phải biết sửa đúng nơi và đúng cách thì thay đổi mới có hiệu lực. PHP cho phép chỉnh cấu hình ở nhiều tầng khác nhau, mỗi tầng có phạm vi ảnh hưởng và độ ưu tiên khác nhau.
1. Sửa Trực Tiếp File php.ini
Đây là cách áp dụng cho toàn bộ request/script chạy qua SAPI đó (CLI hoặc FPM). Luôn xác định đúng file bằng php --ini (CLI) hoặc phpinfo() (FPM) trước khi sửa, vì mỗi SAPI có file riêng như đã nói ở trên.
# Sửa file ini tương ứng đúng SAPI
sudo vi /etc/php/8.3/fpm/php.ini
# Hoặc thêm file riêng trong conf.d thay vì sửa trực tiếp php.ini gốc
# (khuyến khích, vì không bị ghi đè khi PHP update)
sudo vi /etc/php/8.3/fpm/conf.d/99-custom.ini
; conf.d/99-custom.ini
memory_limit = 256M
upload_max_filesize = 20M
post_max_size = 24M
Sau khi sửa file ini của FPM, bắt buộc phải reload/restart service thì thay đổi mới có hiệu lực (khác với code PHP, ini không tự nhận theo thời gian thực):
sudo systemctl reload php8.3-fpm
# hoặc restart nếu reload không đủ (ví dụ đổi pool mới hoàn toàn)
sudo systemctl restart php8.3-fpm
Với CLI thì không cần restart gì cả — mỗi lần chạy php là một process mới, tự động đọc lại file cli/php.ini mới nhất.
2. Ghi Đè Theo Từng Pool (Chỉ Áp Dụng Cho FPM)
Một số setting (loại PHP_INI_PERDIR hoặc PHP_INI_ALL) có thể ghi đè riêng cho từng pool ngay trong file pool .conf, không ảnh hưởng đến pool khác dùng chung server:
; pool.d/heavy-jobs.conf
php_admin_value[memory_limit] = 512M
php_admin_value[upload_max_filesize] = 100M
php_admin_flag[display_errors] = off
; php_value cho phép override ở .htaccess/code, php_admin_value thì KHÔNG cho override
php_value[max_execution_time] = 300
Dùng php_admin_value/php_admin_flag khi muốn khoá cứng giá trị (không cho code hoặc ini_set() ghi đè) — phù hợp với các giới hạn bảo mật hoặc giới hạn tài nguyên bắt buộc. Dùng php_value/php_flag khi muốn chỉ đặt giá trị mặc định nhưng vẫn cho phép linh hoạt.
3. Ghi Đè Ngay Trong Code Với ini_set()
Chỉ áp dụng cho các directive thuộc nhóm PHP_INI_ALL hoặc PHP_INI_USER, và chỉ có hiệu lực trong phạm vi request/script hiện tại, không ảnh hưởng request khác:
<?php
// Chỉ nên dùng cho case đặc thù, ví dụ endpoint export báo cáo cần nhiều RAM hơn bình thường
ini_set('memory_limit', '512M');
ini_set('max_execution_time', '300');
Lưu ý: upload_max_filesize và post_max_size thuộc nhóm PHP_INI_PERDIR — không thể đổi bằng ini_set() vì giá trị này cần biết trước khi PHP nhận request (để cấp phát buffer đọc body), lúc code PHP chạy thì request đã được nhận xong rồi. Đây là lý do nhiều người gọi ini_set('upload_max_filesize', ...) mà không thấy tác dụng gì.
4. Truyền Trực Tiếp Khi Chạy CLI
Hữu ích khi muốn test nhanh một giá trị mà không cần sửa file, hoặc muốn một script cụ thể chạy với cấu hình khác biệt so với mặc định:
php -d memory_limit=1G -d display_errors=1 artisan import:large-dataset
Thứ Tự Ưu Tiên Cần Nhớ
Khi cùng một setting được đặt ở nhiều nơi, thứ tự áp dụng (giá trị sau ghi đè giá trị trước) thường là:
php.ini gốc → file trong conf.d (theo thứ tự alphabet) → pool .conf (php_value/php_admin_value) → ini_set() trong code / cờ -d khi chạy CLI
Nếu đổi một setting mà không thấy hiệu lực, hãy kiểm tra lần lượt theo đúng thứ tự trên bằng phpinfo() — cột Local Value luôn cho biết giá trị đang thực sự áp dụng sau khi đã cộng dồn tất cả các tầng ghi đè.
Nhóm Setting Về Memory Và Upload File
Đây là nhóm setting gây lỗi phổ biến nhất cho người mới: memory_limit, upload_max_filesize, post_max_size, max_execution_time, max_input_time, max_input_vars.
; php.ini (fpm)
memory_limit = 256M
upload_max_filesize = 20M
post_max_size = 24M
max_execution_time = 60
max_input_time = 60
max_input_vars = 3000
Giải thích cơ chế:
memory_limit: giới hạn RAM tối đa một request PHP đơn lẻ được phép cấp phát. Đây KHÔNG phải RAM của cả server, mà là per-process. Nếu một request xử lý ảnh lớn, export Excel, hoặc load dataset lớn vào mảng mà vượt quá con số này, PHP sẽ némFatal error: Allowed memory size exhausted.upload_max_filesize: kích thước tối đa của một file trong request upload.post_max_size: kích thước tối đa của toàn bộ body request POST (bao gồm tất cả file + field khác). Bắt buộcpost_max_sizephải lớn hơnupload_max_filesize, nếu không file upload sẽ âm thầm bị bỏ qua (không có exception rõ ràng,$_FILESsẽ rỗng) vì toàn bộ request bị PHP-FPM/Nginx cắt trước khi đến code của bạn.max_execution_time: thời gian tối đa (giây) một script PHP được chạy, không tính thời gian I/O chờ như đọc file, gọi DB ở một số cấu hình — nhưng an toàn nhất là coi đây là tổng thời gian xử lý cho phép.max_input_vars: số lượng biến tối đa được nhận qua GET/POST/COOKIE. Form có nhiều checkbox, bảng dữ liệu lớn dễ vượt ngưỡng mặc định (1000), khiến dữ liệu bị cắt mà không báo lỗi rõ ràng.
Quan trọng: khi tăng upload_max_filesize, phải đồng thời tăng ở ba nơi để nhất quán, nếu không tầng nhỏ nhất sẽ là giới hạn thực tế:
| Tầng | Setting | Ghi chú |
|---|---|---|
| Nginx | client_max_body_size 24m; |
Chặn ở tầng web server trước khi vào PHP |
PHP (post_max_size) |
post_max_size = 24M |
Giới hạn toàn bộ POST body |
PHP (upload_max_filesize) |
upload_max_filesize = 20M |
Giới hạn từng file |
PHP-FPM (request_terminate_timeout) |
tương ứng thời gian upload đủ lớn | Tránh worker bị kill giữa chừng khi upload chậm |
PHP-FPM: Process Manager Là Trái Tim Của Hiệu Năng
PHP-FPM quản lý một pool các worker process. Mỗi request HTTP được một worker xử lý tuần tự — một worker chỉ xử lý một request tại một thời điểm. Điều này có nghĩa: số lượng worker chính là số lượng request đồng thời (concurrent) tối đa mà PHP có thể xử lý cùng lúc, bất kể CPU có bao nhiêu core.
Cấu hình pool nằm ở file riêng, ví dụ /etc/php/8.3/fpm/pool.d/www.conf:
[www]
user = www-data
group = www-data
listen = /run/php/php8.3-fpm.sock
pm = dynamic
pm.max_children = 50
pm.start_servers = 10
pm.min_spare_servers = 5
pm.max_spare_servers = 15
pm.max_requests = 500
request_terminate_timeout = 60s
pm.status_path = /fpm-status
Ba Chế Độ Process Manager
| Chế độ | Cơ chế hoạt động | Phù hợp với |
|---|---|---|
static |
Luôn giữ đúng pm.max_children process, không tăng giảm |
Server dedicated, traffic ổn định, cần độ trễ thấp và dự đoán được RAM |
dynamic |
Tăng/giảm số process linh hoạt trong khoảng min_spare_servers–max_spare_servers, tối đa max_children |
Web server thông thường, traffic dao động theo giờ trong ngày |
ondemand |
Không giữ process nào sẵn, chỉ tạo khi có request đến, tự kill sau khi idle | Server RAM nhỏ, nhiều site cùng chạy, traffic thấp/thất thường |
static cho hiệu năng ổn định nhất (không tốn thời gian fork process mới) nhưng lãng phí RAM nếu traffic thấp. ondemand tiết kiệm RAM nhất nhưng request đầu tiên sau thời gian idle sẽ chậm hơn do phải fork process mới (cold start).
Công Thức Tính pm.max_children
Đây là setting quan trọng nhất và cũng bị cấu hình sai nhiều nhất. Nguyên tắc: pm.max_children phải được tính từ RAM khả dụng, không phải đoán bừa.
pm.max_children = (RAM khả dụng cho PHP-FPM) / (RAM trung bình 1 process PHP)
Cách đo RAM trung bình một process thật (không dùng số ước lượng):
# Xem RAM thực tế từng worker đang dùng
ps -ylC php-fpm8.3 --sort:rss
# Hoặc dùng FPM status page (xem phần Monitoring bên dưới)
Ví dụ thực tế: Server có 4GB RAM, dành 2.5GB cho PHP-FPM (phần còn lại cho MySQL, Nginx, OS), mỗi worker Laravel trung bình dùng 40MB:
pm.max_children = 2.5 * 1024 / 40 ≈ 64
pm.start_servers = 16 # ~25% max_children
pm.min_spare_servers = 8
pm.max_spare_servers = 24
Nếu đặt pm.max_children quá cao so với RAM thật, khi traffic tăng đột biến, server sẽ bị OOM Killer giết process ngẫu nhiên (kể cả MySQL), gây sập toàn bộ hệ thống chứ không chỉ chậm. Nếu đặt quá thấp, request mới phải xếp hàng chờ (queue) khi hết worker, dẫn đến lỗi 502 Bad Gateway từ Nginx dù CPU/RAM server vẫn còn dư — đây là lỗi rất hay gặp và hay bị chẩn đoán nhầm là "server yếu" trong khi thực chất là cấu hình sai.
pm.max_requests Và Rò Rỉ Bộ Nhớ
pm.max_requests = 500
Sau khi xử lý đủ 500 request, worker đó sẽ tự động bị kill và FPM tạo worker mới thay thế. Đây là cơ chế tự dọn dẹp memory leak — nhiều extension PHP hoặc code không tối ưu (đặc biệt code dùng C extension, hoặc opcache/cache layer tự viết) có thể rò rỉ bộ nhớ dần theo thời gian sống của process. Đặt giá trị 0 nghĩa là không bao giờ tự restart, chỉ nên dùng khi bạn chắc chắn code không có memory leak (rủi ro cho production lâu dài).
Multiple Pools Cho Nhiều Loại Workload
Một sai lầm phổ biến: dùng chung một pool cho cả API nhanh và các endpoint xử lý nặng (export báo cáo, xử lý ảnh, gọi API bên thứ ba chậm). Request nặng chiếm giữ worker lâu, làm cạn kiệt worker cho các request nhẹ khác. Giải pháp là tách pool riêng:
; pool.d/api-fast.conf — request nhẹ, cần độ trễ thấp
[api-fast]
listen = /run/php/api-fast.sock
pm = dynamic
pm.max_children = 40
request_terminate_timeout = 10s
; pool.d/heavy-jobs.conf — request nặng, timeout dài hơn
[heavy-jobs]
listen = /run/php/heavy-jobs.sock
pm = static
pm.max_children = 8
request_terminate_timeout = 300s
Sau đó route theo location trong Nginx để mỗi nhóm endpoint trỏ đến đúng socket.
PHP CLI vs PHP-FPM: Vì Sao Cùng Config Nhưng Hành Xử Khác Nhau
Một điểm hay gây nhầm lẫn: PHP CLI mặc định memory_limit = -1 (không giới hạn), trong khi PHP-FPM luôn có giới hạn cụ thể. Lý do là script CLI thường là batch job, migration, queue worker chạy nền — cần xử lý dataset lớn và không có khái niệm "một request per user" như web.
Tuy nhiên, điều này cũng là con dao hai lưỡi: một cron job hoặc queue worker (ví dụ Laravel Horizon, Supervisor) bị lỗi vòng lặp vô hạn có thể ăn hết RAM server nếu không giới hạn tường minh:
; /etc/php/8.3/cli/conf.d/99-custom.ini
memory_limit = 512M
Hoặc giới hạn trực tiếp khi chạy:
php -d memory_limit=512M artisan queue:work
Bảng khác biệt cấu hình mặc định giữa CLI và FPM:
| Setting | PHP CLI mặc định | PHP-FPM mặc định | Ghi chú |
|---|---|---|---|
memory_limit |
-1 (không giới hạn) |
128M |
CLI nên set tường minh cho long-running job |
max_execution_time |
0 (không giới hạn) |
30 |
Script CLI thường chạy lâu, hợp lý |
display_errors |
On (thường) |
Off ở production |
Web tuyệt đối không hiện lỗi ra ngoài |
opcache.enable_cli |
Off |
(không áp dụng, luôn bật cho FPM) | Bật riêng nếu CLI script chạy lặp nhiều lần trong thời gian ngắn |
Với Supervisor/systemd chạy queue worker liên tục, nên gắn thêm giám sát RAM theo thời gian vì các process này sống rất lâu (khác với FPM có pm.max_requests tự dọn).
OPcache: Tăng Tốc Bằng Cache Bytecode
Không cấu hình OPcache đúng cách gần như luôn khiến PHP chậm hơn 2-3 lần so với tiềm năng thực tế, vì PHP phải parse + compile lại toàn bộ file .php thành opcode ở mỗi request.
[opcache]
opcache.enable = 1
opcache.memory_consumption = 256
opcache.interned_strings_buffer = 16
opcache.max_accelerated_files = 20000
opcache.validate_timestamps = 0
opcache.revalidate_freq = 0
opcache.save_comments = 1
opcache.jit = tracing
opcache.jit_buffer_size = 128M
Giải thích:
opcache.memory_consumption: vùng nhớ (MB) để cache opcode đã biên dịch. Dự án lớn (nhiều file, framework như Laravel/Symfony) cần tối thiểu 128-256MB, kiểm tra tỷ lệused/free memoryquaopcache_get_status()để canh chỉnh.opcache.max_accelerated_files: số file tối đa được cache. Đặt thấp hơn số file thực tế của project (bao gồm cảvendor/) sẽ khiến cache liên tục bị "restart" (wasted restart), giảm hiệu quả gần như về 0. Luôn đếmfind . -name "*.php" | wc -lrồi cộng thêm buffer 20-30%.opcache.validate_timestamps = 0: tắt kiểm tra file có bị sửa đổi hay không — cực nhanh nhưng có nghĩa là deploy code mới sẽ không được nhận cho đến khi reload FPM. Đây là cấu hình chuẩn cho production (kết hợpphp-fpm reloadsau mỗi lần deploy). Ở môi trường dev, luôn đểvalidate_timestamps = 1để thấy code thay đổi ngay lập tức.opcache.jit: PHP 8+ có JIT compiler, hữu ích cho workload tính toán nặng (CPU-bound), nhưng ảnh hưởng không đáng kể với workload I/O-bound thông thường (web app gọi DB/API là chủ yếu) — cân nhắc bật/tắt dựa trên benchmark thực tế thay vì mặc định bật.
Theo Dõi Và Giám Sát Hệ Thống (Monitoring)
Cấu hình đúng lúc ban đầu là chưa đủ — workload thay đổi theo thời gian (traffic tăng dần, feature mới nặng hơn), nên phải theo dõi liên tục để điều chỉnh lại.
FPM Status Page
pm.status_path = /fpm-status
location = /fpm-status {
allow 127.0.0.1;
deny all;
fastcgi_pass unix:/run/php/php8.3-fpm.sock;
include fastcgi_params;
}
curl http://127.0.0.1/fpm-status?full
Các chỉ số quan trọng cần theo dõi:
active processesgần chạmpm.max_childrenliên tục → cần tăngmax_childrenhoặc thêm server.listen queuekhác 0 → request đang phải xếp hàng chờ worker, dấu hiệu rõ ràng nhất của thiếu worker.max children reachedtăng dần theo thời gian → đã từng bị nghẽn cổ chai ít nhất một lần.
Slow Log
slowlog = /var/log/php-fpm/slow.log
request_slowlog_timeout = 5s
Khi một request chạy quá 5 giây, FPM ghi lại full backtrace của request đó vào slow log — cực kỳ hữu ích để tìm ra query chậm hoặc vòng lặp không tối ưu mà không cần cài thêm APM.
Log Phân Tích Khác
- Nginx access log +
$upstream_response_time: phát hiện endpoint nào chậm dần theo traffic. error_logcủa PHP-FPM: theo dõiWARNING: [pool www] server reached max_children.- Công cụ ngoài: Prometheus +
php-fpm_exporter, New Relic, Blackfire để có dashboard trực quan và cảnh báo tự động thay vì đọc log tay.
Bảng Cấu Hình Mẫu Theo Từng Loại Server
| Loại server | RAM | pm |
pm.max_children |
memory_limit |
opcache.memory_consumption |
|---|---|---|---|---|---|
| VPS nhỏ, 1 site, traffic thấp | 1GB | ondemand |
8-10 | 128M | 64 |
| Server vừa, 1-2 site | 4GB | dynamic |
40-60 | 256M | 128 |
| Server production, traffic cao | 8GB+ | static |
100-150 | 256-512M | 256-512 |
| Shared hosting nhiều site nhỏ | 2GB | ondemand |
tuỳ site, 5-15 mỗi pool | 128M | 64 mỗi pool |
Đây chỉ là điểm khởi đầu tham khảo — con số chính xác luôn phải được xác nhận lại bằng đo đạc RAM/CPU thực tế trên chính server đó, không phải copy nguyên bảng này.
Các Lỗi Thường Gặp Và Cách Chẩn Đoán
| Triệu chứng | Nguyên nhân thường gặp | Cách kiểm tra |
|---|---|---|
502 Bad Gateway khi traffic tăng |
pm.max_children quá thấp, worker bị nghẽn |
Xem fpm-status, cột listen queue |
Upload file bị mất, $_FILES rỗng |
post_max_size nhỏ hơn upload_max_filesize, hoặc Nginx client_max_body_size quá nhỏ |
Kiểm tra cả 3 tầng cấu hình liên quan |
Allowed memory size exhausted |
memory_limit quá thấp so với dữ liệu thực tế xử lý |
Tìm dòng code cụ thể trong error log, xem có thể tối ưu bằng cách xử lý theo batch/generator thay vì load hết vào mảng |
| Deploy code mới nhưng web vẫn chạy code cũ | opcache.validate_timestamps = 0 nhưng quên reload FPM sau deploy |
Thêm php-fpm reload vào script deploy |
| Server bị OOM Killer giết random process | pm.max_children đặt quá cao so với RAM thật |
Tính lại theo công thức RAM khả dụng / RAM trung bình mỗi worker |
| Queue worker ăn RAM dần theo thời gian | Memory leak trong code, CLI không có pm.max_requests tự dọn |
Set memory_limit tường minh, dùng Supervisor tự restart worker định kỳ |
Best Practices Checklist
- Luôn xác minh SAPI và file
.iniđang thực sự được load trước khi chỉnh sửa (php --ini,phpinfo()). - Đồng bộ giới hạn upload ở cả ba tầng: Nginx,
post_max_size,upload_max_filesize. - Tính
pm.max_childrentừ RAM thật đo được, không đoán theo cảm tính. - Tách pool riêng cho endpoint nặng và endpoint nhẹ khi traffic đủ lớn.
- Bật
opcache.validate_timestamps = 0ở production, luônreloadFPM sau deploy. - Giới hạn
memory_limittường minh cho CLI worker chạy dài hạn (queue, cron). - Bật FPM status page + slow log ngay từ đầu, đừng đợi đến khi sự cố xảy ra mới thêm.
- Review lại toàn bộ config định kỳ (theo quý, hoặc sau mỗi lần traffic tăng đột biến), vì workload không đứng yên.
Kết Luận
Cài đặt PHP, PHP-FPM và Nginx chỉ là bước đầu tiên trong một quy trình lớn hơn nhiều: đo đạc phần cứng, hiểu workload thực tế, cấu hình dựa trên số liệu, rồi liên tục theo dõi và điều chỉnh. Một hệ thống PHP "chạy được" và một hệ thống PHP "chạy tốt, ổn định dưới tải cao, và dễ chẩn đoán khi có sự cố" là hai câu chuyện hoàn toàn khác nhau — khoảng cách giữa chúng chính là những setting đã trình bày ở trên.
Hãy xem việc tuning này là một vòng lặp liên tục chứ không phải một lần cấu hình xong là xong: đo đạc → cấu hình → theo dõi → phát hiện điểm nghẽn → điều chỉnh lại. Đó mới là cách vận hành một hệ thống PHP thực sự sẵn sàng cho production.
