日本黄色一级经典视频|伊人久久精品视频|亚洲黄色色周成人视频九九九|av免费网址黄色小短片|黄色Av无码亚洲成年人|亚洲1区2区3区无码|真人黄片免费观看|无码一级小说欧美日免费三级|日韩中文字幕91在线看|精品久久久无码中文字幕边打电话

當前位置:首頁 > > 21ic電子網
[導讀]作者:CloudDeveloper 鏈接:https://cizixs.com/2018/01/13/linux-udp-packet-drop-debug/ 最近工作中遇到某個服務器應用程序 UDP 丟包,在排查過程中查閱了很多資料,我在排查過程中基本都是通過使用 tcpdump 在出現問題的各個環(huán)節(jié)上進行抓包、分析在那個環(huán)

作者:CloudDeveloper

鏈接:https://cizixs.com/2018/01/13/linux-udp-packet-drop-debug/

最近工作中遇到某個服務器應用程序 UDP 丟包,在排查過程中查閱了很多資料,我在排查過程中基本都是通過使用 tcpdump 在出現問題的各個環(huán)節(jié)上進行抓包、分析在那個環(huán)節(jié)出現問題、針對性去排查解決問題,對癥下藥,最后終究能夠解決問題。但是這種情況大多是因為服務本身的問題,如果是環(huán)境問題、操作系統、甚至硬件的問題,可能從服務本身出發(fā)不能解決問題,但是這篇文章另辟蹊徑,從外部環(huán)境分析可能丟包的原因,看完之后,很受用,部分章節(jié)對原文有所修改,下面分享出來供更多人參考。


在開始之前,我們先用一張圖解釋 linux 系統接收網絡報文的過程。

  1. 首先網絡報文通過物理網線發(fā)送到網卡

  2. 網絡驅動程序會把網絡中的報文讀出來放到 ring buffer 中,這個過程使用 DMA(Direct Memory Access),不需要 CPU 參與

  3. 內核從 ring buffer 中讀取報文進行處理,執(zhí)行 IP 和 TCP/UDP 層的邏輯,最后把報文放到應用程序的 socket buffer 中

  4. 應用程序從 socket buffer 中讀取報文進行處理

如何解決Linux系統UDP丟包問題?辦法都在這里!

在接收 UDP 報文的過程中,圖中任何一個過程都可能會主動或者被動地把報文丟棄,因此丟包可能發(fā)生在網卡和驅動,也可能發(fā)生在系統和應用。

之所以沒有分析發(fā)送數據流程,一是因為發(fā)送流程和接收類似,只是方向相反;另外發(fā)送流程報文丟失的概率比接收小,只有在應用程序發(fā)送的報文速率大于內核和網卡處理速率時才會發(fā)生。

本篇文章假定機器只有一個名字為 eth0 的 interface,如果有多個 interface 或者 interface 的名字不是 eth0,請按照實際情況進行分析。

NOTE:文中出現的 RX(receive) 表示接收報文,TX(transmit) 表示發(fā)送報文。

確認有 UDP 丟包發(fā)生


要查看網卡是否有丟包,可以使用 ethtool -S eth0 查看,在輸出中查找 bad 或者 drop 對應的字段是否有數據,在正常情況下,這些字段對應的數字應該都是 0。如果看到對應的數字在不斷增長,就說明網卡有丟包。

另外一個查看網卡丟包數據的命令是 ifconfig,它的輸出中會有 RX(receive 接收報文)和 TX(transmit 發(fā)送報文)的統計數據:

[root@k8s-master ng]# ifconfig enp1enp2s0f1: flags=4099<UP,BROADCAST,MULTICAST> mtu 1500 ether 04:b0:e7:fa:75:9d txqueuelen 1000 (Ethernet) RX packets 0 bytes 0 (0.0 B) RX errors 0 dropped 0 overruns 0 frame 0 TX packets 0 bytes 0 (0.0 B) TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0 device memory 0x92200000-922fffff


此外,linux 系統也提供了各個網絡協議的丟包信息,可以使用 netstat -s 命令查看,加上 --udp 可以只看 UDP 相關的報文數據:

[root@k8s-master ng]# netstat -s -uIcmpMsg: InType0: 17 InType3: 75 InType8: 77 OutType0: 77 OutType3: 692 OutType8: 249Udp: 5728807 packets received 12 packets to unknown port received. 0 packet receive errors 982710 packets sent 0 receive buffer errors 0 send buffer errorsUdpLite:IpExt: InNoRoutes: 3 InBcastPkts: 497633 InOctets: 1044710406807 OutOctets: 17460621991142 InBcastOctets: 114600482 InNoECTPkts: 2886955071


對于上面的輸出,關注下面的信息來查看 UDP 丟包的情況:

  • packet receive errors 不為空,并且在一直增長說明系統有 UDP 丟包

  • packets to unknown port received 表示系統接收到的 UDP 報文所在的目標端口沒有應用在監(jiān)聽,一般是服務沒有啟動導致的,并不會造成嚴重的問題

  • receive buffer errors 表示因為 UDP 的接收緩存太小導致丟包的數量

NOTE:并不是丟包數量不為零就有問題,對于 UDP 來說,如果有少量的丟包很可能是預期的行為,比如丟包率(丟包數量/接收報文數量)在萬分之一甚至更低。

網卡或者驅動丟包

之前講過,如果 ethtool -S eth0 中有 rx_***_errors 那么很可能是網卡有問題,導致系統丟包,需要聯系服務器或者網卡供應商進行處理。

[root@k8s-master ng]# ethtool -S enp1 | grep rx_ | grep errors rx_crc_errors: 0 rx_missed_errors: 0 rx_long_length_errors: 0 rx_short_length_errors: 0 rx_align_errors: 0 rx_errors: 0 rx_length_errors: 0 rx_over_errors: 0 rx_frame_errors: 0 rx_fifo_errors: 0


netstat -i 也會提供每個網卡的接發(fā)報文以及丟包的情況,正常情況下輸出中 error 或者 drop 應該為 0。

如果硬件或者驅動沒有問題,一般網卡丟包是因為設置的緩存區(qū)(ring buffer)太小,可以使用 ethtool 命令查看和設置網卡的 ring buffer。

ethtool -g 可以查看某個網卡的 ring buffer,比如下面的例子

[root@k8s-master ng]# ethtool -g enp1Ring parameters for enp2s0f1:Pre-set maximums:RX: 4096RX Mini: 0RX Jumbo: 0TX: 4096Current hardware settings:RX: 256RX Mini: 0RX Jumbo: 0TX: 256


Pre-set 表示網卡最大的 ring buffer 值,可以使用 ethtool -G eth0 rx 8192 設置它的值。

Linux 系統丟包

linux 系統丟包的原因很多,常見的有:UDP 報文錯誤、防火墻、UDP buffer size 不足、系統負載過高等,這里對這些丟包原因進行分析。

UDP 報文錯誤

如果在傳輸過程中UDP 報文被修改,會導致 checksum 錯誤,或者長度錯誤,linux 在接收到 UDP 報文時會對此進行校驗,一旦發(fā)明錯誤會把報文丟棄。

如果希望 UDP 報文 checksum 及時有錯也要發(fā)送給應用程序,可以在通過 socket 參數禁用 UDP checksum 檢查。

防火墻

如果系統防火墻丟包,表現的行為一般是所有的 UDP 報文都無法正常接收,當然不排除防火墻只 drop 一部分報文的可能性。

如果遇到丟包比率非常大的情況,請先檢查防火墻規(guī)則,保證防火墻沒有主動 drop UDP 報文。

UDP buffer size 不足

linux 系統在接收報文之后,會把報文保存到緩存區(qū)中。因為緩存區(qū)的大小是有限的,如果出現 UDP 報文過大(超過緩存區(qū)大小或者 MTU 大?。⒔邮盏綀笪牡乃俾侍?,都可能導致 linux 因為緩存滿而直接丟包的情況。

在系統層面,linux 設置了 receive buffer 可以配置的最大值,可以在下面的文件中查看,一般是 linux 在啟動的時候會根據內存大小設置一個初始值。

  • /proc/sys/net/core/rmem_max:允許設置的 receive buffer 最大值

  • /proc/sys/net/core/rmem_default:默認使用的 receive buffer 值

  • /proc/sys/net/core/wmem_max:允許設置的 send buffer 最大值

  • /proc/sys/net/core/wmem_dafault:默認使用的 send buffer 最大值

但是這些初始值并不是為了應對大流量的 UDP 報文,如果應用程序接收和發(fā)送 UDP 報文非常多,需要講這個值調大。可以使用 sysctl 命令讓它立即生效:

[root@k8s-master ~]# sysctl -w net.core.rmem_max=26214400 # 設置為 25Mnet.core.rmem_max = 26214400


也可以修改 /etc/sysctl.conf 中對應的參數在下次啟動時讓參數保持生效。

如果報文報文過大,可以在發(fā)送方對數據進行分割,保證每個報文的大小在 MTU 內。

另外一個可以配置的參數是 netdev_max_backlog,它表示 linux 內核從網卡驅動中讀取報文后可以緩存的報文數量,默認是 1000,可以調大這個值,比如設置成 2000:

[root@k8s-master ~]# sudo sysctl -w net.core.netdev_max_backlog=2000net.core.netdev_max_backlog = 2000[root@k8s-master ~]#



系統負載過高

系統 CPU、memory、IO 負載過高都有可能導致網絡丟包,比如 CPU 如果負載過高,系統沒有時間進行報文的 checksum 計算、復制內存等操作,從而導致網卡或者 socket buffer 出丟包;memory 負載過高,會應用程序處理過慢,無法及時處理報文;IO 負載過高,CPU 都用來響應 IO wait,沒有時間處理緩存中的 UDP 報文。

linux 系統本身就是相互關聯的系統,任何一個組件出現問題都有可能影響到其他組件的正常運行。對于系統負載過高,要么是應用程序有問題,要么是系統不足。對于前者需要及時發(fā)現,debug 和修復;對于后者,也要及時發(fā)現并擴容。

應用丟包

上面提到系統的 UDP buffer size,調節(jié)的 sysctl 參數只是系統允許的最大值,每個應用程序在創(chuàng)建 socket 時需要設置自己 socket buffer size 的值。

linux 系統會把接受到的報文放到 socket 的 buffer 中,應用程序從 buffer 中不斷地讀取報文。所以這里有兩個和應用有關的因素會影響是否會丟包:socket buffer size 大小以及應用程序讀取報文的速度。

對于第一個問題,可以在應用程序初始化 socket 的時候設置 socket receive buffer 的大小,比如下面的代碼把 socket buffer 設置為 20MB:

uint64_t receive_buf_size = 20*1024*1024; //20 MBsetsockopt(socket_fd, SOL_SOCKET, SO_RCVBUF, &receive_buf_size, sizeof(receive_buf_size));


如果不是自己編寫和維護的程序,修改應用代碼是件不好甚至不太可能的事情。很多應用程序會提供配置參數來調節(jié)這個值,請參考對應的官方文檔;如果沒有可用的配置參數,只能給程序的開發(fā)者提 issue 了。

很明顯,增加應用的 receive buffer 會減少丟包的可能性,但同時會導致應用使用更多的內存,所以需要謹慎使用。

另外一個因素是應用讀取 buffer 中報文的速度,對于應用程序來說,處理報文應該采取異步的方式

包丟在什么地方

想要詳細了解 linux 系統在執(zhí)行哪個函數時丟包的話,可以使用 dropwatch 工具,它監(jiān)聽系統丟包信息,并打印出丟包發(fā)生的函數地址:

# dropwatch -l kasInitalizing kallsyms dbdropwatch> startEnabling monitoring...Kernel monitoring activated.Issue Ctrl-C to stop monitoring
1 drops at tcp_v4_do_rcv+cd (0xffffffff81799bad)10 drops at tcp_v4_rcv+80 (0xffffffff8179a620)1 drops at sk_stream_kill_queues+57 (0xffffffff81729ca7)4 drops at unix_release_sock+20e (0xffffffff817dc94e)1 drops at igmp_rcv+e1 (0xffffffff817b4c41)1 drops at igmp_rcv+e1 (0xffffffff817b4c41)


通過這些信息,找到對應的內核代碼處,就能知道內核在哪個步驟中把報文丟棄,以及大致的丟包原因。本人在排查這個問題過程中更傾向于在各個機器抓包,這個方法更適合追蹤自身業(yè)務出現問題導致丟包,如下所示:


tcpdump -i 網絡接口名稱 udp port 2020 -s0 -XX -nn


此外,還可以使用 linux perf 工具監(jiān)聽 kfree_skb(把網絡報文丟棄時會調用該函數) 事件的發(fā)生:


sudo perf record -g -a -e skb:kfree_skbsudo perf script



關于 perf 命令的使用和解讀,網上有很多文章可以參考。



總結

  • UDP 本身就是無連接不可靠的協議,適用于報文偶爾丟失也不影響程序狀態(tài)的場景,比如視頻、音頻、游戲、監(jiān)控等。對報文可靠性要求比較高的應用不要使用 UDP,推薦直接使用 TCP。當然,也可以在應用層做重試、去重保證可靠性

  • 如果發(fā)現服務器丟包,首先通過監(jiān)控查看系統負載是否過高,先想辦法把負載降低再看丟包問題是否消失

  • 如果系統負載過高,UDP 丟包是沒有有效解決方案的。如果是應用異常導致 CPU、memory、IO 過高,請及時定位異常應用并修復;如果是資源不夠,監(jiān)控應該能及時發(fā)現并快速擴容

  • 對于系統大量接收或者發(fā)送 UDP 報文的,可以通過調節(jié)系統和程序的 socket buffer size 來降低丟包的概率

  • 應用程序在處理 UDP 報文時,要采用異步方式,在兩次接收報文之間不要有太多的處理邏輯

--END--


免責聲明:本文內容由21ic獲得授權后發(fā)布,版權歸原作者所有,本平臺僅提供信息存儲服務。文章僅代表作者個人觀點,不代表本平臺立場,如有問題,請聯系我們,謝謝!

21ic電子網

掃描二維碼,關注更多精彩內容

本站聲明: 本文章由作者或相關機構授權發(fā)布,目的在于傳遞更多信息,并不代表本站贊同其觀點,本站亦不保證或承諾內容真實性等。需要轉載請聯系該專欄作者,如若文章內容侵犯您的權益,請及時聯系本站刪除( 郵箱:macysun@21ic.com )。
換一批
延伸閱讀
關閉