08.17 php-fpm負載飆升解決實戰

還記得那年拉手網wap服務器(m.lashou.com)發生過一次莫名其妙的服務器負載飆升事件(那時的業務量也比較大),以前大體記錄瞭解決過程,現在再整理下為遇到此種問題的人提供下思路,同時也是對相關知識的鞏固。

從10.10下午五點半多wap相關服務器(m.lashou.com)的負載開始飆升,load average甚至超過200,服務器撐一兩個小時就宕機。從session數據庫服務器來看,連接到其上的最多的就是我(朱)這邊業務的服務器,登錄相關服務器free -m查看內存很快被吃盡進而導致服務器宕機(現在已將session數據存入redis)。由於以前也出現過類似情況,加之10號下午連接session數據庫的配置文件更改(ip被換,涉及機房遷移,懷疑兩個節點間的網絡通道有點問題,進而引起了一系列問題),所以運維人員(運維工程師劉橋)第一反應是由此引起的並通知到我(朱)這邊。但是我的判斷是以前也更改過這種數據庫配置文件,並沒有引起這種情況,並且如果2個節點之間網絡通道有問題的話,從服務器上來看對應該session數據庫應該會有很多的timewait,但是根據相關命令查看並不多,截圖如下:

php-fpm負載飆升解決實戰

因此基本排除這種情況。13年也曾經出現過這樣一次情況,會不會跟上次一樣是因為服務器的tcp參數配置不夠優化引起的呢。Linux系統下,TCP連接斷開後會以TIME_WAIT狀態保留一定的時間,然後才會釋放端口。當併發請求過多的時候,就會產生大量的TIME_WAIT狀態的連接,無法及時斷開的話會佔用大量的端口資源和服務器資源.這個時候我們可以優化TCP的內核參數,來及時將TIME_WAIT狀態的端口清理掉。輸入下面的組合命令,查看當前TCP連接的狀態和對應的連接數量。

php-fpm負載飆升解決實戰

我們只關心timewait的連接個數即可,從上圖看到timewait個數也不是很多。查看相關配置文件$more /etc/sysctl.conf,確認了下

#表示開啟SYN Cookies。當出現SYN等待隊列溢出時,啟用cookies處理,可防範少量SYN攻擊,默認為0,表示關閉

net.ipv4.tcp_syncookies = 1

#表示開啟重用。允許將timewait sockets重新用於新的TCP連接,默認為0,表示關閉

net.ipv4.tcp_tw_reuse = 1

#表示開啟TCP連接中timewait sockets的快速回收,默認為0,表示關閉

net.ipv4.tcp_tw_recycle = 1

#修改系統默認的timeout時間

net.ipv4.tcp_fin_timeout = 30

配置沒有問題。綜上判斷並不是因為網絡通道/linux服務器配置參數不當引起。

由於是線上環境涉及線上業務因此建議運維工程師(劉)先寫個腳本對php-fpm進行監控,如果佔用內存到一定程度達到一定閾值用reload參數定時重啟nginx服務器以達到重載php-fpm將業務平穩過渡的目的。先儘可能的減少對用戶的傷害,然後再具體查找原因。

第二天通過查看php-fpm的狀態(查看配置文件在php-fpm配置文件中)如下:

php-fpm負載飆升解決實戰

訪問http://主機名/ls-status1.php即可查看。

#啟動日期,如果reload了php-fpm,時間會更新

start time: 16/Oct/2014:17:10:13 +0800

start since: 67275 #運行時長

可以看出大約2個小時重啟一次,也就是說約2個小時內存會耗盡。

那是什麼問題引起的呢?目前的現象是通過free -m檢測會發現可用內存慢慢變少,直至耗盡。可用內存曲線是向下的,而不是到某個點之後再慢慢的上升。如果是java程序的話,第一反應應該是程序處理不當而引起內存洩露,但是php程序是解釋型語言,運行時間會比較短,連接數據庫及curl函數都設定了超時時間。況且php版本為5.3.10這個版本沒有內存洩露的bug,服務器飆升之前的代碼與現在一致,並沒有變動,因此基本排除不是代碼層面的原因。那會不會是web server的原因呢,目前用的是LNMP架構。Nginx不支持對外部程序的直接調用或者解析,必須通過fastcgi進行調用。Nginx收到cgi請求之後,fastcgi接口在腳本解析服務器上,啟動一個或者多個守護進程對動態腳本進行解析,Php-fpm是一個fastcgi進程管理器/引擎(即對動態腳本進行實際解析的守護進程,由fastcgi啟動)。我理解php-fpm就是一個進程池,它的配置文件配置了fastcgi具體運行的方式。如果配置不當,fastcgi一直開啟進程而不釋放,就會造成進程堆積引起內存溢出,進而引起服務器宕機。

通過命令ps -ylC php-fpm --sort:rss 查看一個php-fpm進程佔用的實際內存空間平均為20多M(下面截圖只列出了一部分)

php-fpm負載飆升解決實戰

php-fpm負載飆升解決實戰

抓緊檢查下php-fpm配置文件,咦?發現pm.max_requests(發送多少個請求後會重啟該線程,從而使其釋放佔用的內存,默認0即決不重啟一直接受請求)的值為0。

通過cat /proc/meminfo 查看m.lashou.com服務器的內存為8G,從上圖sz項可以看出一個php-fpm進程能夠正常運轉起來佔用的內存大部分為100M多,為保險起見這裡預留2G內存給系統及其他應用使用。根據設置進程數原則(在N+20%和M/m之間)。

N 是 CPU 內核數量。

M 是 PHP 能利用的內存數量。

m 是每個 PHP 進程平均使用的內存數量。

所以對php-fpm做如下配置:

pm.start_servers = 24 #動態方式下的起始php-fpm進程數量

pm.min_spare_servers = 16 #動態方式下的最小php-fpm進程數量

pm.max_spare_servers = 32#動態方式下的最大php-fpm進程數量

pm.max_requests = 1024 #靜態方式下開啟的php-fpm進程數量

重啟nginx繼續觀察,

php-fpm負載飆升解決實戰

發現沒有重啟現象,檢測了下內存使用情況基本平穩(在接下來的幾天觀察中也沒發現什麼異常)。

結論:算是告一段落了,通過這個事情我們可以看出配置文件也要隨服務器的負載情況進行適當調整,在負載不高、比較平穩時時pm.max_requests為0不會引起什麼問題,但是當負載高、併發大時問題就凸顯了,就需要調整相應的參數(當時當日pv突破了1000W)。配置文件中還有一個重要參數需要注意下request_terminate_timeout

(腳本最大執行時間)目前設置是30S,

php-fpm負載飆升解決實戰

其實最好設置10S或者更短。因為這麼長時間沒有響應,那應該是有程序問題,儘早斷開以釋放資源。


分享到:


相關文章: