Nginx + PHP-FPM 參數優化、性能監視和問題排查


Linux內存優化:

打開文件 /etc/sysctl.conf,增加以下設置

#該參數設置系統的TIME_WAIT的數量,如果超過默認值則會被立即清除
net.ipv4.tcp_max_tw_buckets = 20000
#定義了系統中每一個端口最大的監聽隊列的長度,這是個全局的參數
net.core.somaxconn = 65535
#對於還未獲得對方確認的連接請求,可保存在隊列中的最大數目
net.ipv4.tcp_max_syn_backlog = 262144
#在每個網絡接口接收數據包的速率比內核處理這些包的速率快時,允許送到隊列的數據包的最大數目
net.core.netdev_max_backlog = 30000
#能夠更快地回收TIME-WAIT套接字。此選項會導致處於NAT網絡的客戶端超時,建議為0
net.ipv4.tcp_tw_recycle = 0
#系統所有進程一共可以打開的文件數量
fs.file-max = 6815744
#防火牆跟蹤表的大小。注意:如果防火牆沒開則會提示error: "net.netfilter.nf_conntrack_max" is an unknown key,忽略即可
net.netfilter.nf_conntrack_max = 2621440

運行 sysctl -p 使配置生效

如果報錯:sysctl: cannot stat /proc/sys/net/netfilter/nf_conntrack_max: No such file or directory,能是 conntrack沒有加載,執行

lsmod | grep conntrack

如果 返回 為空,表示沒有加載,執行下面命令 重新加載

modprobe ip_conntrack

重新運行 sysctl -p

 

設置系統打開文件數設置

解決高並發下 too many open files 問題。此選項直接影響單個進程容納的客戶端連接數。

Soft open files 是Linux系統參數,影響系統單個進程能夠打開最大的文件句柄數量,這個值會影響到長連接應用如聊天中單個進程能夠維持的用戶連接數, 運行ulimit -n能看到這個參數值,如果是1024,就是代表單個進程只能同時最多只能維持1024甚至更少(因為有其它文件的句柄被打開)。如果開啟4個進程維持用戶連接,那么整個應用能夠同時維持的連接數不會超過4*1024個,也就是說最多只能支持4x1024個用戶在線可以增大這個設置以便服務能夠維持更多的TCP連接。

Soft open files 修改方法:

(1)ulimit -HSn 102400

這只是在當前終端有效,退出之后,open files 又變為默認值。

(2)在/etc/profile文件末尾添加一行 ulimit -HSn 102400,這樣每次登錄終端時,都會自動執行/etc/profile。

(3)令修改open files的數值永久生效,則必須修改配置文件:/etc/security/limits.conf. 在這個文件后加上:

* soft nofile 1024000
* hard nofile 1024000
root soft nofile 1024000
root hard nofile 1024000

這種方法需要重啟機器才能生效。

 

PHP參數優化

php-fpm.conf文件參數調整

pm = dynamic; 表示使用哪種進程數量管理方式

dynamic表示php-fpm進程數是動態的,最開始是pm.start_servers指定的數量,如果請求較多,則會自動增加,保證空閑的進程數不小於pm.min_spare_servers,如果進程數較多,也會進行相應清理,保證多余的進程數不多於pm.max_spare_servers。
static表示php-fpm進程數是靜態的, 進程數自始至終都是pm.max_children指定的數量,不再增加或減少。

pm.max_children = 300;  靜態方式下開啟的php-fpm進程數量
pm.start_servers = 20;  動態方式下的起始php-fpm進程數量
pm.min_spare_servers = 5;  動態方式下的最小php-fpm進程數量
pm.max_spare_servers = 35;  動態方式下的最大php-fpm進程數量

如果pm為static, 那么其實只有pm.max_children這個參數生效。php-fpm服務啟動后,系統會開啟設置數量的php-fpm進程

如果pm為dynamic, 那么pm.max_children參數失效,后面3個參數生效。系統會在php-fpm運行開始的時候啟動pm.start_servers個php-fpm進程,然后根據系統的需求動態在pm.min_spare_servers和pm.max_spare_servers之間調整php-fpm進程數

那么,對於我們的服務器,選擇哪種pm方式比較好呢?事實上,跟Apache一樣,運行的PHP程序在執行完成后,或多或少會有內存泄露的問題。這也是為什么開始的時候一個php-fpm進程只占用3M左右內存,運行一段時間后就會上升到20-30M的原因了。

對於內存大的服務器(比如8G以上)來說,指定靜態的max_children實際上更為妥當,因為這樣不需要進行額外的進程數目控制,會提高效率。因為頻繁開關php-fpm進程也會有時滯,所以內存夠大的情況下開靜態效果會更好。數量也可以根據 內存/30M 得到,比如8GB內存可以設置為100,那么php-fpm耗費的內存就能控制在 2G-3G的樣子。如果內存稍微小點,比如1G,那么指定靜態的進程數量更加有利於服務器的穩定。這樣可以保證php-fpm只獲取夠用的內存,將不多的內存分配給其他應用去使用,會使系統的運行更加暢通。

pm.max_requests = 10240;

nginx+php-fpm 組合中最大問題是內存泄漏出問題:服務器的負載不大,但是內存占用迅速增加,很快吃掉內存接着開始吃交換分區,系統很快掛掉!
其實根據官方的介紹,php-cgi不存在內存泄漏,每個請求完成后php-cgi會回收內存,但是不會釋放給操作系統,這樣就會導致大量內存被php-cgi占用。
    
官方的解決辦法是降低PHP_FCGI_MAX_REQUESTS的值,如果用的是php-fpm,對應的php-fpm.conf中的就是max_requests
該值的意思是發送多少個請求后會重啟該線程,我們需要適當降低這個值,用以讓php-fpm自動的釋放內存,不是大部分網上說的51200等等,實際上還有另一個跟它有關聯的值max_children,這個是每次php-fpm會建立多少個進程,這樣實際上的內存消耗是 max_children*max_requests*每個請求使用內存,根據這個我們可以預估一下內存的使用情況,就不用再寫腳本去kill了。

request_terminate_timeout = 30;
最大執行時間, 在php.ini中也可以進行配置(max_execution_time)

rlimit_files = 1024;  增加php-fpm打開文件描述符的限制

 

listen.backlog 參數設置為-1時,在2.6.18內核的機器上會有問題,參考 https://blog.csdn.net/haoluojie/article/details/76070191

 

php-fpm的高CPU使用率排查方法

 

資源占用查看

1、查看php-fpm的進程個數

ps -ef |grep "php-fpm"|grep "pool"|wc -l

2、查看每個php-fpm占用的內存大小

ps -ylC php-fpm --sort:rss

3.查看PHP-FPM在你的機器上的平均內存占用

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

4.查看每個php-fpm進程消耗內存的明細

pmap $(pgrep php-fpm) | less



1) 查詢php-fpm慢日志

request_slowlog_timeout = 2; 開啟慢日志
slowlog = log/$pool.slow.log; 慢日志路徑

grep -v "^$" www.slow.log | cut -d " " -f 3,2 | sort | uniq -c | sort -k1,1nr | head -n 10

參數解釋:
sort:  對日志文件每行日志按字母進行排序,以便傳遞給uniq -c進行行數(慢查詢出現次數)統計
uniq -c:  統計內容相同的行,合並顯示為一行,並在行首加上本行在文件中出現的次數
sort -k1,1nr:  按照第一個字段(出現次數),數值排序,且為逆序
head -n 10:  取前10行數據

結果類似:

出現次數    被調用的函數    文件和調用行號
5181        run()            /www/test.net/framework/web/filters/CFilter.php:41

5156        filter()        /www/test.net/framework/web/filters/CFilterChain.php:131

2636        run()            /www/test.net/application/controllers/survey/index.php:665

2630        action()        /www/test.net/application/controllers/survey/index.php:18

2625        run()           /www/test.net/framework/web/actions/CAction.php:75

2605        runWithParams()    /www/test.net/framework/web/CController.php:309

 

file_get_contents 請求url有個問題值得注意:http://zyan.cc/tags/request_terminate_timeout/1/

 

2) 監測php-fpm線程狀態

nginx 在站點中增加配置

location ~ ^/status$ {
    include fastcgi_params;
    fastcgi_pass 127.0.0.1:9000;
    fastcgi_param SCRIPT_FILENAME $fastcgi_script_name;
}

php-fpm 配置

pm.status_path = /status

 

然后就可以通過http://域名/status就可以看到當前的php情況,輸出參數說明:
pool:php-fpm池的名稱,一般都是應該是www
process manage:進程的管理方法,php-fpm支持三種管理方法,分別是static,dynamic和ondemand,一般情況下都是dynamic
start time:php-fpm啟動時候的時間,不管是restart或者reload都會更新這里的時間
start since:php-fpm自啟動起來經過的時間,默認為秒
accepted conn:當前接收的連接數
listen queue:在隊列中等待連接的請求個數,如果這個數字為非0,那么最好增加進程的fpm個數
max listen queue:從fpm啟動以來,在隊列中等待連接請求的最大值
listen queue len:等待連接的套接字隊列大小
idle processes:空閑的進程個數
active processes:活動的進程個數
total processes:總共的進程個數
max active processes:從fpm啟動以來,活動進程的最大個數,如果這個值小於當前的max_children,可以調小此值
max children reached:當pm嘗試啟動更多的進程,卻因為max_children的限制,沒有啟動更多進程的次數。如果這個值非0,那么可以適當增加fpm的進程數
slow requests:慢請求的次數,一般如果這個值未非0,那么可能會有慢的php進程,一般一個不好的mysql查詢是最大的禍首。

3) strace分析跟蹤進程


方法一:利用nohup將strace轉為后台執行,直到attach上的php-fpm進程死掉為止

nohup strace -T -p 13167 > 13167-strace.log &

參數說明:

-c 統計每一系統調用的所執行的時間,次數和出錯的次數等.
-d 輸出strace關於標准錯誤的調試信息.
-f 跟蹤由fork調用所產生的子進程.
-o filename,則所有進程的跟蹤結果輸出到相應的filename
-F 嘗試跟蹤vfork調用.在-f時,vfork不被跟蹤.
-h 輸出簡要的幫助信息.
-i 輸出系統調用的入口指針.
-q 禁止輸出關於脫離的消息.
-r 打印出相對時間關於,,每一個系統調用.
-t 在輸出中的每一行前加上時間信息.
-tt 在輸出中的每一行前加上時間信息,微秒級.
-ttt 微秒級輸出,以秒了表示時間.
-T 顯示每一調用所耗的時間.
-v 輸出所有的系統調用.一些調用關於環境變量,狀態,輸入輸出等調用由於使用頻繁,默認不輸出.
-V 輸出strace的版本信息.
-x 以十六進制形式輸出非標准字符串
-xx 所有字符串以十六進制形式輸出.
-a column
設置返回值的輸出位置.默認為40.
-e execve 只記錄 execve 這類系統調用
-p 主進程號

結果類似:

select(7, [6], [6], [], {15, 0})               = 1 (out [6], left {15, 0})
poll([{fd=6, events=POLLIN}], 1, 0)     = 0 (Timeout)
select(7, [6], [6], [], {15, 0})               = 1 (out [6], left {15, 0})
...

 

方法二:用利用-c參數讓strace幫助匯總

strace -cp 9907

輸出類似

Process 9907 attached - interrupt to quit

Process 9907 detached

% time     seconds  usecs/call     calls    errors syscall

------ ----------- ----------- --------- --------- ----------------

56.61    0.016612           5      3121           read

11.11    0.003259           1      2517          715 stat

0.00    0.000000           0        26           chdir

0.00    0.000000           0         1           futex

...
------ ----------- ----------- --------- --------- ----------------

100.00    0.029344                 18000       986 total

 

4) 使用xdebug性能監控(xdebug對php運行有性能影響,線上服務器慎用)

常用的方法就是開啟xdebug的性能監控功能,將xdebug輸出結果通過WinCacheGrind軟件分析。

xdebug的安裝和配合IDE調試的方法參見:Vim+XDebug調試PHPWinCacheGrind分析腳本執行時間

php.ini中配置的這幾項是輸出性能信息的:

xdebug.auto_trace = on

xdebug.auto_profile = on
xdebug.collect_params = on
xdebug.collect_return = on
xdebug.profiler_enable = on
xdebug.trace_output_dir = "/tmp"
xdebug.profiler_output_dir ="/tmp"


這樣XDebug會輸出所有執行php函數的性能數據,但產生的文件也會比較大。可以關閉一些選項如collect_params、collect_return,
來減少輸出的數據量。或者關閉自動輸出,通過在想要監控的函數首尾調用xdebug函數來監控指定的函數。

輸出的文件名類似cachegrind.out.1277560600 和 trace.3495983249.txt,可以拿到Windows平台下用WinCacheGrind進行圖形化分析。

 

4) 使用 xhprof 做被動分析

https://blog.csdn.net/maquealone/article/details/80434699


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM