首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> 網頁程式設計 >> PHP 程式設計 >> PHP 相關知識

PHP-FPM (Nginx) 環境下解決腳本執行超時 (504 Gateway Timeout) 完整設定指南

     編輯:PHP 相關知識

在 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 內部設定

php.ini (全域)

; php.ini
max_execution_time = 300  ; 秒,0 為無限制 (僅限 CLI 建議),Web 建議 300-600
max_input_time = 300      ; 解析輸入資料時間 (POST/GET/檔案上傳)
memory_limit = 256M       ; 記憶體上限,防止腳本耗盡資源

腳本內動態修改 (最高優先級,蓋過 php.ini)

<?php
// 設定無限制 (長時間任務如匯出、同步)
set_time_limit(0); 

// 或設定具體秒數
ini_set('max_execution_time', 600);

// 注意:set_time_limit() 在安全模式下無效;若腳本被 system call (如 sleep) 阻塞,時間不計入
?>

第二層:PHP-FPM 進程管理 (關鍵且常被忽略)

編輯 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 反向代理超時

# 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;
}

排查實戰:從 504 找到真兇

  1. 現象:匯出 500 筆資料,約 150 筆時 Nginx 回 504,錯誤日誌 upstream timed out。
  2. 檢查 php.ini:max_execution_time = 300 已足夠。
  3. 測試腳本:
    <?php
    set_time_limit(0);
    sleep(40);
    echo 'done';
    ?>
    仍 30 秒超時 → set_time_limit 未生效或被上層截斷。
  4. 檢查 php-fpm.conf:發現 request_terminate_timeout = 30s!改為 300s 重載 → 仍超時。
  5. 終極解法:將 request_terminate_timeout = 0s (關閉),重載 → 正常執行完成。
  6. 同步調整 Nginx:將 fastcgi_read_timeout 等設為 300s,防止 Nginx 先切斷。

負載均衡 (Upstream) 額外設定

若 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_timePHP-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); // 即使使用者關閉瀏覽器也繼續執行 (匯出、同步任務適用)
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved