linux 丢包排查思路简述(tcp+rdma)
linux 丟包排查思路簡(jiǎn)述
- 概述
- 網(wǎng)絡(luò)包接收流程
- 網(wǎng)絡(luò)包發(fā)送流程
- 丟包排查的思路
- tcp排查方法
- rdma排查方法
- 網(wǎng)絡(luò)工具匯總
- 參考鏈接
概述
我們首先以tcp網(wǎng)絡(luò)為例,談?wù)刲inux系統(tǒng)如何收發(fā)網(wǎng)絡(luò)包
在進(jìn)行網(wǎng)絡(luò)傳輸時(shí),數(shù)據(jù)包就會(huì)按照協(xié)議棧,對(duì)上一層發(fā)來(lái)的數(shù)據(jù)進(jìn)行逐層處理;然后封裝上該層的協(xié)議頭,再發(fā)送給下一層。
- 傳輸層在應(yīng)用程序數(shù)據(jù)前面增加了 TCP 頭;
- 網(wǎng)絡(luò)層在 TCP 數(shù)據(jù)包前增加了 IP 頭;
- 而網(wǎng)絡(luò)接口層,又在 IP 數(shù)據(jù)包前后分別增加了幀頭和幀尾。
這些新增的頭部和尾部,都按照特定的協(xié)議格式填充,想了解具體格式,你可以查看協(xié)議的文檔。
比如,你可以查看這里,了解 TCP 頭的格式。這些新增的頭部和尾部,增加了網(wǎng)絡(luò)包的大小,但我們都知道,物理鏈路中并不能傳輸任意大小的數(shù)據(jù)包。網(wǎng)絡(luò)接口配置的最大傳輸單元(MTU),就規(guī)定了最大的 IP 包大小。在我們最常用的以太網(wǎng)中,MTU 默認(rèn)值是 1500(這也是 Linux 的默認(rèn)值)。一旦網(wǎng)絡(luò)包超過(guò) MTU 的大小,就會(huì)在網(wǎng)絡(luò)層分片,以保證分片后的 IP 包不大于 MTU 值。顯然,MTU 越大,需要的分包也就越少,自然,網(wǎng)絡(luò)吞吐能力就越好。
如下圖所示,就是 Linux 通用 IP 網(wǎng)絡(luò)棧的示意圖:(圖片參考《性能之巔》圖 10.7 通用 IP 網(wǎng)絡(luò)棧繪制)
我們從上到下來(lái)看這個(gè)網(wǎng)絡(luò)棧,可以發(fā)現(xiàn),
- 最上層的應(yīng)用程序,需要通過(guò)系統(tǒng)調(diào)用,來(lái)跟套接字接口進(jìn)行交互;
- 套接字的下面,就是我們前面提到的傳輸層、網(wǎng)絡(luò)層和網(wǎng)絡(luò)接口層;
- 最底層,則是網(wǎng)卡驅(qū)動(dòng)程序以及物理網(wǎng)卡設(shè)備。
網(wǎng)卡,作為發(fā)送和接收網(wǎng)絡(luò)包的基本設(shè)備。在系統(tǒng)啟動(dòng)過(guò)程中,網(wǎng)卡通過(guò)內(nèi)核中的網(wǎng)卡驅(qū)動(dòng)程序注冊(cè)到系統(tǒng)中。而在網(wǎng)絡(luò)收發(fā)過(guò)程中,內(nèi)核通過(guò)中斷跟網(wǎng)卡進(jìn)行交互。再結(jié)合前面提到的 Linux 網(wǎng)絡(luò)棧,可以看出,網(wǎng)絡(luò)包的處理非常復(fù)雜。所以,網(wǎng)卡硬中斷只處理最核心的網(wǎng)卡數(shù)據(jù)讀取或發(fā)送,而協(xié)議棧中的大部分邏輯,都會(huì)放到軟中斷中處理。(如果top時(shí)發(fā)現(xiàn)系統(tǒng)的si比較高,可以通過(guò)定位/proc/softirqs中增長(zhǎng)較快的軟中斷從而定位問(wèn)題。)
理解了上述架構(gòu),我們就不難理解,為什么tcp的收發(fā)過(guò)程會(huì)牽涉到如下幾個(gè)緩沖區(qū):
- 網(wǎng)卡收發(fā)網(wǎng)絡(luò)包時(shí),通過(guò) DMA 方式交互的環(huán)形緩沖區(qū);
- 網(wǎng)卡中斷處理程序?yàn)榫W(wǎng)絡(luò)幀分配的,內(nèi)核數(shù)據(jù)結(jié)構(gòu) sk_buff 緩沖區(qū);
- 應(yīng)用程序通過(guò)套接字接口,與網(wǎng)絡(luò)協(xié)議棧交互時(shí)的套接字緩沖區(qū)。
網(wǎng)絡(luò)包接收流程
- 在鏈路層檢查報(bào)文的合法性,找出上層協(xié)議的類型(比如 IPv4 還是 IPv6),再去掉幀頭、幀尾,然后交給網(wǎng)絡(luò)層。
- 網(wǎng)絡(luò)層取出 IP 頭,判斷網(wǎng)絡(luò)包下一步的走向,比如是交給上層處理還是轉(zhuǎn)發(fā)。當(dāng)網(wǎng)絡(luò)層確認(rèn)這個(gè)包是要發(fā)送到本機(jī)后,就會(huì)取出上層協(xié)議的類型(比如 TCP 還是 UDP),去掉 IP 頭,再交給傳輸層處理。
- 傳輸層取出 TCP 頭或者 UDP 頭后,根據(jù) < 源 IP、源端口、目的 IP、目的端口 > 四元組作為標(biāo)識(shí),找出對(duì)應(yīng)的 Socket,并把數(shù)據(jù)拷貝到 Socket 的接收緩存中。
網(wǎng)絡(luò)包發(fā)送流程
了解網(wǎng)絡(luò)包的接收流程后,就很容易理解網(wǎng)絡(luò)包的發(fā)送流程。網(wǎng)絡(luò)包的發(fā)送流程就是上圖的右半部分,很容易發(fā)現(xiàn),網(wǎng)絡(luò)包的發(fā)送方向,正好跟接收方向相反。
丟包排查的思路
理解了linux網(wǎng)絡(luò)棧的原理,我們就不難去定位丟包問(wèn)題,
關(guān)于丟包及其分析設(shè)計(jì)網(wǎng)絡(luò)棧、內(nèi)核棧的各個(gè)層面,筆者在也僅僅稍懂皮毛,歡迎讀者踴躍補(bǔ)充。
我們可以使用ifconfig可以查看網(wǎng)絡(luò)丟包情況
$ ifconfig net0 net0: flags=6211<UP,BROADCAST,RUNNING,SLAVE,MULTICAST> mtu 1500ether 98:03:9b:8c:63:3a txqueuelen 1000 (Ethernet)RX packets 46725983 bytes 9200932091 (8.5 GiB)RX errors 0 dropped 48193 overruns 0 frame 0TX packets 127710842 bytes 127005910250 (118.2 GiB)TX errors 1 dropped 0 overruns 0 carrier 1 collisions 0- RX errors: 表示總的收包的錯(cuò)誤數(shù)量,這包括 too-long-frames 錯(cuò)誤,Ring Buffer 溢出錯(cuò)誤,crc 校驗(yàn)錯(cuò)誤,幀同步錯(cuò)誤,fifo overruns 以及 missed pkg 等等。
- RX dropped: 表示數(shù)據(jù)包已經(jīng)進(jìn)入了 Ring Buffer,但是由于內(nèi)存不夠等系統(tǒng)原因,導(dǎo)致在拷貝到內(nèi)存的過(guò)程中被丟棄。
- RX overruns: 表示了 fifo 的 overruns,這是由于 Ring Buffer(aka Driver Queue) 傳輸?shù)?IO 大于 kernel 能夠處理的 IO 導(dǎo)致的,而 Ring Buffer 則是指在發(fā)起 IRQ 請(qǐng)求之前的那塊 buffer。很明顯,overruns 的增大意味著數(shù)據(jù)包沒(méi)到 Ring Buffer 就被網(wǎng)卡物理層給丟棄了,而 CPU 無(wú)法即使的處理中斷是造成 Ring Buffer 滿的原因之一
- RX frame: 表示 misaligned 的 frames。
對(duì)于 TX 的來(lái)說(shuō),出現(xiàn)上述 counter 增大的原因主要包括 aborted transmission, errors due to carrirer, fifo error, heartbeat erros 以及 windown error,而 collisions 則表示由于 CSMA/CD 造成的傳輸中斷。
dropped與overruns的區(qū)別:
- dropped,表示這個(gè)數(shù)據(jù)包已經(jīng)進(jìn)入到網(wǎng)卡的接收緩存fifo隊(duì)列,并且開(kāi)始被系統(tǒng)中斷處理準(zhǔn)備進(jìn)行數(shù)據(jù)包拷貝(從網(wǎng)卡緩存fifo隊(duì)列拷貝到系統(tǒng)內(nèi)存),但由于此時(shí)的系統(tǒng)原因(比如內(nèi)存不夠等)導(dǎo)致這個(gè)數(shù)據(jù)包被丟掉,即這個(gè)數(shù)據(jù)包被Linux系統(tǒng)丟掉。
- overruns,表示這個(gè)數(shù)據(jù)包還沒(méi)有被進(jìn)入到網(wǎng)卡的接收緩存fifo隊(duì)列就被丟掉,因此此時(shí)網(wǎng)卡的fifo是滿的。為什么fifo會(huì)是滿的?因?yàn)橄到y(tǒng)繁忙,來(lái)不及響應(yīng)網(wǎng)卡中斷,導(dǎo)致網(wǎng)卡里的數(shù)據(jù)包沒(méi)有及時(shí)的拷貝到系統(tǒng)內(nèi)存,fifo是滿的就導(dǎo)致后面的數(shù)據(jù)包進(jìn)不來(lái),即這個(gè)數(shù)據(jù)包被網(wǎng)卡硬件丟掉。所以,個(gè)人覺(jué)得遇到overruns非0,需要檢測(cè)cpu負(fù)載與cpu中斷情
tcp排查方法
tcp丟包排查方法和工具集比較健全,手段也比較多,一般情況下,我們分析tcp丟包主要分析出向丟包重傳,通過(guò)在出向丟包的服務(wù)器上抓包,找到出問(wèn)題的網(wǎng)絡(luò)包和對(duì)端服務(wù)器。
這里僅舉幾個(gè)例子:
- wireshark抓重傳包的原理是:由于tcp字段中沒(méi)有重傳相關(guān)的資源,因此wireshark通過(guò)掃描網(wǎng)絡(luò)包中SEQ/ACK number, IP ID, source and destination IP address, TCP Port等字段,找到重復(fù)包,這些包就是丟包重傳的包。
rdma排查方法
目前我遇到的系統(tǒng)(mlx cx4/cx5/cx6),在rdma上主要的指標(biāo)是入向丟包(out_of_order),其根因有如下幾種情況:
- 打開(kāi)roce v2的tcpdump支持ethtool --set-priv-flags net0 sniffer on(注意,使用完成之后記得關(guān)閉ethtool --set-priv-flags net0 sniffer off)
- 使用tcpdump進(jìn)行抓包,在wireshark中使用過(guò)濾器ip.dsfield.dscp,過(guò)濾出dscp錯(cuò)誤的rdma包。如果存在,說(shuō)明有dscp入錯(cuò)隊(duì)列的rdma流量。
- 也可以在抓包的時(shí)候使用參數(shù)過(guò)濾,如:tcpdump -i net2 '(ip and (ip[1] & 0xfc) >> 2 != 46)' -w rdma_retrans.pcap,該語(yǔ)句過(guò)濾掉了dscp等于46的網(wǎng)絡(luò)包。
- 抓到包后我們就知道了問(wèn)題流量的src和dest在哪里,我們可以通過(guò)perftest(如ib_send_bw)工具打流確認(rèn)。
網(wǎng)絡(luò)工具匯總
tcp
rdma
RoCE/RDMA Tools
參考鏈接
總結(jié)
以上是生活随笔為你收集整理的linux 丢包排查思路简述(tcp+rdma)的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: 分布式事务简介
- 下一篇: linux网络编程--阻塞与非阻塞