首先,這裏講的站羣服務器環境(lnmp)是指 linux + nginx + php(php-cgi + php-fpm)+ mysql 。
502 Bad Gateway 是 lnmp 下出現得最頻繁的問題,其原因也有很多,以下是我收集的問題原因及其解決方法。
1. php 程序死亡
此原因的問題表現為:每次動態(php)請求都出現 502 錯誤
解決方法:啓動 php 即可 “service php-fpm start ”,或者 “php 安裝路徑/php/sbin/php-fpm start”
2. php-cgi 程序數不足
此原因的問題表現為:動態請求有時出現 502 錯誤,一般沒問題,這是併發高時 php-cgi 程序數不夠用的表現
解決方法:修改 php-fpm 配置 php-fpm.conf,將
3. php-cgi 程序超時
此原因的問題表現為:php 程序執行一段時間後出現 502 錯誤,這種情況可能是 php 程式沒有加 set_time_limit(0),也可能是被 php-fpm 的設定限定了執行時間,下面討論第二中情況
解決方法:修改 php-fpm 配置 php-fpm.conf,將
4. 磁碟空間不足
此原因較少,問題表現為:502 錯誤或者無法連線到站羣服務器,無法連線到站羣服務器時 nginx 也死了
這種情況的判斷:啓動 php-fpm 或者 nginx 的時間較長,但最終啓動失敗,這大概就是磁碟空間不足了,然後可以用命令檢視磁碟佔用狀況:df -lh ,如果根目錄 “/” 對應的磁碟使用率為 100%,那麼需要清理磁碟空間
解決方法:刪除過大的日誌檔案,關閉部分服務元件的日誌。一般需要檢查 /var/log 目錄下的日誌檔案,檢查 nginx 、 php 的日誌,檢查 mysql 的日誌。如果以上目錄沒有問題,則需一個一個的檢查其他目錄(優先檢查 /usr 目錄),刪除過大的檔案。
Nginx 502 Bad Gateway 的含義是請求的 PHP-CGI 已經執行,但是由於某種原因(一般是讀取資源的問題)沒有執行完畢而導致 PHP-CGI 程序終止。
Nginx 504 Gateway Time-out 的含義是所請求的閘道器沒有請求到,簡單來説就是沒有請求到可以執行的 PHP-CGI 。
解決這兩個問題其實是需要綜合思考的,一般來説 Nginx 502 Bad Gateway 和 php-fpm.conf 的設定有關,而 Nginx 504 Gateway Time-out 則是與 nginx.conf 的設定有關。
而正確的設定需要考慮站羣服務器自身的效能和訪客的數量等多重因素。
以我目前的站羣服務器為例子 CPU 是奔四 1.5G 的,內存 1GB,CENTOS 的系統,訪客大概是 50 人左右同時線上。
但是線上的人大都需要請求 PHP-CGI 進行大量的資訊處理,因此我將 nginx.conf 設定為:
fastcgi_connect_timeout 300s;
fastcgi_send_timeout 300s;
fastcgi_read_timeout 300s;
fastcgi_buffer_size 128k;
fastcgi_buffers 8 128k;#8 128
fastcgi_busy_buffers_size 256k;
fastcgi_temp_file_write_size 256k;
fastcgi_intercept_errors on;
這裏最主要的設定是前三條,即
fastcgi_connect_timeout 300s;
fastcgi_send_timeout 300s;
fastcgi_read_timeout 300s;
這裏規定了 PHP-CGI 的連線、傳送和讀取的時間,300 秒足夠用了,因此我的站羣服務器很少出現 504 Gateway Time-out 這個錯誤。最關鍵的是 php-fpm.conf 的設定,這個會直接導致 502 Bad Gateway 和 504 Gateway Time-out 。
下面我們來仔細分析一下 php-fpm.conf 幾個重要的引數:
php-fpm.conf 有兩個至關重要的引數,一個是”max_children”, 另一個是”request_terminate_timeout”
我的兩個設定的值一個是”40″,一個是”900″,但是這個值不是通用的,而是需要自己計算的。
計算的方式如下:
如果你的站羣服務器效能足夠好,且寬頻資源足夠充足,PHP 指令碼沒有系迴圈或 BUG 的話你可以直接將”request_terminate_timeout” 設定成 0s 。 0s 的含義是讓 PHP-CGI 一直執行下去而沒有時間限制。而如果你做不到這一點,也就是説你的 PHP-CGI 可能出現某個 BUG,或者你的寬頻不夠充足或者其他的原因導致你的 PHP-CGI 能夠假死那麼就建議你給”request_terminate_timeout” 賦一個值,這個值可以根據你站羣服務器的效能進行設定。一般來説效能越好你可以設定越高,20 分鐘-30 分鐘都可以。由於我的站羣服務器 PHP 指令碼需要長時間執行,有的可能會超過 10 分鐘因此我設定了 900 秒,這樣不會導致 PHP-CGI 死掉而出現 502 Bad gateway 這個錯誤。
而”max_children” 這個值又是怎麼計算出來的呢?這個值原則上是越大越好,php-cgi 的程序多了就會處理的很快,排隊的請求就會很少。設定”max_children” 也需要根據站羣服務器的效能進行設定,一般來説一台站羣服務器正常情況下每一個 php-cgi 所耗費的內存在 20M 左右,因此我的”max_children” 我設定成 40 個,20M*40=800M 也就是説在峯值的時候所有 PHP-CGI 所耗內存在 800M 以內,低於我的有效內存 1Gb 。而如果我的”max_children” 設定的較小,比如 5-10 個,那麼 php-cgi 就會 “很累”,處理速度也很慢,等待的時間也較長。如果長時間沒有得到處理的請求就會出現 504 Gateway Time-out 這個錯誤,而正在處理的很累的那幾個 php-cgi 如果遇到了問題就會出現 502 Bad gateway 這個錯誤。
一些執行在 Nginx 上的網站有時候會出現 “502 Bad Gateway” 錯誤,有些時候甚至頻繁的出現。以下是從 Google 蒐集整理的一些 Nginx 502 錯誤的排查方法,供參考:
Nginx 502 錯誤的原因比較多,是因為在代理模式下後端站羣服務器出現問題引起的。這些錯誤一般都不是 nginx 本身的問題,一定要從後端找原因!但 nginx 把這些出錯都攬在自己身上了,著實讓 nginx 的推廣者備受置疑,畢竟從字眼上理解,bad gateway?不就是 bad nginx 嗎?讓不瞭解的人看到,會直接把責任推在 nginx 身上,希望 nginx 下一個版本會把出錯提示寫稍微友好一些,至少不會是現在簡單的一句 502 Bad Gateway,另外還不忘附上自己的大名。
Nginx 502 的觸發條件
502 錯誤最通常的出現情況就是後端 WordPress 主機當機。在 upstream 配置裏有這麼一項配置:proxy_next_upstream,這個配置指定了 nginx 在從一個後端 WordPress 主機取資料遇到何種錯誤時會轉到下一個後端 WordPress 主機,裏頭寫上的就是會出現 502 的所有情況拉,預設是 error timeout 。 error 就是當機、斷線之類的,timeout 就是讀取堵塞超時,比較容易理解。我一般是全寫上的:
proxy_next_upstream error timeout invalid_header http_500 http_503;
不過現在可能我要去掉 http_500 這一項了,http_500 指定後端返回 500 錯誤時會轉一個 WordPress 主機,後端的 jsp 出錯的話,本來會列印一堆 stacktrace 的錯誤資訊,現在被 502 取代了。但公司的程式設計師可不這麼認為,他們認定是 nginx 出現了錯誤,我實在沒空跟他們解釋 502 的原理 了……
503 錯誤就可以保留,因為後端通常是 apache resin,如果 apache 宕機就是 error,但 resin 宕機,僅僅是 503,所以還是有必要保留的。
解決辦法
遇到 502 問題,可以優先考慮按照以下兩個步驟去解決。
1 、檢視當前的 PHP FastCGI 程序數是否夠用:
netstat -anpo | grep “php-cgi” | wc -l
如果實際使用的 “FastCGI 程序數” 接近預設的 “FastCGI 程序數”,那麼,説明 “FastCGI 程序數” 不夠用,需要增大。
2 、部分 PHP 程式的執行時間超過了 Nginx 的等待時間,可以適當增加 nginx.conf 配置檔案中 FastCGI 的 timeout 時間,例如:
……http{……fastcgi_connect_timeout 300;fastcgi_send_timeout 300;fastcgi_read_timeout 300;……}……
php.ini 中 memory_limit 設低了會出錯,修改了 php.ini 的 memory_limit 為 64M,重啓 nginx,發現好了,原來是 PHP 的內存不足了。
如果這樣修改了還解決不了問題,可以參考下面這些方案:
一、 max-children 和 max-requests
一台站羣服務器上執行著 nginx php(fpm) xcache,訪問量日均 300W pv 左右
最近經常會出現這樣的情況: php 頁面開啓很慢,cpu 使用率突然降至很低,系統負載突然升至很高,檢視網絡卡的流量,也會發現突然降到了很低。這種情況只持續數秒鐘就恢復了
檢查 php-fpm 的日誌檔案發現了一些線索
Sep 30 08:32:23.289973 [NOTICE] fpm_unix_init_main(), line 271: getrlimit(nofile): max:51200, cur:51200Sep 30 08:32:23.290212 [NOTICE] fpm_sockets_init_main(), line 371: using inherited socket fd=10, “127.0.0.1:9000″Sep 30 08:32:23.290342 [NOTICE] fpm_event_init_main(), line 109: libevent: using epollSep 30 08:32:23.296426 [NOTICE] fpm_init(), line 47: fpm is running, pid 30587
在這幾句的前面,是 1000 多行的關閉 children 和開啓 children 的日誌
原來,php-fpm 有一個引數 max_requests,該引數指明瞭,每個 children 最多處理多少個請求後便會被關閉,預設的設定是 500 。因為 php 是把請求輪詢給每個 children,在大流量下,每個 childre 到達 max_requests 所用的時間都差不多,這樣就造成所有的 children 基本上在同一時間 被關閉。
在這期間,nginx 無法將 php 檔案轉交給 php-fpm 處理,所以 cpu 會降至很低 (不用處理 php,更不用執行 sql),而負載會升至很高 (關閉和開啓 children 、 nginx 等待 php-fpm),網絡卡流量也降至很低 (nginx 無法生成資料傳輸給客户端)
解決問題很簡單,增加 children 的數量,並且將 max_requests 設定未 0 或者一個比較大的值:
開啓 /usr/local/php/etc/php-fpm.conf
調大以下兩個引數 (根據站羣服務器實際情況,過大也不行)
然後重啓 php-fpm 。
二、增加緩衝區容量大小
將 nginx 的 error log 開啓,發現 “pstream sent too big header while reading response header from upstream” 這樣的錯誤提示。查閲了一下資料,大意是 nginx 緩衝區有一個 bug 造成的, 我們網站的頁面消耗佔用緩衝區可能過大。參考老外寫的修 改辦法增加了緩衝區容量大小設定,502 問題徹底解決。後來系統管理員又對引數做了調整隻保留了 2 個設定引數:client head buffer,fastcgi buffer size 。
三、 request_terminate_timeout
如果主要是在一些 post 或者資料庫操作的時候出現 502 這種情況,而不是在靜態頁面操作中常見,那麼可以檢視一下 php-fpm.conf 設定中的一項:
request_terminate_timeout
這個值是 max_execution_time,就是 fast-cgi 的執行指令碼時間。
0s
0s 為關閉,就是無限執行下去。(當時裝的時候沒仔細看就改了一個數字)
發現,問題解決了,執行很長時間也不會出錯了。
優化 fastcgi 中,還可以改改這個值 5s 看看效果。
php-cgi 程序數不夠用、 php 執行時間長、或者是 php-cgi 程序死掉,都會出現 502 錯誤。
原文連結:http://www.centoscn.com/CentosBug/softbug/2017/0228/8555.html