Linux网络丢包排查 - 墨天轮

标签: | 发表时间:2022-10-27 14:56 | 作者:
出处:https://www.modb.pro


一、简介

工作中遇到的服务器,最常用的操作系统就是linux系统,linux 系统使用网络适配器和外部进行数据交换。当在高速链路或异常环境下进行网络通信时,就有可能出现网络数据丢包现象,接下来我主要要说的是:网路丢包的故障定位思路和解决方法。


二、相关原理介绍

1 、网络消息的收发(报文收发过程)

在说丢包故障定位之前,我先来了介绍“网络报文收发过程”。本文以接收报文为例,发送报文与之类似,只是报文的传输方向相反。

1、网络packet首先通过网线被网卡获取,网卡检查packet的crc正常后,去掉packet头得到frame,如果frame中MAC的目的地址为本机地址,则接受该报文,否则丢弃(在混杂模式下也会接收该报文)

2、网卡将frame拷贝到网卡内部缓冲区中,一般是网卡的ring buffer中,拷贝完成后触发软中断通知内核处理

3、内核从ring buffer中拷贝网络数据,并传递给网络协议栈进行解析

4、协议栈解析完成后将数据放入ocket套接字的buffer中,最终传递给上层应用

2 、相关名词解释

-

Bash代码

          enp125s0f0:flags=4163  mtu 1500      
    inet90.90.160.163 netmask 255.255.252.0 broadcast 90.90.163.255
    inet6fe80::903a:4e71:69cd:eb09 prefixlen 64 scopeid 0x20
    ether08:4f:0a:04:85:ac txqueuelen 1000 (Ethernet)
    RXpackets 28356 bytes 4397271 (4.1 MiB)
    RXerrors 0 dropped 15869 overruns 0 frame 0
    TXpackets 3003 bytes 450378 (439.8 KiB)
    TXerrors 0 dropped 0 overruns 0 carrier 0 collisions 0

    RX errors:表示总的收包的错误数量

    RX dropped:表示数据包已进入Ring buffer,但是由于系统原因(如内存不足)导致在拷贝到内存中的过程中被丢弃

    RX overruns:表示数据还未进入网卡缓存(Ring buffer)时就被丢弃了,一般是由于Ring buffer中的数据未被及时取出导致溢出,新来的数据只能被丢弃。例如CPU负载大,导致处理网卡数据的速度小于网卡接收数据的速度,Ring buffer溢出。

    RX frame:表示misaligend的frames数量

    三、丢包故障定位与解决

    1 、网卡丢包

    首先检查丢包是否是因为crc校验错误导致的:

    Bash代码

            [root@localhost ~]# ethtool -S enp1s0f0 | grep crc      
      rx_crc_errors_phy:0

      如果crc字段为非0,则表示网络报文在传输时出现了差错,此时可以更换线缆或网卡再做验证。

      如果丢包发生在网卡上,则可以通过ethtool -S eth0 | egrep-i drop|error确认

      Bash代码





              [root@localhost ~]# ethtool -S enp125s0f0 | egrep -ierror|drop      
        rxq#0_rx_dropped: 0
        rxq#0_errors: 0
        rx_oq_drop_pkt_cnt:0

        netstat -i也可以提供网卡的收发报文和丢包情况,正常情况下error、drop和overrun字段应该为0

        Bash代码

        如果RX_OVR一直在增加,说明Ringbuffer有溢出,除了Ring Buffer太小以外,有可能是CPU处于高负荷下,来不及从Ring buffer中获取数据,此时可以检查CPU高负荷的原因,对网卡进行中断亲和设置等操作。通过查看/proc/net/dev也可以查看是否有Ring buffer满而导致的丢包

        [root@localhost~]# netstat -i

                KernelInterface table      
          IfaceMTU RX-OK RX-ERR RX-DRP RX-OVR TX-OK TX-ERR TX-DRP TX-OVR Flg
          enp125s0f01500 29113 0 16149 0 3258 0 0 0 BMRU
          enp125s0f11500 0 0 0 0 0 0 0 0 BMU
          enp125s0f21500 0 0 0 0 0 0 0 0 BMU
          enp125s0f31500 0 0 0 0 0 0 0 0 BMRU
          enp1s0f01500 0 0 0 0 0 0 0 0 BMU




          enp1s0f11500 0 0 0 0 0 0 0 0 BMU
          lo65536 1820 0 0 0 1820 0 0 0 LRU

          如果硬件或者驱动没有问题,一般网卡丢包是由于Ring buffer太小导致,可以使用ethtool -G修改Ring buffer大小。

          Bash代码

                  [root@localhost~]# cat proc/net/dev      
            Inter-|Receive | Transmit

            face|bytes packets errs drop fifo frame compressed multicast|bytes packets errs drop fifo colls carrier compressed
            enp125s0f1:0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0




            enp125s0f3:0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
            enp125s0f2:0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
            enp1s0f1:0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
            enp1s0f0:0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
            lo:169176 1948 0 0 0 0 0 0 169176 1948 0 0 0 0 0 0
            enp125s0f0:4880071 32037 0 18238 0 0 0 40408 486664 3302 0 0 0 0 0 0


             

            2 、内核丢包其中的fifo字段统计的是Ringbuffer满而丢弃的包

            内核从网卡收到数据以后,交给协议栈处理之前会有缓冲队列backlog,每个CPU都有一个backlog队列,当从网卡中获取数据到backlog中的速率大于从backlog中将数据交给协议栈的速率时就会发生溢出。可以查看/proc/net/softnet_stat文件确认是否有backlog溢出:

            -

            Bash代码

             

                    [root@localhost~]# cat proc/net/softnet_stat      
              0000000300000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000
              0000000000000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000
              0000000000000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000
              0000000000000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000
              0000000000000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000
              0000000000000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000
              0000000000000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000
              • 每一行代表一个CPU core接收数据的情况

              • 第1列表示收到的包总数

              • 第2列是丢弃的包计数,此处的丢包指的是从网卡Ring buffer中输出到内核缓存队列时,由于队列满了而丢弃的数据包

              • 第3列表示软中断一次取走netdev_budget个数据包,或取数据包时间超过2ms的次数

              • 第4列~第8列固定为0,没有意义

              • 第9列表示发送数据包时,对应的队列被锁住的次数

              如果是因为backlog队列溢出导致的丢包,可以修改backlog队列的大小,通过systctl修改netdev maxbacklog参数,默认大小为1000

              -

              Bash代码

               sysctl -w net.core.netdev_max_backlog=2000    

              在将数据交给内核协议栈后,协议栈进行分析处理。在协议栈中也有可能丢包,通过netstat-s可以查看是否有协议栈丢包,-u参数指定udp协议,-t参数指定tcp协议,也可以加-c参数持续输出,看各个数据的变化,本文以UDP协议为例进行讲解

              -

              Bash代码

                      [root@localhost~]# netstat -s -u      
                IcmpMsg:
                InType3:1006
                OutType3:1006
                Udp:
                0packetsreceived
                1006packetsto unknown port received.
                0packetreceive errors
                1081packetssent
                0receivebuffer errors
                0sendbuffer errors
                UdpLite:
                IpExt:
                InMcastPkts:3245
                OutMcastPkts:11
                InBcastPkts:6213
                InOctets:2859135
                OutOctets:633832
                InMcastOctets:495247
                OutMcastOctets:2658
                InBcastOctets:2038580
                InNoECTPkts:13895
                [root@localhost~]#


                • packet receive errors表示接收有丢包

                • packets to unknown port received表示系统接收到的UDP报文的目标端口没有应用在监听,一般影响不严重

                • receive/send buffer errors表示收发队列太小导致的丢包数量

                对于收发队列太小导致的丢包,可以通过调整收发队列参数来解决,系统默认的receive/sendbuffer大小如下:

                -

                Bash代码

                        [root@localhost ~]# sysctlnet.core.rmem_default      
                  net.core.rmem_default =229376
                  [root@localhost ~]# sysctlnet.core.wmem_default
                  net.core.wmem_default =229376


                  可以使用以下命令修改buffer大小

                  -

                  Bash代码

                          sysctl-w net.core.rmem_max=26214400# 设置为 25M      
                    sysctl -w net.core.wmem_max=26214400# 设置为 25M


                    通过查看/proc/net/snmp文件也可以查看各个协议的收发包情况:

                    -

                    Bash代码

                            Ip: Forwarding DefaultTTL InReceives InHdrErrorsInAddrErrors ForwDatagrams InUnknownProtos InDiscards InDelivers OutRequestsOutDiscards OutNoRoutes ReasmTimeout ReasmReqds ReasmOKs ReasmFails FragOKsFragFails FragCreates      
                      Ip: 2 64 14757 0 28 0 0 0 4844 5745 512 0 0 0 0 0 0 00
                      Icmp: InMsgs InErrors InCsumErrors InDestUnreachsInTimeExcds InParmProbs InSrcQuenchs InRedirects InEchos InEchoRepsInTimestamps InTimestampReps InAddrMasks InAddrMaskReps OutMsgs OutErrorsOutDestUnreachs OutTimeExcds OutParmProbs OutSrcQuenchs OutRedirects OutEchosOutEchoReps OutTimestamps OutTimestampReps OutAddrMasks OutAddrMaskReps
                      Icmp: 1038 0 0 1038 0 0 0 0 0 0 0 0 0 0 1038 0 1038 00 0 0 0 0 0 0 0 0
                      IcmpMsg: InType3 OutType3
                      IcmpMsg: 1038 1038
                      Tcp: RtoAlgorithm RtoMin RtoMax MaxConn ActiveOpensPassiveOpens AttemptFails EstabResets CurrEstab InSegs OutSegs RetransSegsInErrs OutRsts InCsumErrors
                      Tcp: 1 200 120000 -1 0 2 0 0 2 2768 3592 0 0 0 0
                      Udp: InDatagrams NoPorts InErrors OutDatagramsRcvbufErrors SndbufErrors InCsumErrors IgnoredMulti
                      Udp: 0 1038 0 1113 0 0 0 0
                      UdpLite: InDatagrams NoPorts InErrors OutDatagramsRcvbufErrors SndbufErrors InCsumErrors IgnoredMulti
                      UdpLite: 0 0 0 0 0 0 0 0/


                      3 、应用丢包

                      内核协议栈把接收到的报文放到socket套接字的buffer中,应用程序从buffer中不断读取报文。所以这里有两个和应用程序有关的因素会影响丢包:socket buffer的大小和应用程序报文读取速度。

                      socket buffer大小可在应用程序初始化socket时设置,不过增大buffer的值会增加内存的使用,请根据实际情况配置;对于应用程序报文处理速度,应采用异步方式处理

                      四、其他定位方法

                      1 、dropwatch

                      dropwatch可以输出数据包是在哪个内核函数中丢失的:

                      -

                      Bash代码

                              [root@localhost~]# dropwatch -l kas      
                        Initalizingkallsyms db
                        dropwatch>start
                        Enablingmonitoring...
                        Kernelmonitoring activated.
                        IssueCtrl-C to stop monitoring
                        1drops at skb_queue_purge+20 (0xffff000008708d3c)
                        2drops at __netif_receive_skb_core+504(0xffff00000871bd7c)
                        1drops at __netif_receive_skb_core+504(0xffff00000871bd7c)


                         


                        相关 [linux 网络 丢包] 推荐:

                        Linux网络丢包排查 - 墨天轮

                        - -
                        工作中遇到的服务器,最常用的操作系统就是linux系统,linux 系统使用网络适配器和外部进行数据交换. 当在高速链路或异常环境下进行网络通信时,就有可能出现网络数据丢包现象,接下来我主要要说的是:网路丢包的故障定位思路和解决方法. 、网络消息的收发(报文收发过程). 在说丢包故障定位之前,我先来了介绍“网络报文收发过程”.

                        Android之网络丢包事件

                        - - 开源小站
                        有那么一个应用,同样的服务器端,同样的Wi-Fi网络下,Android连接速度总是慢过iphone一个数量级. 起先怀疑跟Android的硬件有关,无奈的是通过3G甚至于2G EDGE无线连接,速度均超过Wi-Fi. 然后这个责任就一把归结到了“Android不如iPhone”,“Android七拼八凑”之类无休止的平台沙文主义之上了.

                        Linux丢包故障的解决与思路 - Albert的博客 | Albert's Blog

                        - -
                        Linux丢包故障的解决与思路. 原文地址,和之前一样,在原文的基础上进行了一些格式的调整,包括一些错别字的修正,以及进行了一些博文链接的插入,以便于读者或者我自己更好的理解. Linux作为服务器操作系统时,为了达到高并发处理能力,充分利用机器性能,经常会进行一些内核参数的调整优化,但不合理的调整常常也会引起意想不到的其他问题,本文就一次.

                        Oracle 管理之 Linux 网络基础

                        - - CSDN博客数据库推荐文章
                        1、TCP/IP 网络配置文件. TCP/IP 网络配置文件. IP配置文件:/etc/sysconfig/network-scripts/ifcfg-eth0. 网管配置文件:/etc/sysconfig/network. 域名解析:/etc/host.conf. 主机配置:/etc/hosts.

                        dropwatch 网络协议栈丢包检查利器

                        - - 系统技术非业余研究
                        原创文章,转载请注明: 转载自 系统技术非业余研究. dropwatch 网络协议栈丢包检查利器. 在做网络服务器的时候,会碰到各种各样的网络问题比如说网络超时,通常一般的开发人员对于这种问题最常用的工具当然是tcpdump或者更先进的wireshark来进行抓包分析. 通常这个工具能解决大部分的问题,但是比如说wireshark发现丢包,那深层次的原因就很难解释了.

                        网络会议软件 Mikogo 发布 Linux 版

                        - Lambda - Wow! Ubuntu
                        免费网络会议及远程桌面控制软件 Mikogo 正式通告发布首个 Linux 平台上的 Beta 版本,完全原生的 Linux 程序. Mikogo 是一款与 TeamViewer 类似的远程控制及网络会议软件,来自德国,原先只能运行于 Windows 及 Mac 平台下. 其最大特点是体积非常小巧、可一次连接10人、传输效果好速度快,可限定共享的程序,并且能穿透局域网、防火墙.

                        Linux下网络抓包命令tcpdump详解(在wireshark中看包)

                        - - 开心平淡对待每一天。热爱生活
                        tcpdump采用命令行方式,它的命令格式为:.       tcpdump[ -adeflnNOpqStvx ] [ -c 数量 ] [ -F 文件名 ].           [ -i 网络接口 ] [ -r 文件名] [ -s snaplen ].           [ -T 类型 ] [ -w 文件名 ] [表达式 ]   .

                        用 NetHogs 监控 Linux 每个进程的网络情况

                        - - vpsee.com
                        有时候我们客户会发现服务器或 VPS 网络慢,进一步发现大量带宽被占用,一些客户到这里为止就不知道怎么办了. 能不能有简单办法找出哪个程序(或者进程)占用了流量呢. Linux 下提供了很多监控流量的小工具,比如 iftop, iptraf, ifstat, darkstat, bwm-ng, vnstat 等,今天介绍的 NetHogs 正是我们需要的工具,nethogs 可以监控每个进程的网络带宽占用情况,为我们进一步分析问题提供了帮助.

                        如何在Linux下统计高速网络中的流量?

                        - - 操作系统 - ITeye博客
                        如何在Linux下统计高速网络中的流量. 2014-01-22 11:04 彭秦进 . 在Linux中有很多的流量监控工具,它们可以监控、分类网络流量,以花哨的图形用户界面提供实时流量分析报告. 本文中我们介绍一种简单的Shell 脚本,它可以监控网络流量而且不依赖于缓慢的libpcap库. 2013云计算架构师峰会课程资料下载.

                        Linux上的基础网络设备详解

                        - - 博客园_知识库
                          网络虚拟化是 Cloud 中的一个重要部分. 作为基础知识,本文详细讲述 Linux 抽象出来的各种网络设备的原理、用法、数据流向. 您通过此文,能够知道如何使用 Linux 的基础网络设备进行配置以达到特定的目的,分析出 Linux 可能的网络故障原因.   Linux 抽象网络设备简介.   和磁盘设备类似,Linux 用户想要使用网络功能,不能通过直接操作硬件完成,而需要直接或间接的操作一个 Linux 为我们抽象出来的设备,既通用的 Linux 网络设备来完成.