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

Nginx 504 Gateway Time-out 排查實戰:罪魁禍首是 PHP cURL 未設超時

     編輯:PHP 相關知識

現象

  • 架構:Nginx 反向代理 → PHP-FPM(原 Apache+mod_php)。
  • 不定期出現 504,Nginx 錯誤日誌:upstream timed out (110: Connection timed out) while reading response header from upstream。
  • 重啟 PHP-FPM 暫時恢復,但特定頁面 /kd/open.php 再次觸發則全站掛掉。

排查過程

  1. netstat -napo | grep php-fpm | wc -l 發現 worker 進程數達上限(10),推測全被該腳本卡住。
  2. /kd/open.php 功能:抓取快遞資訊,使用 php_curl。
  3. 檢查 php.ini 有 max_execution_time = 30,但腳本仍卡死。
  4. 查閱文檔發現:max_execution_time 不包含 系統呼叫、流操作、資料庫查詢、cURL 等外部等待時間。
  5. 原始碼中 完全沒有設定 cURL 超時,導致 PHP 進程永久阻塞等待遠端回應。

解決方案

1. 代碼層面(推薦)

$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $url);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, 10); // 連線階段超時 10 秒
curl_setopt($ch, CURLOPT_TIMEOUT, 10);        // 整個請求超時 10 秒
$response = curl_exec($ch);
curl_close($ch);

2. PHP-FPM 配置層面(兜底)

編輯 www.conf:

request_terminate_timeout = 30s  ; 請求超過 30 秒強制 kill worker
request_slowlog_timeout = 10s    ; 慢請求日誌
slowlog = /var/log/php-fpm/slow.log

重載 PHP-FPM 生效。

3. 命令列腳本防阻塞範例

$limit = 60;
if (pcntl_fork()) {
    // 子進程執行耗時任務
} else {
    sleep($limit);
    posix_kill(posix_getppid(), SIGKILL); // 父進程超時自殺
}

總結

  • 所有外部資源呼叫(cURL、DB、Redis、Socket)必須設定超時。
  • Nginx fastcgi_read_timeout、PHP-FPM request_terminate_timeout 形成多層防護。
  • 善用慢日誌定位問題腳本,避免單點阻塞拖垮整個服務池。
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved