參考:http://phpmianshi.com/?id=92
一、問題分析
1、分析php-fpm.slow.log發現沒有執行慢的地方,然後把目光放到了nginx 與php建立連接的階段上,使用tcpdump在服務器上抓包,
發現性能差的機器上存在大量的SYN3秒超時,並且會伴有請求頭的超時重傳。如下圖:
看來兇手已經找到了:是SYN 超時。一般SYN 超時是由於服務端backlog引起的,在我們的應用中,nginx –> php-fpm,所以php-fpm相當於服務端,查看php-fpm配置發現 backlog值是 -1
抱着試試看的心態,改變了fpm配置backlog的值,測試發現把php-fpm的backlog值設爲:10 –262143 之間機器的性能恢復了(1-10因爲太小,所以性能不太理想),但是隻要大於262144,性能就又變差了。結合上面的問題,SYN超時一般是服務器端完成連接隊列滿導致的, 既然backlog值被設置成了somaxconn,那麼不應該出現內核中完成連接隊列滿的情況。
從上面的測試我們可以認爲php-fpm是因爲沒有及時accept連接導致服務器不再接收TCP連接導致的,那麼fpm爲什麼會不及時accept呢?
原來fpm 多個進程是監聽同一個套接字的,通過一個套接字鎖來保證同一時刻只有一個進程可以accept,多進程間搶鎖是需要消耗時間的,
在backlog被設置成-1的情況下,如果fpm沒有及時accept,那麼在併發量很大的情況下勢必會出現SYN 超時重連了。
二、結論
綜上:性能差是由於php-fpm backlog參數設置爲-1,導致fpm沒能及時取出完成連接隊列的socket,出現SYN 超時,最終導致壓不上去,表現出性能差。
所以安裝php-fpm時backlog一定要重新設置,不能用fpm默認配置的-1 ,可以根據機器的併發量來設置,建議設置在1024以上,最好是2的冪值(因爲內核會調整成2的n次冪)。
如果您的業務機是2.6.18內核,同時發現php 機器性能特不合理,那麼就試試改一下fpm的backlog參數吧,您肯定會震驚的。。。。
三、備註
在2.6.32內核上測試就不會出現這個問題,因爲2.6.32內核給listen socket分配空間時做了特殊的處理:
四、遺留問題
雖然問題解決了,但是還存在兩個疑問。
1、雖然通過測試可以確定backlog設置很大會出現SYN超時,但是還不能從原理上解釋?
2、爲什麼同樣設置的-1,有的機器性能很好,有的卻很差呢?