自拍偷在线精品自拍偷,亚洲欧美中文日韩v在线观看不卡

Linux性能優(yōu)化實(shí)戰(zhàn),網(wǎng)絡(luò)丟包問題分析

系統(tǒng) Linux
對于 Linux 系統(tǒng)的使用者來說,網(wǎng)絡(luò)性能的優(yōu)劣直接關(guān)系到系統(tǒng)的整體表現(xiàn)。而在網(wǎng)絡(luò)性能問題中,網(wǎng)絡(luò)丟包堪稱最為棘手的難題之一,它就像隱藏在暗處的殺手,悄無聲息地侵蝕著系統(tǒng)的性能。

在當(dāng)今數(shù)字化時(shí)代,無論是搭建服務(wù)器、開發(fā)網(wǎng)絡(luò)應(yīng)用,還是進(jìn)行云計(jì)算部署,Linux 系統(tǒng)都扮演著舉足輕重的角色。作為一名運(yùn)維人員或開發(fā)者,你肯定希望自己的 Linux 系統(tǒng)能夠高效穩(wěn)定地運(yùn)行。但當(dāng)網(wǎng)絡(luò)丟包問題出現(xiàn)時(shí),一切都變得糟糕起來,服務(wù)器響應(yīng)遲緩,應(yīng)用程序頻繁報(bào)錯(cuò),用戶體驗(yàn)直線下降。

今天,我就帶大家深入 Linux 性能優(yōu)化的實(shí)戰(zhàn)領(lǐng)域,一起揪出網(wǎng)絡(luò)丟包這個(gè) “罪魁禍?zhǔn)住?,從原理分析到排查方法,再到解決方案,全方位為你答疑解惑 ,讓你的 Linux 系統(tǒng)重回高性能狀態(tài)。

一、網(wǎng)絡(luò)丟包概述

對于 Linux 系統(tǒng)的使用者來說,網(wǎng)絡(luò)性能的優(yōu)劣直接關(guān)系到系統(tǒng)的整體表現(xiàn)。而在網(wǎng)絡(luò)性能問題中,網(wǎng)絡(luò)丟包堪稱最為棘手的難題之一,它就像隱藏在暗處的殺手,悄無聲息地侵蝕著系統(tǒng)的性能。想象一下,當(dāng)你在服務(wù)器上部署了一個(gè)關(guān)鍵的應(yīng)用服務(wù),滿懷期待地等待用戶的訪問和使用。然而,用戶卻頻繁反饋訪問速度極慢,甚至出現(xiàn)連接中斷的情況。經(jīng)過一番排查,你發(fā)現(xiàn)罪魁禍?zhǔn)拙谷皇蔷W(wǎng)絡(luò)丟包。這時(shí)候,你就會(huì)深刻地意識到,網(wǎng)絡(luò)丟包問題絕不是一個(gè)可以忽視的小麻煩。

從專業(yè)角度來看,網(wǎng)絡(luò)丟包會(huì)帶來一系列嚴(yán)重的后果。最直觀的就是網(wǎng)絡(luò)延遲的顯著增加。當(dāng)數(shù)據(jù)包在傳輸過程中被丟棄,接收方就無法及時(shí)收到完整的數(shù)據(jù),這就需要發(fā)送方重新發(fā)送這些丟失的數(shù)據(jù)包。重傳的過程無疑會(huì)消耗額外的時(shí)間,導(dǎo)致數(shù)據(jù)傳輸?shù)难舆t大幅上升。在一些對實(shí)時(shí)性要求極高的應(yīng)用場景中,如在線游戲、視頻會(huì)議等,哪怕是幾毫秒的延遲增加都可能帶來極差的用戶體驗(yàn)。在在線游戲中,延遲的增加可能導(dǎo)致玩家的操作出現(xiàn)卡頓,無法及時(shí)響應(yīng)游戲中的各種事件,嚴(yán)重影響游戲的流暢性和競技性;在視頻會(huì)議中,延遲則可能使畫面出現(xiàn)卡頓、聲音不同步等問題,讓溝通變得異常困難。

網(wǎng)絡(luò)丟包還會(huì)導(dǎo)致吞吐量的降低。吞吐量是指單位時(shí)間內(nèi)成功傳輸?shù)臄?shù)據(jù)量,它是衡量網(wǎng)絡(luò)性能的重要指標(biāo)之一。當(dāng)丟包發(fā)生時(shí),一部分?jǐn)?shù)據(jù)無法正常傳輸,這就必然會(huì)導(dǎo)致實(shí)際的吞吐量下降。對于一些大數(shù)據(jù)傳輸?shù)膱鼍?,如文件下載、數(shù)據(jù)備份等,吞吐量的降低會(huì)大大延長傳輸時(shí)間,降低工作效率。如果你需要從遠(yuǎn)程服務(wù)器下載一個(gè)大型文件,原本預(yù)計(jì)幾個(gè)小時(shí)就能完成的下載任務(wù),可能因?yàn)榫W(wǎng)絡(luò)丟包導(dǎo)致下載時(shí)間延長數(shù)倍,甚至可能因?yàn)閬G包過于嚴(yán)重而導(dǎo)致下載失敗,需要重新開始。

對于基于 TCP 協(xié)議的應(yīng)用來說,丟包更是意味著網(wǎng)絡(luò)擁塞和重傳。TCP 協(xié)議具有可靠性機(jī)制,當(dāng)它檢測到數(shù)據(jù)包丟失時(shí),會(huì)自動(dòng)觸發(fā)重傳機(jī)制,以確保數(shù)據(jù)的完整性。然而,頻繁的重傳不僅會(huì)增加網(wǎng)絡(luò)流量,還會(huì)進(jìn)一步加劇網(wǎng)絡(luò)擁塞,形成一種惡性循環(huán)。在高并發(fā)的網(wǎng)絡(luò)環(huán)境中,這種惡性循環(huán)可能會(huì)導(dǎo)致整個(gè)網(wǎng)絡(luò)的癱瘓,使所有依賴網(wǎng)絡(luò)的應(yīng)用都無法正常運(yùn)行。

網(wǎng)絡(luò)丟包對 Linux 系統(tǒng)性能的影響是多方面的,它不僅會(huì)降低用戶體驗(yàn),還會(huì)影響業(yè)務(wù)的正常運(yùn)行,給企業(yè)帶來巨大的損失。因此,解決網(wǎng)絡(luò)丟包問題刻不容緩,這也是我們今天深入探討 Linux 性能優(yōu)化實(shí)戰(zhàn) —— 網(wǎng)絡(luò)丟包問題分析的重要原因。

在開始之前,我們先用一張圖解釋 linux 系統(tǒng)接收網(wǎng)絡(luò)報(bào)文的過程:

  • 首先網(wǎng)絡(luò)報(bào)文通過物理網(wǎng)線發(fā)送到網(wǎng)卡
  • 網(wǎng)絡(luò)驅(qū)動(dòng)程序會(huì)把網(wǎng)絡(luò)中的報(bào)文讀出來放到 ring buffer 中,這個(gè)過程使用 DMA(Direct Memory Access),不需要 CPU 參與
  • 內(nèi)核從 ring buffer 中讀取報(bào)文進(jìn)行處理,執(zhí)行 IP 和 TCP/UDP 層的邏輯,最后把報(bào)文放到應(yīng)用程序的 socket buffer 中
  • 應(yīng)用程序從 socket buffer 中讀取報(bào)文進(jìn)行處理

圖片圖片

二、探尋“兇手”:丟包可能發(fā)生在哪

當(dāng)網(wǎng)絡(luò)丟包問題出現(xiàn)時(shí),就如同一場懸疑案件,我們需要抽絲剝繭,從各個(gè)層面去探尋 “兇手”,也就是丟包發(fā)生的原因。在 Linux 系統(tǒng)中,丟包可能發(fā)生在網(wǎng)絡(luò)協(xié)議棧的各個(gè)層次,每個(gè)層次都有其獨(dú)特的丟包原因和排查方法。

2.1收包流程:數(shù)據(jù)包的 “入境之路”

圖片圖片

當(dāng)網(wǎng)卡接收到報(bào)文時(shí),這場 “入境之旅” 就開啟了。首先,網(wǎng)卡通過 DMA(直接內(nèi)存訪問)技術(shù),以極高的效率將數(shù)據(jù)包拷貝到 RingBuf(環(huán)形緩沖區(qū))中,就好比貨物被快速卸到了一個(gè)臨時(shí)倉庫。緊接著,網(wǎng)卡向 CPU 發(fā)起一個(gè)硬中斷,就像吹響了緊急集合哨,通知 CPU 有數(shù)據(jù)抵達(dá) “國門”。

CPU 迅速響應(yīng),開始執(zhí)行對應(yīng)的硬中斷處理例程,在這個(gè)例程里,它會(huì)將數(shù)據(jù)包的相關(guān)信息放入每 CPU 變量 poll_list 中,隨后觸發(fā)一個(gè)收包軟中斷,把后續(xù)的精細(xì)活兒交給軟中斷去處理。對應(yīng) CPU 的軟中斷線程 ksoftirqd 就登場了,它負(fù)責(zé)處理網(wǎng)絡(luò)包接收軟中斷,具體來說,就是執(zhí)行 net_rx_action () 函數(shù)。

在這個(gè)函數(shù)的 “指揮” 下,數(shù)據(jù)包從 RingBuf 中被小心翼翼地取出,然后進(jìn)入?yún)f(xié)議棧,開啟層層闖關(guān)。從鏈路層開始,檢查報(bào)文合法性,剝?nèi)^、幀尾,接著進(jìn)入網(wǎng)絡(luò)層,判斷包的走向,若是發(fā)往本機(jī),再傳遞到傳輸層。最終,數(shù)據(jù)包被妥妥地放到 socket 的接收隊(duì)列中,等待應(yīng)用層隨時(shí)來收取,至此,數(shù)據(jù)包算是順利 “入境”,完成了它的收包流程。

2.2發(fā)包流程:數(shù)據(jù)包的 “出境之旅”

圖片圖片

應(yīng)用程序要發(fā)送數(shù)據(jù)時(shí),數(shù)據(jù)包的 “出境之旅” 便啟程了。首先,應(yīng)用程序調(diào)用 Socket API(比如 sendmsg)發(fā)送網(wǎng)絡(luò)包,這一操作觸發(fā)系統(tǒng)調(diào)用,使得數(shù)據(jù)從用戶空間拷貝到內(nèi)核空間,同時(shí),內(nèi)核會(huì)為其分配一個(gè) skb(sk_buff 結(jié)構(gòu)體,它可是數(shù)據(jù)包在內(nèi)核中的 “代言人”,承載著各種關(guān)鍵信息),并將數(shù)據(jù)封裝其中。接著,skb 進(jìn)入?yún)f(xié)議棧,開始自上而下的 “闖關(guān)升級”。

在傳輸層,會(huì)為數(shù)據(jù)添加 TCP 頭或 UDP 頭,進(jìn)行擁塞控制、滑動(dòng)窗口等一系列精細(xì)操作;到了網(wǎng)絡(luò)層,依據(jù)目標(biāo) IP 地址查找路由表,確定下一跳,填充 IP 頭中的源和目標(biāo) IP 地址、TTL 等關(guān)鍵信息,還可能進(jìn)行 skb 切分,同時(shí)要經(jīng)過 netfilter 框架的 “安檢”,判斷是否符合過濾規(guī)則。

之后,在鄰居子系統(tǒng)填充目的 MAC 地址,再進(jìn)入網(wǎng)絡(luò)設(shè)備子系統(tǒng),skb 被放入發(fā)送隊(duì)列 RingBuf 中,等待網(wǎng)卡發(fā)送。網(wǎng)卡發(fā)送完成后,會(huì)向 CPU 發(fā)出一個(gè)硬中斷,告知 “任務(wù)完成”,這個(gè)硬中斷又會(huì)觸發(fā)軟中斷,在軟中斷處理函數(shù)中,對 RingBuf 進(jìn)行清理,把已經(jīng)發(fā)送成功的數(shù)據(jù)包殘留信息清除掉,就像清理運(yùn)輸后的車廂,為下一次運(yùn)輸做好準(zhǔn)備,至此,數(shù)據(jù)包順利 “出境”,完成了它的發(fā)包流程。

三、鏈路層詳解

當(dāng)鏈路層由于緩沖區(qū)溢出等原因?qū)е戮W(wǎng)卡丟包時(shí),Linux 會(huì)在網(wǎng)卡收發(fā)數(shù)據(jù)的統(tǒng)計(jì)信息中記錄下收發(fā)錯(cuò)誤的次數(shù)。鏈路層是網(wǎng)絡(luò)通信的基礎(chǔ),它負(fù)責(zé)將網(wǎng)絡(luò)層傳來的數(shù)據(jù)封裝成幀,并通過物理介質(zhì)進(jìn)行傳輸。鏈路層丟包通常是由于硬件故障、網(wǎng)絡(luò)擁塞或者配置錯(cuò)誤等原因?qū)е碌摹.?dāng)鏈路層由于緩沖區(qū)溢出等原因?qū)е戮W(wǎng)卡丟包時(shí),Linux 會(huì)在網(wǎng)卡收發(fā)數(shù)據(jù)的統(tǒng)計(jì)信息中記錄下收發(fā)錯(cuò)誤的次數(shù)。

我們可以通過 ethtool 或者 netstat 命令,來查看網(wǎng)卡的丟包記錄:

netstat -i
 
Kernel Interface table
Iface      MTU    RX-OK RX-ERR RX-DRP RX-OVR    TX-OK TX-ERR TX-DRP TX-OVR Flg
eth0       100       31      0      0 0             8      0      0      0 BMRU
lo       65536        0      0      0 0             0      0      0      0 LRU

RX-OK、RX-ERR、RX-DRP、RX-OVR ,分別表示接收時(shí)的總包數(shù)、總錯(cuò)誤數(shù)、進(jìn)入 Ring Buffer 后因其他原因(如內(nèi)存不足)導(dǎo)致的丟包數(shù)以及 Ring Buffer 溢出導(dǎo)致的丟包數(shù)。

TX-OK、TX-ERR、TX-DRP、TX-OVR 也代表類似的含義,只不過是指發(fā)送時(shí)對應(yīng)的各個(gè)指標(biāo)。

這里我們沒有發(fā)現(xiàn)任何錯(cuò)誤,說明虛擬網(wǎng)卡沒有丟包。不過要注意,如果用 tc 等工具配置了 QoS,那么 tc 規(guī)則導(dǎo)致的丟包,就不會(huì)包含在網(wǎng)卡的統(tǒng)計(jì)信息中。所以接下來,我們還要檢查一下 eth0 上是否配置了 tc 規(guī)則,并查看有沒有丟包。添加 -s 選項(xiàng),以輸出統(tǒng)計(jì)信息:

tc -s qdisc show dev eth0
 
qdisc netem 800d: root refcnt 2 limit 1000 loss 30%
 Sent 432 bytes 8 pkt (dropped 4, overlimits 0 requeues 0)
 backlog 0b 0p requeues 0

可以看到, eth0 上配置了一個(gè)網(wǎng)絡(luò)模擬排隊(duì)規(guī)則(qdisc netem),并且配置了丟包率為 30%(loss 30%)。再看后面的統(tǒng)計(jì)信息,發(fā)送了 8 個(gè)包,但是丟了 4個(gè)。看來應(yīng)該就是這里導(dǎo)致 Nginx 回復(fù)的響應(yīng)包被 netem 模塊給丟了。

既然發(fā)現(xiàn)了問題,解決方法也很簡單,直接刪掉 netem 模塊就可以了。執(zhí)行下面的命令,刪除 tc 中的 netem 模塊:

tc qdisc del dev eth0 root netem loss 30%

刪除后,重新執(zhí)行之前的 hping3 命令,看看現(xiàn)在還有沒有問題:

hping3 -c 10 -S -p 80 192.168.0.30
 
HPING 192.168.0.30 (eth0 192.168.0.30): S set, 40 headers + 0 data bytes
len=44 ip=192.168.0.30 ttl=63 DF id=0 sport=80 flags=SA seq=0 win=5120 rtt=7.9 ms
len=44 ip=192.168.0.30 ttl=63 DF id=0 sport=80 flags=SA seq=2 win=5120 rtt=1003.8 ms
len=44 ip=192.168.0.30 ttl=63 DF id=0 sport=80 flags=SA seq=5 win=5120 rtt=7.6 ms
len=44 ip=192.168.0.30 ttl=63 DF id=0 sport=80 flags=SA seq=6 win=5120 rtt=7.4 ms
len=44 ip=192.168.0.30 ttl=63 DF id=0 sport=80 flags=SA seq=9 win=5120 rtt=3.0 ms
 
--- 192.168.0.30 hping statistic ---
10 packets transmitted, 5 packets received, 50% packet loss
round-trip min/avg/max = 3.0/205.9/1003.8 ms

不幸的是,從 hping3 的輸出中可以看到還是 50% 的丟包,RTT 的波動(dòng)也仍舊很大,從 3ms 到 1s。顯然,問題還是沒解決,丟包還在繼續(xù)發(fā)生。不過,既然鏈路層已經(jīng)排查完了,我們就繼續(xù)向上層分析,看看網(wǎng)絡(luò)層和傳輸層有沒有問題。

四、網(wǎng)絡(luò)層和傳輸層

在網(wǎng)絡(luò)層和傳輸層中,引發(fā)丟包的因素非常多。不過,其實(shí)想確認(rèn)是否丟包,是非常簡單的事,因?yàn)?Linux 已經(jīng)為我們提供了各個(gè)協(xié)議的收發(fā)匯總情況。

⑴網(wǎng)絡(luò)層

網(wǎng)絡(luò)層負(fù)責(zé)將數(shù)據(jù)包從源地址傳輸?shù)侥康牡刂?,它主要處理路由選擇、IP 地址解析等功能。網(wǎng)絡(luò)層丟包可能是由于路由失敗、組包大小超過 MTU(最大傳輸單元)等原因引起的。當(dāng)數(shù)據(jù)包的大小超過了網(wǎng)絡(luò)中某條鏈路的 MTU 時(shí),數(shù)據(jù)包就需要被分片傳輸,如果分片過程出現(xiàn)問題,或者在重組過程中丟失了部分分片,就會(huì)導(dǎo)致丟包。我們可以通過netstat -s命令查看 IP 層的統(tǒng)計(jì)信息,其中IpInReceives表示接收到的 IP 數(shù)據(jù)包總數(shù),IpInDelivers表示成功交付給上層協(xié)議的 IP 數(shù)據(jù)包數(shù),如果兩者之間的差值較大,就可能存在網(wǎng)絡(luò)層丟包的情況。還可以查看IpOutNoRoutes指標(biāo),它表示因?yàn)檎也坏铰酚啥鴣G棄的數(shù)據(jù)包數(shù),如果這個(gè)值不斷增加,說明可能存在路由問題導(dǎo)致丟包。

⑵傳輸層

傳輸層負(fù)責(zé)為應(yīng)用層提供端到端的通信服務(wù),常見的傳輸層協(xié)議有 TCP 和 UDP。傳輸層丟包可能是由于端口未監(jiān)聽、資源占用超過內(nèi)核限制等原因造成的。在高并發(fā)的網(wǎng)絡(luò)環(huán)境中,如果應(yīng)用程序創(chuàng)建了大量的 TCP 連接,而系統(tǒng)資源(如文件描述符、內(nèi)存等)有限,就可能導(dǎo)致部分連接無法正常建立或維持,從而出現(xiàn)丟包現(xiàn)象。我們可以通過netstat -s命令查看 TCP 和 UDP 協(xié)議的統(tǒng)計(jì)信息,比如TcpRetransSegs表示 TCP 重傳的數(shù)據(jù)包數(shù),如果這個(gè)值較大,說明可能存在傳輸層丟包導(dǎo)致的重傳。UdpInErrors表示接收到的 UDP 錯(cuò)誤數(shù)據(jù)包數(shù),如果該值不為零,也提示可能存在 UDP 丟包問題。

執(zhí)行 netstat -s 命令,可以看到協(xié)議的收發(fā)匯總,以及錯(cuò)誤信息:

netstat -s
#輸出
Ip:
    Forwarding: 1          //開啟轉(zhuǎn)發(fā)
    31 total packets received    //總收包數(shù)
    0 forwarded            //轉(zhuǎn)發(fā)包數(shù)
    0 incoming packets discarded  //接收丟包數(shù)
    25 incoming packets delivered  //接收的數(shù)據(jù)包數(shù)
    15 requests sent out      //發(fā)出的數(shù)據(jù)包數(shù)
Icmp:
    0 ICMP messages received    //收到的ICMP包數(shù)
    0 input ICMP message failed    //收到ICMP失敗數(shù)
    ICMP input histogram:
    0 ICMP messages sent      //ICMP發(fā)送數(shù)
    0 ICMP messages failed      //ICMP失敗數(shù)
    ICMP output histogram:
Tcp:
    0 active connection openings  //主動(dòng)連接數(shù)
    0 passive connection openings  //被動(dòng)連接數(shù)
    11 failed connection attempts  //失敗連接嘗試數(shù)
    0 connection resets received  //接收的連接重置數(shù)
    0 connections established    //建立連接數(shù)
    25 segments received      //已接收報(bào)文數(shù)
    21 segments sent out      //已發(fā)送報(bào)文數(shù)
    4 segments retransmitted    //重傳報(bào)文數(shù)
    0 bad segments received      //錯(cuò)誤報(bào)文數(shù)
    0 resets sent          //發(fā)出的連接重置數(shù)
Udp:
    0 packets received
    ...
TcpExt:
    11 resets received for embryonic SYN_RECV sockets  //半連接重置數(shù)
    0 packet headers predicted
    TCPTimeouts: 7    //超時(shí)數(shù)
    TCPSynRetrans: 4  //SYN重傳數(shù)
  ...

etstat 匯總了 IP、ICMP、TCP、UDP 等各種協(xié)議的收發(fā)統(tǒng)計(jì)信息。不過,我們的目的是排查丟包問題,所以這里主要觀察的是錯(cuò)誤數(shù)、丟包數(shù)以及重傳數(shù)??梢钥吹剑挥?TCP 協(xié)議發(fā)生了丟包和重傳,分別是:

  • 11 次連接失敗重試(11 failed connection attempts)
  • 4 次重傳(4 segments retransmitted)
  • 11 次半連接重置(11 resets received for embryonic SYN_RECV sockets)
  • 4 次 SYN 重傳(TCPSynRetrans)
  • 7 次超時(shí)(TCPTimeouts)

這個(gè)結(jié)果告訴我們,TCP 協(xié)議有多次超時(shí)和失敗重試,并且主要錯(cuò)誤是半連接重置。換句話說,主要的失敗,都是三次握手失敗。不過,雖然在這兒看到了這么多失敗,但具體失敗的根源還是無法確定。

五、iptables規(guī)則

iptables 是 Linux 系統(tǒng)中常用的防火墻工具,它可以根據(jù)用戶定義的規(guī)則對網(wǎng)絡(luò)數(shù)據(jù)包進(jìn)行過濾和處理。如果 iptables 的規(guī)則配置不當(dāng),就可能導(dǎo)致數(shù)據(jù)包被錯(cuò)誤地丟棄。我們可以通過iptables -L -n命令查看當(dāng)前的 iptables 規(guī)則,檢查是否存在不合理的規(guī)則,如錯(cuò)誤的端口過濾、源地址或目的地址限制等。也可以使用iptables -v -L命令查看規(guī)則的統(tǒng)計(jì)信息,了解哪些規(guī)則被頻繁匹配,從而判斷是否是 iptables 規(guī)則導(dǎo)致了丟包。

首先,除了網(wǎng)絡(luò)層和傳輸層的各種協(xié)議,iptables 和內(nèi)核的連接跟蹤機(jī)制也可能會(huì)導(dǎo)致丟包。所以,這也是發(fā)生丟包問題時(shí)我們必須要排查的一個(gè)因素。

先來看看連接跟蹤,要確認(rèn)是不是連接跟蹤導(dǎo)致的問題,只需要對比當(dāng)前的連接跟蹤數(shù)和最大連接跟蹤數(shù)即可。

# 主機(jī)終端中查詢內(nèi)核配置
$ sysctl net.netfilter.nf_conntrack_max
net.netfilter.nf_conntrack_max = 262144
$ sysctl net.netfilter.nf_conntrack_count
net.netfilter.nf_conntrack_count = 182

可以看到,連接跟蹤數(shù)只有 182,而最大連接跟蹤數(shù)則是 262144。顯然,這里的丟包,不可能是連接跟蹤導(dǎo)致的。

接著,再來看 iptables?;仡櫼幌?iptables 的原理,它基于 Netfilter 框架,通過一系列的規(guī)則,對網(wǎng)絡(luò)數(shù)據(jù)包進(jìn)行過濾(如防火墻)和修改(如 NAT)。這些 iptables 規(guī)則,統(tǒng)一管理在一系列的表中,包括 filter、nat、mangle(用于修改分組數(shù)據(jù)) 和 raw(用于原始數(shù)據(jù)包)等。而每張表又可以包括一系列的鏈,用于對 iptables 規(guī)則進(jìn)行分組管理。

對于丟包問題來說,最大的可能就是被 filter 表中的規(guī)則給丟棄了。要弄清楚這一點(diǎn),就需要我們確認(rèn),那些目標(biāo)為 DROP 和 REJECT 等會(huì)棄包的規(guī)則,有沒有被執(zhí)行到??梢灾苯硬樵?DROP 和 REJECT 等規(guī)則的統(tǒng)計(jì)信息,看看是否為0。如果不是 0 ,再把相關(guān)的規(guī)則拎出來進(jìn)行分析。

iptables -t filter -nvL
#輸出
Chain INPUT (policy ACCEPT 25 packets, 1000 bytes)
 pkts bytes target     prot opt in     out     source               destination
    6   240 DROP       all  --  *      *       0.0.0.0/0            0.0.0.0/0            statistic mode random probability 0.29999999981
 
Chain FORWARD (policy ACCEPT 0 packets, 0 bytes)
 pkts bytes target     prot opt in     out     source               destination
 
Chain OUTPUT (policy ACCEPT 15 packets, 660 bytes)
 pkts bytes target     prot opt in     out     source               destination
    6   264 DROP       all  --  *      *       0.0.0.0/0            0.0.0.0/0            statistic mode random probability 0.29999999981

從 iptables 的輸出中,你可以看到,兩條 DROP 規(guī)則的統(tǒng)計(jì)數(shù)值不是 0,它們分別在INPUT 和 OUTPUT 鏈中。這兩條規(guī)則實(shí)際上是一樣的,指的是使用 statistic 模塊,進(jìn)行隨機(jī) 30% 的丟包。0.0.0.0/0 表示匹配所有的源 IP 和目的 IP,也就是會(huì)對所有包都進(jìn)行隨機(jī) 30% 的丟包。看起來,這應(yīng)該就是導(dǎo)致部分丟包的“罪魁禍?zhǔn)住绷恕?/p>

執(zhí)行下面的兩條 iptables 命令,刪除這兩條 DROP 規(guī)則。

root@nginx:/# iptables -t filter -D INPUT -m statistic --mode random --probability 0.30 -j DROP
root@nginx:/# iptables -t filter -D OUTPUT -m statistic --mode random --probability 0.30 -j DROP

再次執(zhí)行剛才的 hping3 命令,看看現(xiàn)在是否正常

hping3 -c 10 -S -p 80 192.168.0.30
#輸出
HPING 192.168.0.30 (eth0 192.168.0.30): S set, 40 headers + 0 data bytes
len=44 ip=192.168.0.30 ttl=63 DF id=0 sport=80 flags=SA seq=0 win=5120 rtt=11.9 ms
len=44 ip=192.168.0.30 ttl=63 DF id=0 sport=80 flags=SA seq=1 win=5120 rtt=7.8 ms
...
len=44 ip=192.168.0.30 ttl=63 DF id=0 sport=80 flags=SA seq=9 win=5120 rtt=15.0 ms
 
--- 192.168.0.30 hping statistic ---
10 packets transmitted, 10 packets received, 0% packet loss
round-trip min/avg/max = 3.3/7.9/15.0 ms

這次輸出你可以看到,現(xiàn)在已經(jīng)沒有丟包了,并且延遲的波動(dòng)變化也很小??磥?,丟包問題應(yīng)該已經(jīng)解決了。

不過,到目前為止,我們一直使用的 hping3 工具,只能驗(yàn)證案例 Nginx 的 80 端口處于正常監(jiān)聽狀態(tài),卻還沒有訪問 Nginx 的 HTTP 服務(wù)。所以,不要匆忙下結(jié)論結(jié)束這次優(yōu)化,我們還需要進(jìn)一步確認(rèn),Nginx 能不能正常響應(yīng) HTTP 請求。我們繼續(xù)在終端二中,執(zhí)行如下的 curl 命令,檢查 Nginx 對 HTTP 請求的響應(yīng):

$ curl --max-time 3 http://192.168.0.30
curl: (28) Operation timed out after 3000 milliseconds with 0 bytes received

奇怪,hping3 的結(jié)果顯示Nginx 的 80 端口是正常狀態(tài),為什么還是不能正常響應(yīng) HTTP 請求呢?別忘了,我們還有個(gè)大殺器——抓包操作??磥碛斜匾グ纯戳?。

六、tcpdump命令工具使用

執(zhí)行下面的 tcpdump 命令,抓取 80 端口的包如下:

tcpdump -i eth0 -nn port 80
#輸出
tcpdump: verbose output suppressed, use -v or -vv for full protocol decode
listening on eth0, link-type EN10MB (Ethernet), capture size 262144 bytes

然后,切換到終端二中,再次執(zhí)行前面的 curl 命令:

curl --max-time 3 http://192.168.0.30
curl: (28) Operation timed out after 3000 milliseconds with 0 bytes received

等到 curl 命令結(jié)束后,再次切換回終端一,查看 tcpdump 的輸出:

14:40:00.589235 IP 10.255.255.5.39058 > 172.17.0.2.80: Flags [S], seq 332257715, win 29200, options [mss 1418,sackOK,TS val 486800541 ecr 0,nop,wscale 7], length 0
14:40:00.589277 IP 172.17.0.2.80 > 10.255.255.5.39058: Flags [S.], seq 1630206251, ack 332257716, win 4880, options [mss 256,sackOK,TS val 2509376001 ecr 486800541,nop,wscale 7], length 0
14:40:00.589894 IP 10.255.255.5.39058 > 172.17.0.2.80: Flags [.], ack 1, win 229, options [nop,nop,TS val 486800541 ecr 2509376001], length 0
14:40:03.589352 IP 10.255.255.5.39058 > 172.17.0.2.80: Flags [F.], seq 76, ack 1, win 229, options [nop,nop,TS val 486803541 ecr 2509376001], length 0
14:40:03.589417 IP 172.17.0.2.80 > 10.255.255.5.39058: Flags [.], ack 1, win 40, options [nop,nop,TS val 2509379001 ecr 486800541,nop,nop,sack 1 {76:77}], length 0

從 tcpdump 的輸出中,我們就可以看到:

  • 前三個(gè)包是正常的 TCP 三次握手,這沒問題;
  • 但第四個(gè)包卻是在 3 秒以后了,并且還是客戶端(VM2)發(fā)送過來的 FIN 包,說明客戶端的連接關(guān)閉了

根據(jù) curl 設(shè)置的 3 秒超時(shí)選項(xiàng),你應(yīng)該能猜到,這是因?yàn)?curl 命令超時(shí)后退出了。用 Wireshark 的 Flow Graph 來表示,你可以更清楚地看到上面這個(gè)問題:

圖片圖片

這里比較奇怪的是,我們并沒有抓取到 curl 發(fā)來的 HTTP GET 請求。那究竟是網(wǎng)卡丟包了,還是客戶端就沒發(fā)過來呢?

可以重新執(zhí)行 netstat -i 命令,確認(rèn)一下網(wǎng)卡有沒有丟包問題:

netstat -i
 
Kernel Interface table
Iface      MTU    RX-OK RX-ERR RX-DRP RX-OVR    TX-OK TX-ERR TX-DRP TX-OVR Flg
eth0       100      157      0    344 0            94      0      0      0 BMRU
lo       65536        0      0      0 0             0      0      0      0 LRU

從 netstat 的輸出中,你可以看到,接收丟包數(shù)(RX-DRP)是 344,果然是在網(wǎng)卡接收時(shí)丟包了。不過問題也來了,為什么剛才用 hping3 時(shí)不丟包,現(xiàn)在換成 GET 就收不到了呢?還是那句話,遇到搞不懂的現(xiàn)象,不妨先去查查工具和方法的原理。我們可以對比一下這兩個(gè)工具:

  • hping3 實(shí)際上只發(fā)送了 SYN 包;
  • curl 在發(fā)送 SYN 包后,還會(huì)發(fā)送 HTTP GET 請求。HTTP GET本質(zhì)上也是一個(gè) TCP 包,但跟 SYN 包相比,它還攜帶了 HTTP GET 的數(shù)據(jù)。

通過這個(gè)對比,你應(yīng)該想到了,這可能是 MTU 配置錯(cuò)誤導(dǎo)致的。為什么呢?

其實(shí),仔細(xì)觀察上面 netstat 的輸出界面,第二列正是每個(gè)網(wǎng)卡的 MTU 值。eth0 的 MTU只有 100,而以太網(wǎng)的 MTU 默認(rèn)值是 1500,這個(gè) 100 就顯得太小了。當(dāng)然,MTU 問題是很好解決的,把它改成 1500 就可以了。

ifconfig eth0 mtu 1500

修改完成后,再切換到終端二中,再次執(zhí)行 curl 命令,確認(rèn)問題是否真的解決了:

curl --max-time 3 http://192.168.0.30/
#輸出
<!DOCTYPE html>
<html>
...
<p><em>Thank you for using nginx.</em></p>
</body>
</html>

非常不容易呀,這次終于看到了熟悉的 Nginx 響應(yīng),說明丟包的問題終于徹底解決了。

七、實(shí)戰(zhàn)演練:排查與解決 Nginx 丟包問題

理論上的分析固然重要,但實(shí)際操作才是檢驗(yàn)真理的關(guān)鍵。下面,我們將通過一個(gè)具體的案例,以 Nginx 應(yīng)用為例,深入探討如何在實(shí)際場景中排查和解決網(wǎng)絡(luò)丟包問題。

7.1模擬訪問與初步判斷

假設(shè)我們在一臺 Linux 服務(wù)器上部署了 Nginx 應(yīng)用,現(xiàn)在懷疑它存在網(wǎng)絡(luò)丟包問題。我們首先使用 hping3 命令來模擬訪問 Nginx 服務(wù)。hping3 是一個(gè)功能強(qiáng)大的網(wǎng)絡(luò)工具,它可以發(fā)送各種類型的網(wǎng)絡(luò)數(shù)據(jù)包,幫助我們測試網(wǎng)絡(luò)的連通性和性能。執(zhí)行以下命令:

hping3 -c 10 -S -p 80 192.168.0.30

在這個(gè)命令中,-c 10表示發(fā)送 10 個(gè)請求包,-S表示使用 TCP SYN 標(biāo)志位,-p 80指定目標(biāo)端口為 80,即 Nginx 服務(wù)默認(rèn)的端口,192.168.0.30是 Nginx 服務(wù)器的 IP 地址。執(zhí)行命令后,我們得到如下輸出:

HPING 192.168.0.30 (eth0 192.168.0.30): S set, 40 headers + 0 data bytes
len=44 ip=192.168.0.30 ttl=63 DF id=0 sport=80 flags=SA seq=3 win=5120 rtt=7.5 ms
len=44 ip=192.168.0.30 ttl=63 DF id=0 sport=80 flags=SA seq=4 win=5120 rtt=7.4 ms
len=44 ip=192.168.0.30 ttl=63 DF id=0 sport=80 flags=SA seq=5 win=5120 rtt=3.3 ms
len=44 ip=192.168.0.30 ttl=63 DF id=0 sport=80 flags=SA seq=7 win=5120 rtt=3.0 ms
len=44 ip=192.168.0.30 ttl=63 DF id=0 sport=80 flags=SA seq=6 win=5120 rtt=3027.2 ms
--- 192.168.0.30 hping statistic ---
10 packets transmitted, 5 packets received, 50% packet loss
round-trip min/avg/max = 3.0/609.7/3027.2 ms

從輸出結(jié)果中,我們可以清晰地看到,總共發(fā)送了 10 個(gè)請求包,但只收到了 5 個(gè)回復(fù)包,丟包率高達(dá) 50%。而且,每個(gè)請求的 RTT(往返時(shí)間)波動(dòng)非常大,最小值只有 3.0ms,而最大值卻達(dá)到了 3027.2ms,這表明網(wǎng)絡(luò)中很可能存在丟包現(xiàn)象。

7.2鏈路層排查

初步判斷存在丟包問題后,我們首先從鏈路層開始排查。使用netstat -i命令查看虛擬網(wǎng)卡的丟包記錄:

netstat -i

得到如下輸出:

Kernel Interface table
Iface      MTU    RX-OK RX-ERR RX-DRP RX-OVR    TX-OK TX-ERR TX-DRP TX-OVR Flg
eth0      100       31      0      0    0             8      0      0      0 BMRU
lo       65536        0      0      0    0             0      0      0      0 LRUR

在這個(gè)輸出中,RX-OK表示接收時(shí)的總包數(shù),RX-ERR表示總錯(cuò)誤數(shù),RX-DRP表示進(jìn)入 Ring Buffer 后因其他原因(如內(nèi)存不足)導(dǎo)致的丟包數(shù),RX-OVR表示 Ring Buffer 溢出導(dǎo)致的丟包數(shù),TX-OK至TX-OVR則表示發(fā)送時(shí)的相應(yīng)指標(biāo)。從這里可以看出,虛擬網(wǎng)卡的各項(xiàng)錯(cuò)誤指標(biāo)均為 0,說明虛擬網(wǎng)卡本身沒有丟包。

不過,如果使用tc等工具配置了 QoS(Quality of Service,服務(wù)質(zhì)量),tc規(guī)則導(dǎo)致的丟包不會(huì)包含在網(wǎng)卡的統(tǒng)計(jì)信息中。因此,我們還需要檢查eth0上是否配置了tc規(guī)則,并查看是否有丟包。添加-s選項(xiàng)以輸出統(tǒng)計(jì)信息:

tc -s qdisc show dev eth0

輸出結(jié)果如下:

qdisc netem 800d: root refcnt 2 limit 1000 loss 30%
Sent 432 bytes 8 pkt (dropped 4, overlimits 0 requeues 0)
backlog 0b 0p requeues 0

可以看到,eth0上配置了一個(gè)網(wǎng)絡(luò)模擬排隊(duì)規(guī)則qdisc netem,并且設(shè)置了丟包率為 30%(loss 30%)。從后面的統(tǒng)計(jì)信息可知,發(fā)送了 8 個(gè)包,但丟了 4 個(gè)。這很可能就是導(dǎo)致 Nginx 回復(fù)的響應(yīng)包被netem模塊丟棄的原因。既然找到了問題,解決方法就很簡單,直接刪除netem模塊:

tc qdisc del dev eth0 root netem loss 30%

刪除后,重新執(zhí)行hping3命令,看看問題是否解決。然而,從hping3的輸出中發(fā)現(xiàn),仍然有 50% 的丟包,RTT 波動(dòng)依舊很大,說明問題還未得到解決,需要繼續(xù)向上層排查。

網(wǎng)絡(luò)層和傳輸層排查

接下來,我們排查網(wǎng)絡(luò)層和傳輸層。在這兩層中,引發(fā)丟包的因素眾多,但確認(rèn)是否丟包卻相對簡單,因?yàn)?Linux 已經(jīng)為我們提供了各個(gè)協(xié)議的收發(fā)匯總情況。執(zhí)行netstat -s命令,查看 IP、ICMP、TCP 和 UDP 等協(xié)議的收發(fā)統(tǒng)計(jì)信息:

netstat -s

輸出結(jié)果非常豐富,這里我們重點(diǎn)關(guān)注與丟包相關(guān)的信息。例如,從 TCP 協(xié)議的統(tǒng)計(jì)信息中,我們看到有多次超時(shí)和失敗重試,并且主要錯(cuò)誤是半連接重置,這表明可能存在三次握手失敗的問題。這可能是由于網(wǎng)絡(luò)擁塞、端口被占用、防火墻限制等原因?qū)е碌摹4藭r(shí),我們需要進(jìn)一步分析具體的錯(cuò)誤原因,可以結(jié)合其他工具和命令,如lsof查看端口占用情況,檢查防火墻規(guī)則等。

7.3iptables 排查

iptables 是 Linux 系統(tǒng)中常用的防火墻工具,其規(guī)則配置不當(dāng)可能導(dǎo)致數(shù)據(jù)包被丟棄。首先,我們檢查內(nèi)核的連接跟蹤機(jī)制,查看當(dāng)前的連接跟蹤數(shù)和最大連接跟蹤數(shù):

cat /proc/sys/net/nf_conntrack_count
cat /proc/sys/net/nf_conntrack_max

假設(shè)連接跟蹤數(shù)只有 182,而最大連接跟蹤數(shù)是 262144,說明連接跟蹤數(shù)沒有達(dá)到上限,不存在因連接跟蹤數(shù)滿而導(dǎo)致丟包的問題。

接著,查看 iptables 規(guī)則,使用iptables -L -n命令:

iptables -L -n

在輸出的規(guī)則列表中,我們發(fā)現(xiàn)有兩條DROP規(guī)則,使用了statistic模塊進(jìn)行隨機(jī) 30% 的丟包。這顯然是導(dǎo)致丟包的一個(gè)重要原因。我們將這兩條規(guī)則直接刪除,然后重新執(zhí)行hping3命令。此時(shí),hping3的輸出顯示已經(jīng)沒有丟包,這說明 iptables 的錯(cuò)誤規(guī)則是導(dǎo)致之前丟包的原因之一。

端口狀態(tài)檢查與進(jìn)一步排查

雖然hping3驗(yàn)證了 Nginx 的 80 端口處于正常監(jiān)聽狀態(tài),但還需要檢查 Nginx 對 HTTP 請求的響應(yīng)。使用curl命令:

curl -w 'Http code: %{http_code}\\nTotal time:%{time_total}s\\n' -o /dev/null --connect-timeout 10 http://192.168.0.30/

結(jié)果發(fā)現(xiàn)連接超時(shí),這表明雖然端口監(jiān)聽正常,但 Nginx 在處理 HTTP 請求時(shí)可能存在問題。為了進(jìn)一步分析,我們使用tcpdump命令抓包:

tcpdump -i eth0 -n tcp port 80

在另一個(gè)終端執(zhí)行curl命令,然后查看tcpdump的輸出。發(fā)現(xiàn)前三個(gè)包是正常的 TCP 三次握手,但第四個(gè)包卻是在 3 秒后才收到,并且是客戶端發(fā)送過來的 FIN 包,這說明客戶端的連接已經(jīng)關(guān)閉。

重新執(zhí)行netstat -i命令,檢查網(wǎng)卡是否有丟包,發(fā)現(xiàn)果然是在網(wǎng)卡接收時(shí)丟包了。進(jìn)一步檢查最大傳輸單元 MTU(Maximum Transmission Unit):

ifconfig eth0 | grep MTU

發(fā)現(xiàn)eth0的 MTU 只有 100,而以太網(wǎng)的 MTU 默認(rèn)值是 1500。MTU 過小可能導(dǎo)致數(shù)據(jù)包在傳輸過程中需要分片,從而增加丟包的風(fēng)險(xiǎn)。我們將 MTU 修改為 1500:

ifconfig eth0 mtu 1500

再次執(zhí)行curl命令,問題得到解決,Nginx 能夠正常響應(yīng) HTTP 請求。

責(zé)任編輯:武曉燕 來源: 深度Linux
相關(guān)推薦

2013-02-27 10:39:41

網(wǎng)絡(luò)丟包故障

2017-03-29 14:44:20

網(wǎng)絡(luò)性能優(yōu)化

2022-07-15 08:52:03

Linux優(yōu)化

2022-04-13 11:46:17

抓包wireshark丟包

2009-07-27 10:39:50

2017-05-26 10:54:31

網(wǎng)絡(luò)故障丟包網(wǎng)絡(luò)診斷

2022-05-26 16:51:07

網(wǎng)絡(luò)丟包網(wǎng)絡(luò)故障網(wǎng)絡(luò)

2023-11-01 11:59:13

2009-04-20 08:51:50

MySQL查詢優(yōu)化數(shù)據(jù)庫

2022-05-17 09:02:30

前端性能優(yōu)化

2010-12-20 10:56:32

Linux網(wǎng)絡(luò)性能優(yōu)化

2014-01-22 09:39:21

科來軟件網(wǎng)絡(luò)回溯分析

2019-12-13 10:25:08

Android性能優(yōu)化啟動(dòng)優(yōu)化

2022-06-28 16:00:17

Linux網(wǎng)絡(luò)性能優(yōu)化

2018-10-12 14:34:13

2022-06-13 13:45:56

Linuxmtr命令

2011-01-04 09:25:40

延時(shí)模擬丟包模擬

2021-07-29 14:20:34

網(wǎng)絡(luò)優(yōu)化移動(dòng)互聯(lián)網(wǎng)數(shù)據(jù)存儲

2022-02-16 14:10:51

服務(wù)器性能優(yōu)化Linux

2021-11-29 11:13:45

服務(wù)器網(wǎng)絡(luò)性能
點(diǎn)贊
收藏

51CTO技術(shù)棧公眾號