TCP的socket資源被耗盡的問題


一、 故障現象

部分機頂盒用戶出現大面積登錄APP時,界面停留在登陸頁面,無反應。

 

二、 現象初步分析

本次問題出現時,所有AAA出現了異常流量波動,在AAA異常流量段期間接到用戶故障報障。此時主要表現在LVS集群顯示真實的EPG 服務器不停的被踢出集群和加入(UP/DOWN),導致了用戶調度到EPG后出現了異常顯示。

AAA異常流量圖

 

三、 問題排查過程

接到故障后第一時間對AAA/EPG后台日志進行了查看,發現用戶接入認證和響應都正常,觀察到EPG 的LVS集群中有服務器的inactive連接數異常並且隨機出現不同EPG服務器被踢出和加入集群,隨后對EPG 的LVS集群的狀態進行了跟蹤和抓包分析,為了快速恢復業務隨后重啟了EPG tomcat並進行了LVS的主備切換,業務故障恢復。

 

四、 診斷分析結果

   出現故障時通過LVS的日志可以看到5台EPG服務器在輪詢的出現連接失敗和連接成功的情況,也就是一台OK后,另一台出現連接失敗,如此反復的表現在5台EPG服務器上

此時被UP/DOWN的EPG會出現大量的inactive

 

此時對集群出現UP/DOWM的服務器進行抓包,發現客戶端發出了SYN報

文,但是EPG服務器沒有響應,並且響應報文發不出去不停的retransmission。

進一步查看該EPG的資源消耗情況netstat發現大量的SYN-RECV

 

通過上面的現象判斷是EPG的socket資源被耗盡進而出現了響應客戶端異常,導致了LVS檢測EPG服務器異常,因集群是5台EPG服務器,一台異常后LVS集群把用戶調度到其它EPG服務器,此時異常用戶也對該服務器產生了影響出現了該服務器也被資源耗盡,依次循環。根據當前的用戶量程度來看一般EPG的資源應該是可以滿足,進一步查看資源情況發現是EPG的句柄數被耗盡導致的,當重啟EPG后,資源被釋放句柄數被釋放問題故障就恢復了。查看EPG服務器發現系統的默認句柄數為1024。

LVS原理分析:

當有異常用戶訪問EPG時,SYN消息先發送到LVS,LVS會建立一個調度表,顯示用戶與EPG的TCP對應關系,EPG會直接返回ACK給用戶端不經過LVS,只有LVS收到用戶端發送的FIN時,表項的對應關系才會刪除該用戶客戶端的EPG對應關系。

當用戶訪問突然異常且量大的時候EPG默認的句柄數只有1024,這樣會導致LVS踢出該EPG,但是此時LVS建立的表里面的TCP關系還在所以inactive數會變的特別大,根據LVS調度策略用戶會被調度到其它EPG真實服務器,這樣就會形成惡性循環,所有集群的EPG真實服務器會被資源耗盡。

 

五、處理優化措施

從上述分析來看本次故障根本原因是EPG真實服務器的句柄數采用默認的1024,一旦出現異常用戶訪問的時候就會變的脆弱,目前修改為了204800。經過本次故障,對系統的參數做了確認和文檔化

 

六、參數修改記錄

修改記錄一:net.ipv4.tcp_timestamps = 0

原因如下

1、slb服務器為了優化性能,調整以下內核參數:

net.ipv4.tcp_timestamps = 1

net.ipv4.tcp_tw_recycle = 1

當這兩個參數都打開時,tcp需要校驗syn包的時間戳(timestamp)對集團用戶有影響使其接入失敗。

 

2、當滿足以下條件,syn包將會被忽略,不會回復ack包:

        a、該源ip的上次tcp通訊發生在60s內。

        b、該源ip的上次tcp通訊的timestamp 大於本次tcp。

        注:tcp通訊的timestamp 為系統啟動到當前的時間。

 

3、解釋現象:

        a、為什么普通的用戶播放正常,集團用戶不行?

            一個ip對應一個普通用戶,那么普通用戶的tcp通訊的timestamp是一直增大的,即不會滿足2中的b條件。

            集團用戶是做了NAT的,一個ip對應多個客戶端,只有tcp通訊的timestamp比較大的客戶端(大堂)才能請求成功,timestamp比較小的(房間)請求就失敗。

 

        b、房間偶爾又能播放?

             該源ip的上次tcp通訊發生在60s之外了。

 

修改記錄二:net.ipv4.tcp_max_tw_buckets = 5000

TIME_WAIT狀態的連接過多,會影響到大並發。

 

修改記錄三:net.ipv4.tcp_synack_retries = 0

net.core.somaxconn = 65535

原因如下:

SYN Flood(TCP洪水攻擊優化)

tcp_synack_retries:表示回應第二個握手包(SYN+ACK包)給客戶端IP后,如果收不到第三次握手包(ACK包)后,不進行重試,加快回收“半連接”,不要耗光資源。可以把tcp_synack_retries改為0,因為客戶端還有tcp_syn_retries參數,默認是5,即使服務器端沒有重發SYN+ACK包,客戶端也會重發SYN握手包。

net.core.somaxconn:最大的監聽隊列的長度,默認限制為128,在高突發的請求中可能會導致鏈接超時或觸發重傳。

 

修改記錄四:

括號值為修改后的值,(X)代表刪除。

net.ipv4.tcp_fin_timeout = 5 (1)

net.ipv4.tcp_max_syn_backlog = 10240(262144)

net.ipv4.tcp_max_tw_buckets = 5000(6000)

net.ipv4.tcp_mem = 24794688      33059584        49589376 (X)

net.ipv4.tcp_retries1 = 3 (2)

net.ipv4.tcp_retries2 = 15(2)

net.ipv4.tcp_keepalive_intvl = 75(2)

net.ipv4.tcp_keepalive_probes = 9(3)

net.ipv4.tcp_keepalive_time = 7200(2)

net.ipv4.tcp_rmem = 4096     87380      4194304(X)

net.ipv4.tcp_syn_retries = 2

net.ipv4.tcp_timestamps = 0(1)// timestamps可單獨起效

net.ipv4.tcp_tw_recycle = 1(0)// 需要timestamps起效,此項才奇效,單獨開啟無意義

net.ipv4.tcp_wmem = 4096    16384      4194304(X)

net.ipv4.udp_mem = 24794688     33059584        49589376(X)

net.ipv4.udp_rmem_min = 4096(X)

net.ipv4.udp_wmem_min = 4096(X)

net.core.rps_sock_flow_entries = 65535

// nf_conntrack 避免iptables的conntrack模塊故障

net.netfilter.nf_conntrack_acct = 0

net.netfilter.nf_conntrack_checksum = 1

net.netfilter.nf_conntrack_events = 1

net.netfilter.nf_conntrack_events_retry_timeout = 5

net.netfilter.nf_conntrack_expect_max = 256

net.netfilter.nf_conntrack_generic_timeout = 6

net.netfilter.nf_conntrack_helper = 1

net.netfilter.nf_conntrack_icmp_timeout = 3

net.netfilter.nf_conntrack_log_invalid = 0

net.netfilter.nf_conntrack_max = 524288

net.netfilter.nf_conntrack_tcp_be_liberal = 0

net.netfilter.nf_conntrack_tcp_loose = 1

net.netfilter.nf_conntrack_tcp_max_retrans = 2

net.netfilter.nf_conntrack_tcp_timeout_close = 5

net.netfilter.nf_conntrack_tcp_timeout_close_wait = 6

net.netfilter.nf_conntrack_tcp_timeout_established = 5

net.netfilter.nf_conntrack_tcp_timeout_fin_wait = 3

net.netfilter.nf_conntrack_tcp_timeout_last_ack = 3

net.netfilter.nf_conntrack_tcp_timeout_max_retrans = 3

net.netfilter.nf_conntrack_tcp_timeout_syn_recv = 3

net.netfilter.nf_conntrack_tcp_timeout_syn_sent = 3

net.netfilter.nf_conntrack_tcp_timeout_time_wait = 2

net.netfilter.nf_conntrack_tcp_timeout_unacknowledged = 3

net.netfilter.nf_conntrack_timestamp = 0

net.netfilter.nf_conntrack_udp_timeout = 3

net.netfilter.nf_conntrack_udp_timeout_stream = 3

net.nf_conntrack_max = 524288

 

修改記錄五:

net.ipv4.tcp_max_tw_buckets = 6000 (262144)

原因:tcp_max_tw_buckets的默認值為262144

 

修改記錄六:

增加修改文件句柄數:在/root/.bash_profile增加ulimit -n 204800

 


免責聲明!

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



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