前幾天有業務在新機器上線測試時,發現個問題:同樣的資源的虛機、同樣配置的ngxin+php-fpmweb後端的兩台機器,測試後發現:訪問.html檔案時qps相差不大,但是訪問php
頁面時其中一台的qps是另一台的數倍。通過分析,發現是php-fpm的backlog引數引起的,可以通過設定php-fpm.conf中的backlog引數來解決。下面是對問題的簡單分析。
一、問題分析
1、通過測試分析,的確存在所述的效能相差數倍的問題,因為訪問靜態檔案的效能相當,所以可以確定排除nginx錯誤的可能,猜想是不是有php執行過慢導致呢?
於是安裝了我們針對php5.2.5開發的slow log除錯模組後發現沒有執行慢的地方,然後把目光放到了nginx 與php建立連線的階段上,使用tcpdump在伺服器上抓包,
發現效能差的機器上存在大量的syn3秒超時,並且會伴有請求頭的超時重傳。如下圖:
看來**已經找到了:是syn 超時。一般syn 超時是由於服務端backlog引起的,在我們的應用中,nginx –> php-fpm,所以php-fpm相當於服務端,檢視php-fpm配置發現 backlog值是-1!!
asmlinkage long sys_listen(int fd, intbacklog)
return err; }
抱著試試看的心態,改變了fpm配置backlog的值,測試發現把php-fpm的backlog值設為:10 –262143 之間機器的效能恢復了(1-10因為太小,所以效能不太理想),cpu跑得很high,但是
只要大於262144,效能就又變差了。結合上面的問題,syn超時一般是伺服器端完成連線佇列滿導致的, 既然backlog值被設定成了somaxconn,那麼不應該出現核心中完成連線佇列滿的情況。
為了搞清楚backlog值對tcp監聽套接字的影響,編寫了乙個測試程式:服務端listen之後不accept,客戶端迴圈來連線(服務端非阻塞)。
(1)把backlog設定為-1 或 大於262144的乙個值時,客戶端連線很慢,抓包發現有syn 3、6秒超時,伺服器端established的連線也很少,如圖:
(2)把backlog設定為n(10 從上面的測試我們可以認為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分配空間時做了特殊的處理:
int reqsk_queue_alloc(struct request_sock_queue*queue,unsigned int nr_table_entries)
nr_table_entries 可以認為是使用者空間傳進來的值,min_t
保證了最大只取sysctl_max_syn_backlog的值,系統中是8196。
四、遺留問題
雖然問題解決了,但是還存在兩個疑問。
1、雖然通過測試可以確定backlog設定很大會出現syn超時,但是還不能從原理上解釋?
2、為什麼同樣設定的-1,有的機器效能很好,有的卻很差呢?
預設引數,命名引數,可變引數
def sayname name string pk unit sayname 其中預設引數為pk,所以此時輸出pk sayname dog 此時傳入引數dog,那麼就以你當前傳入的引數為準,輸出dogdef speed distance float time float float println...
C 方法引數 值引數,引用引數,輸出引數
使用值引數,通過複製實參的值到形參的方式,把資料傳遞到方法,方法被呼叫的時候,系統做如下操作 在棧中為形參分配空間 複製實參到形參。注意 乙個值引數的實參不一定是變數,它可以是任何能夠計算成相應資料型別的表示式。在把變數用作實參之前,變數必須被賦值 除非是輸出引數,這個稍後介紹 對於引用型別,變數可...
C C 引數 預設引數 佔位符引數
不多說了,直接看 在c c 中表示空的引數列表 void test void 在c中表示不確定的引數數目,c 中表示空的引數列表 void test1 在c中編譯失敗,必須至少有乙個顯示引數 在c 中表示可變的引數數目 void test2 c 預設引數,c不支援 預設引數同函式過載一樣,給程式設計...