Linux的php-fpm優化教程/php-fpm進程佔用內存大和不釋放內存問題

最近發現博客的內存老是隔三差五地被“喫掉”了,登錄到後臺後偶爾會出牛頓的情況,一開始懷疑是Swap不夠導致的,於是給VPS主機增加了幾個G的Swap,觀察了一段時間後發現再大的Swap也被慢慢地“喫掉”了!

很顯然是PHP某些服務一直在佔用着VPS的內存沒有釋放,導致物理內存耗盡後調用了Swap,顯然Swap沒有物理內存運行的效率高,於是就出現了進程卡死的情況了。考慮到挖站否現在用的Wordpress用的主題與插件過多,出現這樣的情況也是正常。

LNMP架構中PHP是運行在FastCGI模式下,按照官方的說法,php-cgi會在每個請求結束的時候會回收腳本使用的全部內存,但是並不會釋放給操作系統,而是繼續持有以應對下一次PHP請求。而php-fpm是FastCGI進程管理器,用於控制php的內存和進程等。

所以,解決的辦法就是通過php-fpm優化總的進程數和單個進程佔用的內存,從而解決php-fpm進程佔用內存大和不釋放內存的問題。

一、分析判斷php-fpm內存佔用情況

如果你發現VPS主機出現了卡頓的情況,首先查看一下內存的佔用情況,常用的命令就是Top、Glances、Free等

使用Glances命令,再按下m,就可以查看到當前VPS主機進程內存佔用情況了,按照佔用內存由多到少排序(或者使用Top命令,按下M,效果是一樣的)。

這是一張重啓後進程內存佔用情況圖,從前後對比中可以發現:隨着開機時間的增長,php-fpm佔用的內存越來越大,最終php-fpm耗盡了VPS所有物理內存。

查看當前php-fpm總進程數,命令:ps -ylC php-fpm --sort:rss。其中RSS就是佔用的內存情況。如下圖:

查看當前php-fpm進程的內存佔用情況及啓動時間,命令如下:

ps -e -o 'pid,comm,args,pcpu,rsz,vsz,stime,user,uid'|grep www|sort -nrk5

從下圖可以看出當前php-fpm所有進程平均每個進程佔用了60-70MB的內存,啓動時間,是當天的話就是3:12,否則會顯示是X月X日。

查看當前php-fpm進程平均佔用內存情況,一般來說一個php-fpm進程佔用的內存爲30-40MB,本次查詢的結果是60MB,顯然是多了。命令如下:

ps --no-headers -o "rss,cmd" -C php-fpm | awk '{ sum+=$1 } END { printf ("%d%s\n", sum/NR/1024,"M") }'
結果61M

二、熟悉php-fpm配置文件說明

php-fpm.conf就是php-fpm的配置文件,路徑一般在:/usr/local/php/etc,如下圖:

php-fpm.conf幾個重要的參數說明如下:

pm = dynamic #指定進程管理方式,有3種可供選擇:static、dynamic和ondemand。
pm.max_children = 16 #static模式下創建的子進程數或dynamic模式下同一時刻允許最大的php-fpm子進程數量。
pm.start_servers = 10 #動態方式下的起始php-fpm進程數量。
pm.min_spare_servers = 8 #動態方式下服務器空閒時最小php-fpm進程數量。
pm.max_spare_servers = 16 #動態方式下服務器空閒時最大php-fpm進程數量。
pm.max_requests = 2000 #php-fpm子進程能處理的最大請求數。
pm.process_idle_timeout = 10s
request_terminate_timeout = 120

pm三種進程管理模式說明如下:


pm = static,始終保持一個固定數量的子進程,這個數由pm.max_children定義,這種方式很不靈活,也通常不是默認的。 pm = dynamic,啓動時會產生固定數量的子進程(由pm.start_servers控制)可以理解成最小子進程數,而最大子進程數則由pm.max_children去控制,子進程數會在最大和最小數範圍中變化。閒置的子進程數還可以由另2個配置控制,分別是pm.min_spare_servers和pm.max_spare_servers。如果閒置的子進程超出了pm.max_spare_servers,則會被殺掉。小於pm.min_spare_servers則會啓動進程(注意,pm.max_spare_servers應小於pm.max_children)。 pm = ondemand,這種模式和pm = dynamic相反,把內存放在第一位,每個閒置進程在持續閒置了pm.process_idle_timeout秒後就會被殺掉,如果服務器長時間沒有請求,就只會有一個php-fpm主進程。弊端是遇到高峯期或者如果pm.process_idle_timeout的值太短的話,容易出現504 Gateway Time-out錯誤,因此pm = dynamic和pm = ondemand誰更適合視實際情況而定。

三、解決php-fpm進程佔用內存大問題

3.1? 調整管理模式

static管理模式適合比較大內存的服務器,而dynamic則適合小內存的服務器,你可以設置一個pm.min_spare_servers和pm.max_spare_servers合理範圍,這樣進程數會不斷變動。ondemand模式則更加適合微小內存,例如512MB或者256MB內存,以及對可用性要求不高的環境。

3.2? 減少php-fpm進程數

如果你的VPS主機的內存被佔用耗盡,可以檢查一下你的php-fpm進程數,按照php-fpm進程數=內存/2/30來計算,1GB內存適合的php-fpm進程數爲10-20之間,具體還得根據你的PHP加載的附加組件有關係。

3.3? php-fpm配置示例

這裏以1GB內存的VPS配置php-fpm爲演示,實際操作來看設置數值還得根據服務器本身的性能、PHP等綜合考慮。

pm = dynamic #dynamic和ondemand適合小內存。
pm.max_children = 15 #static模式下生效,dynamic不生效。
pm.start_servers = 8 #dynamic模式下開機的進程數量。
pm.min_spare_servers = 6 #dynamic模式下最小php-fpm進程數量。
pm.max_spare_servers = 15 #dynamic模式下最大php-fpm進程數量。

四、解決php-fpm進程不釋放內存問題

上面通過減少php-fpm進程總數來達到減少php-fpm內存佔用的問題,實際使用過程中發現php-fpm進程還存長期佔用內存而不釋放的問題。解決的方法就是減少pm.max_requests數。

最大請求數max_requests,即當一個 PHP-CGI 進程處理的請求數累積到 max_requests 個後,自動重啓該進程,這樣達到了釋放內存的目的了。以1GB內存的VPS主機設置爲例(如果你設置的數值沒有達到釋放內存可以繼續調低):

pm.max_requests = 500

php-fpm進程達到了pm.max_requests設定的數值後,就會重啓該進程,從而釋放內存。下圖是我測試後的效果,可以看出php-fpm進程被強制結束並釋放了內存。

五、總結

對於大內存以及對併發和可用性要求的話,建議使用static管理模式+最大的pm.max_children。如果是小內存的服務器,建議使用dynamic或者ondemand模式,同時降低pm.start_servers和pm.max_spare_servers進程數。

爲什麼我調整了參數沒有達到應有的效果?根據wzfou.com的經驗,php-fpm配置文件參數不能一概而論,必須要結合服務器自身的性能、WEB動態內容以及對可用性的要求來進行調整,內存長期佔用最好是再檢查一下是否有內存泄露。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章