1. 程式人生 > >linux下建立tcp連線(connect)非常慢的問題的排查

linux下建立tcp連線(connect)非常慢的問題的排查

先說結論:
執行了如下的命令後,問題解決。 之前nf_conntrack_max的值是65536
sysctl -w net.netfilter.nf_conntrack_max=358576

參考:

Linux伺服器丟包故障的解決思路及引申的TCP/IP協議棧理論

http://www.sdnlab.com/17530.html

===================================

問題描述:

 當php的請求量稍微變大的時候(nginx+php-fpm的架構),php對外建立連線的時間 connnect 的時間會變長(無論連線mysql,還是redis都很慢),持續幾秒鐘才建立了解成功,有的時候甚至卡10幾秒,30秒,但是本身請求量不是非常大,也就幾百次/秒,同時cpu佔用非常低(10%不到), time_wait連線數也很少(開啟了快速回收),程序能開啟的控制代碼數8192(和開啟的fd數量沒關係),機器的網路流量也遠沒有達到瓶頸(實際上這個機器時不限制流量上限的),那麼問題出在哪裡了?

機器: 12核12G,php-frm 400個程序。 strace php程序看到的一些現象:

//  這個是異常的情況 
 1476414907.830951 connect(5, {sa_family=AF_INET, sin_port=htons(6379), sin_addr=inet_addr("10.66.112.169")}, 16) = -1 EINPROGRESS (Operation now in progress)
1476414907.830985 poll([{fd=5, events=POLLIN|POLLOUT|POLLERR|POLLHUP}], 1, -1000) = 1 ([{fd=5, revents=POLLOUT}])
1476414910.831337 getsockopt(5, SOL_SOCKET, SO_ERROR, [0], [4]) = 0  // 這裡poll了3秒才返回 

// 這個是正常的情況 

 1476415329.443653 connect(5, {sa_family=AF_INET, sin_port=htons(6379), sin_addr=inet_addr("10.66.112.169")}, 16) = -1 EINPROGRESS (Operation now in progress)
1476415329.443697 poll([{fd=5, events=POLLIN|POLLOUT|POLLERR|POLLHUP}], 1, -1000) = 1 ([{fd=5, revents=POLLOUT}])
1476415329.443953 getsockopt(5, SOL_SOCKET, SO_ERROR, [0], [4]) = 0  // 壓力小點的時候,很快就返回了。 

===================================

排查過程:

起初懷疑是機器問題,但是試了很多臺機器,都有一樣的現象。

再次懷疑是redis或者mysql伺服器的問題,但是當把請求分擔到很多個機器上,即使總的請求量很大的時候,redis和mysql也正常服務

其次懷疑程式碼問題
       1 懷疑thinkphp框架有什麼問題,至少發現 /var/lib/php/session/目錄下回頻繁的建立sess檔案,幾十萬個,都是我們沒用的東西,正好本身覺得用框架效率也低(框架裡面的功能都是我們用不著的),就把程式碼重構去掉了框架。 沒有了sess檔案之後,問題依舊。

       2 既然connect頻繁了會有問題,那我不用短連線總可以了吧,把redis和mysqli都是用長連線後,症狀輕了點,支援的請求數翻了2倍,也不過400左右,更高的時候問題又出現了

      3 當redis和mysql都是長連線後,php訪問騰訊的openapi依然還是短連線,這個依然會connect會卡!但是騰訊的openapi是之前在騰訊的時候自己做的,很多開發商在用,很明確的是沒有問題的,一定是問題出在我們身上。 當connect卡的時候, telnet openapi.tencentyun.com 80 也是不定時的telnet不通,或卡一段時間。 既然telnet都卡了,應該和程式碼沒關係了吧。

最後懷疑是機器的某些tcp相關核心引數配置的問題

網上搜索了下 tcp 丟包,發現了答案

       http://www.sdnlab.com/17530.html

       Linux伺服器丟包故障的解決思路及引申的TCP/IP協議棧理論


我的機器上執行 dmesg 結果如下;

[4331898.853374] __ratelimit: 5 callbacks suppressed

[4331898.853378] nf_conntrack: table full, dropping packet.
[4331898.914146] nf_conntrack: table full, dropping packet.
[4331898.914380] nf_conntrack: table full, dropping packet.
[4331899.047487] nf_conntrack: table full, dropping packet.
[4331899.047501] nf_conntrack: table full, dropping packet.
[4331899.047508] nf_conntrack: table full, dropping packet.
[4331899.047515] nf_conntrack: table full, dropping packet.
[4331899.047525] nf_conntrack: table full, dropping packet.
[4331899.047532] nf_conntrack: table full, dropping packet.
[4331899.047539] nf_conntrack: table full, dropping packet.

。。。。。

# 檢視nf_conntrack表最大連線數 $ cat /proc/sys/net/netfilter/nf_conntrack_max 65536 # 檢視nf_conntrack表當前連線數 已經滿了,或者接近滿了(是個動態變化的值) $ cat /proc/sys/net/netfilter/nf_conntrack_count 65535

根據文中的指引調大 /proc/sys/net/netfilter/nf_conntrack_max 之後,問題解決。 cpu的壓力上來了,php程序不再阻塞。