在處理大量資料匯出、長時間運算任務時,Nginx 504 Gateway Time-out 是最常見的阻礙。本文記錄一次 Excel 匯出 2 萬筆、每筆 50 欄位導致的 10 分鐘超時案例,完整呈現從現象分析、配置調整到根因解決的全過程。
upstream timed out (110: Connection timed out) while reading response header from upstream504 錯誤本質是 Nginx 作為反向代理,在等待上游(PHP-FPM)回應時超時。常見三大原因:
本案例屬於第 1 類:PHP 腳本執行時間超過 Nginx 與 PHP-FPM 的預設超時閾值。
請求鏈路:Client → Nginx → PHP-FPM → PHP Script,每層都有獨立超時控制:
# /etc/nginx/nginx.conf 或站點配置中
location ~ \.php$ {
fastcgi_connect_timeout 1200s; # 連線上游超時,預設 60s
fastcgi_send_timeout 1200s; # 向上游傳送請求超時,預設 60s
fastcgi_read_timeout 1200s; # 等待上游回應超時,預設 60s **最關鍵**
fastcgi_buffer_size 64k;
fastcgi_buffers 4 64k;
fastcgi_busy_buffers_size 128k;
fastcgi_temp_file_write_size 256k;
}
關鍵說明:
fastcgi_read_timeout:Nginx 等待 PHP-FPM 回應的最長時間,**必須大於 PHP 腳本最大執行時間**; /etc/php-fpm.d/www.conf request_terminate_timeout = 0 ; 0 表示無限制,單位秒 ; 預設為 0,但受限於 php.ini 的 max_execution_time
; php.ini max_execution_time = 300 ; CLI 模式無效,僅對 mod_php 生效 ; PHP 程式碼中動態設定(最高優先級) set_time_limit(0); // 0 = 無限制,單位秒
重要機制: set_time_limit() 是**重置計時器**,而非累加。例如預設 30 秒,執行 25 秒後呼叫 set_time_limit(20),總允許時間變為 45 秒(25+20)。
修改配置後重載服務:
nginx -t && systemctl reload nginx systemctl reload php-fpm
結果:504 錯誤消失,但頁面空白、無檔案下載 → PHP 仍在超時中終止。
set_time_limit() 呼叫request_terminate_timeout = 0 已關閉強制終止max_execution_time 或 PHP 內部機制生效在匯出函數入口加入:
// 匯出函數開頭
set_time_limit(0); // 移除執行時間限制
ini_set('memory_limit', '512M'); // 同步調大記憶體
結果:匯出成功完成,檔案正常下載。
| 層級 | 參數 | 長任務建議值 | 說明 |
|---|---|---|---|
| Nginx | fastcgi_read_timeout | 3600s (1小時) | 視最大任務時長而定,預留緩衝 |
| PHP-FPM | request_terminate_timeout | 0 (關閉) | 交由腳本層控制 |
| PHP 腳本 | set_time_limit() | 0 或具體秒數 | 程式碼中動態控制,彈性最高 |
| PHP 腳本 | memory_limit | 512M/1G | 大量資料處理必須調大 |
若任務常態化超過 5 分鐘,建議採用**非同步處理架構**:
fopen('php://output') 邊生成邊輸出,避免記憶體飆升max_execution_time 對 CLI/FPM 生效 → **無效**此案例印證了「分層超時、逐層突破」的排查邏輯。遇到 504 時,請沿著請求鏈路由外而內、由基礎設施到應用程式碼逐層檢查,定能精準定位瓶頸。