在 Nginx + PHP-FPM 架構中,執行時間限制由三層共同決定:PHP 內部、PHP-FPM 進程管理、Nginx 反向代理。任一層設定過低皆會導致 504 Gateway Timeout。本文系統梳理三層設定與排查步驟。
請求流向: Client → Nginx → PHP-FPM (master) → PHP-FPM (worker) → PHP 腳本
│ │ │
│ │ └─ request_terminate_timeout
│ └─ fastcgi_read_timeout / proxy_read_timeout
└─ max_execution_time / set_time_limit()
; php.ini
max_execution_time = 300 ; 秒,0 為無限制 (僅限 CLI 建議),Web 建議 300-600
max_input_time = 300 ; 解析輸入資料時間 (POST/GET/檔案上傳)
memory_limit = 256M ; 記憶體上限,防止腳本耗盡資源
<?php
// 設定無限制 (長時間任務如匯出、同步)
set_time_limit(0);
// 或設定具體秒數
ini_set('max_execution_time', 600);
// 注意:set_time_limit() 在安全模式下無效;若腳本被 system call (如 sleep) 阻塞,時間不計入
?>
編輯 php-fpm.conf 或 pool 設定檔 (如 www.conf):
; 進程處理單一請求的最長時間,超過則殺掉 worker 進程
; 預設值通常是 30s 或 0 (關閉)
; 若 PHP 的 max_execution_time 失效 (如死循環、C 擴充阻塞),此設定為最後防線
request_terminate_timeout = 300s ; 建議與 PHP max_execution_time 一致
; 進程閒置超過此時間則被回收 (節省記憶體)
pm.max_idle_timeout = 60s
; 請求緩衝區大小,防止大 POST 截斷
request_max_body_size = 10M
重要:修改後必須 重載 PHP-FPM:systemctl reload php-fpm 或 kill -USR2 $(cat /run/php-fpm.pid)。
# nginx.conf 或 site-conf
location ~ \.php$ {
fastcgi_pass unix:/run/php/php-fpm.sock; # 或 127.0.0.1:9000
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
include fastcgi_params;
# 關鍵:FastCGI 讀取回應超時 (預設 60s)
fastcgi_read_timeout 300s;
fastcgi_send_timeout 300s; # 發送請求給 PHP-FPM 超時
fastcgi_connect_timeout 300s; # 連線 PHP-FPM 超時
# 若使用 proxy_pass 而非 fastcgi_pass
# proxy_read_timeout 300s;
# proxy_send_timeout 300s;
# proxy_connect_timeout 300s;
}
upstream timed out。max_execution_time = 300 已足夠。<?php
set_time_limit(0);
sleep(40);
echo 'done';
?>
仍 30 秒超時 → set_time_limit 未生效或被上層截斷。request_terminate_timeout = 30s!改為 300s 重載 → 仍超時。request_terminate_timeout = 0s (關閉),重載 → 正常執行完成。fastcgi_read_timeout 等設為 300s,防止 Nginx 先切斷。若 Nginx 使用 upstream 負載均衡:
upstream php_backend {
server 127.0.0.1:9001;
server 127.0.0.1:9002;
# keepalive 連線池,減少建立連線開銷
keepalive 32;
}
location ~ \.php$ {
fastcgi_pass php_backend;
# ... 其他設定 ...
fastcgi_read_timeout 300s;
fastcgi_send_timeout 300s;
fastcgi_connect_timeout 300s;
# 重要:啟用 keepalive 時需加此行
fastcgi_keep_conn on;
}
| 誤區 | 正確認知 |
|---|---|
| 只改 php.ini 的 max_execution_time | PHP-FPM 的 request_terminate_timeout 會強制殺進程,Nginx 的 fastcgi_read_timeout 會切連線 |
| set_time_limit(0) 就萬事大吉 | system call (sleep、資料庫查詢、curl、shell_exec) 不計入執行時間;且受限於上層超時 |
| Nginx 只需改 proxy_read_timeout | 用 fastcgi_pass 時必須改 fastcgi_read_timeout;proxy_* 僅對 proxy_pass 生效 |
| 設定 0 代表無限制最安全 | 生產環境建議設定合理上限 (如 300-600s),防止異常腳本佔用資源導致雪崩 |
# php.ini
max_execution_time = 300
# php-fpm.d/www.conf
request_terminate_timeout = 300s
# nginx.conf (location ~ \.php$)
fastcgi_read_timeout 300s;
fastcgi_send_timeout 300s;
fastcgi_connect_timeout 300s;
# 長任務腳本內
set_time_limit(600); // 視實際需求調大
ignore_user_abort(true); // 即使使用者關閉瀏覽器也繼續執行 (匯出、同步任務適用)