php-fpm 超时,PHP超时的坑
結合去年國慶和過年期間平臺碰到的一些問題,下面主要介紹的是PHP里面會涉及到的各種超時以及其中存在的坑。
Nginx的超時配置
fastcgi_connct_timeout 60
Nginx和fastcgi進程建立連接的超時時間,默認60秒,如果超過了這個時間就斷開連接。
fastcgi_read_timeout 300
和fastcgi進程建立連接后獲得fastcgi進程響應的超時時間,默認60秒,如果超過了這個時間都沒有獲得響應就斷開連接。我們經常碰到的是'504 Gateway Time-out',就是因為后端連接沒有在超時時間內返回數據導致的。我們經常碰到的是'502 Bad Gateway',是因為fastcig進程報錯,導致連接斷開。
fastcgi_send_timeout 300
Nginx向fastcgi進程發送請求的超時時間,默認60秒,如果超過了這個時間都沒有發送完就斷開連接。可以通過上傳比較大的文件,就會出現超時,然后就會返回'504 Gateway Time-out'。
PHP,PHP-FPM 的超時配置
max_execution_time 300
這個參數是在php.ini中設置的,說實在的這個參數沒有什么太大的意義,因為這個300秒的超時時間僅僅是統計本身代碼的執行時間,不包括網絡請求,系統調用,數據庫查詢,sleep()等的時間,如果超過這個時間會產生一個'Fatal error: Maximum execution time'的錯誤,然后返回的是'500 Internal Server Error'。我們程序大部分的時間都是花在網絡請求,數據庫查詢方面的。
request_terminate_timeout 0
這個參數是在php-fpm中設置的,這個超時時間就是整個fastcgi花費的所有時間,這個和max_execution_time最大的不同,如果總時間超過了,會直接將FPM進程kill掉,然后返回'502 Bad Gateway'。很多人認為配置了這個參數max_execution_time就失效了,實際不是的,先達到哪個的超時時間就哪個配置起作用的。
建議是不要開啟這個參數,因為如果你某個程序超時了,進程直接kill掉,你的數據完整性就沒有辦法保證了,可以在nginx那邊做連接超時的控制和做好程序請求第三方資源超時時間的控制。
接口請求方面的超時設置
這部分要特別注意,在沒有什么并發量的時候沒有什么問題,在并發量大的時候,如果有些對接的第三方系統掛了或是處理速度很慢了,你的FPM進程很快就會用完,然后就是各種502,然后很有可能的就是系統崩潰了。我們在框架層面,對需要用到的請求方法做了統一的封裝。
/**
* CURL 提交請求數據,現在基本的接口都是使用curl進行post請求
*
* @author dwer
* @date 2016-04-11
* @param string $url 請求URL
* @param string $postData 請求發送的數據
* @param int $port 請求端口
* @param int $timeout 超時時間
* @param array $headers 請求頭信息
* @return bool|mixed
*/
function pft_curl_post($url, $postData, $port = 80, $timeout = 25, $headers = []) {
//超時時間處理
$timeout = intval($timeout);
$timeout = $timeout <= 0 ? 25 : $timeout;
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $url);
curl_setopt($ch, CURLOPT_PORT, $port);
curl_setopt($ch, CURLOPT_TIMEOUT, $timeout);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_HEADER, 0);
if ((is_array($headers) || is_object($headers)) && count($headers)) {
curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);
}
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_POSTFIELDS, $postData);
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, 0);
$res = curl_exec($ch);
//錯誤處理
$errCode = curl_errno($ch);
if ($errCode > 0) {
curl_close($ch);
return false;
} else {
//獲取HTTP碼
$httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
if ($httpCode != 200) {
curl_close($ch);
return false;
} else {
curl_close($ch);
return $res;
}
}
}
file_get_contents的封裝
/**
* 統一封裝的file_get_contents, 原生的file_get_contents絕對不能使用,沒有設置超時時間,如果碰到網絡問題,這個進程會一直卡在那邊,無情地占用你的網絡連接。
* @author dwer
*
* @param string $url 請求url
* @param integer $timeout 超時時間
* @param array $header 請求頭部
* @return
*/
function pft_file_get_contents($url, $timeout = 10, $header = []){
$url = strval($url);
$timeout = intval($timeout);
$timeout = $timeout <= 0 ? 10 : $timeout;
$contextOptions = [
'http' => ['timeout' => $timeout]
];
if($header) {
$contextOptions['http']['header'] = $header;
}
$context = stream_context_create($contextOptions);
$res = file_get_contents($url, false, $context);
return $res;
}
SoapClient的封裝
/**
* 統一封裝的SOAP客戶端封裝,有些系統還在使用soap協議提供接口
* @author dwer
*
* 用法是一樣的,只是添加了設置超時的時間的方法
* $soapClient = new PftSoapClient('xxx.wsdl');
* $soapClient->setTimeout(25);
* $soapClient->getMyMoney($params);
*/
class PftSoapClient extends \SoapClient {
//超時的時間
private $timeout = 0;
//設置超時時間
public function setTimeout($timeout) {
$timeout = intval($timeout);
$timeout = $timeout <= 0 ? 25 : $timeout;
$this->timeout = $timeout;
}
//請求接口
public function __doRequest($request, $location, $action, $version, $oneWay = FALSE) {
if ($this->timeout <= 0) {
//使用默認的方式
$res = parent::__doRequest($request, $location, $action, $version, $oneWay);
} else {
//使用添加了超時的方式
$socketTime = ini_get('default_socket_timeout');
ini_set('default_socket_timeout', $this->timeout);
$res = parent::__doRequest($request, $location, $action, $version, $oneWay);
ini_set('default_socket_timeout', $socketTime);
}
return $res;
}
}
數據庫,Redis方面的超時
在Mysql和Redis服務器的配置中就會設置wait_timeout 和 timeout 參數,保證連接在超時沒有連接的情況下斷開連接。在程序方面需要做的就是處理超時后的'The MySQL server has gone away' 和 'PHP Fatal error: Uncaught exception 'RedisException' with message 'read error on connection'' 的異常捕獲和重連接處理。不過正常情況下,這些在底層框架應該都做了統一的封裝。
總結
以上是生活随笔為你收集整理的php-fpm 超时,PHP超时的坑的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 魅族年终福利来了!魅族17、18/18s
- 下一篇: php实现电脑自动关机,用批处理实现电脑