原本是想收藏的。实在没找到收藏在哪儿。就记录下。

在开始之前,我们先用一张图解释linux接收网路报文的过程。

首先网路报文通过化学网线发送到网卡网路驱动程序会把网路中的报文读下来放在ringbuffer中,这个过程使用DMA(DirectMemoryAccess),不须要CPU参与内核从ringbuffer中读取报文进行处理linux公社,执行IP和TCP/UDP层的逻辑,最后把报文放在应用程序的socketbuffer中应用程序从socketbuffer中读取报文进行处理

在接收UDP报文的过程中,图中任何一个过程都可能会主动或则被动地把报文遗弃,因而丢包可能发生在网卡和驱动,也可能发生在系统和应用。

之所以没有剖析发送数据流程,一是由于发送流程和接收类似,只是方向相反;另外发送流程报文遗失的机率比接收小,只有在应用程序发送的报文速度小于内核和网卡处理速度时才能发生。

本篇文章假设机器只有一个名子为eth0的interface,倘若有多个interface或则interface的名子不是eth0,请根据实际情况进行剖析。

NOTE:文中出现的RX(receive)表示接收报文,TX(transmit)表示发送报文。

确认有UDP丢包发生

要查看网卡是否有丢包,可以使用ethtool-Seth0查看linux丢包,在输出中查找bad或则drop对应的数组是否有数据,在正常情况下,这种数组对应的数字应当都是0。假如见到对应的数字在不断下降,就说明网卡有丢包。

另外一个查看网卡丢包数据的是ifconfig,它的输出中会有RX(receive接收报文)和TX(transmit发送报文)的统计数据:

~# ifconfig eth0
...
        RX packets 3553389376  bytes 2599862532475 (2.3 TiB)
        RX errors 0  dropped 1353  overruns 0  frame 0
        TX packets 3479495131  bytes 3205366800850 (2.9 TiB)
        TX errors 0  dropped 0 overruns 0  carrier 0  collisions 0
...

据悉,linux系统也提供了各个网路合同的丢包信息,可以使用netstat-s查看,加上--udp可以只看UDP相关的报文数据:

[root@holodesk02 GOD]# netstat -s -u
IcmpMsg:
    InType0: 3
    InType3: 1719356
    InType8: 13
    InType11: 59
    OutType0: 13
    OutType3: 1737641
    OutType8: 10
    OutType11: 263
Udp:
    517488890 packets received
    2487375 packets to unknown port received.
    47533568 packet receive errors
    147264581 packets sent
    12851135 receive buffer errors
    0 send buffer errors
UdpLite:
IpExt:
    OutMcastPkts: 696
    InBcastPkts: 2373968
    InOctets: 4954097451540
    OutOctets: 5538322535160
    OutMcastOctets: 79632
    InBcastOctets: 934783053
    InNoECTPkts: 5584838675

对于前面的输出,关注下边的信息来查看UDP丢包的情况:

NOTE:并不是丢包数目不为零就有问题,对于UDP来说,假如有少量的丢包很可能是预期的行为,例如丢包率(丢包数目/接收报文数目)在万分之一甚至更低。

网卡或则驱动丢包

之前讲过,假如ethtool-Seth0中有rx_***_errors这么很可能是网卡有问题,致使系统丢包,须要联系服务器或则网卡供应商进行处理。

# ethtool -S eth0 | 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也会提供每位网卡的接发报文以及丢包的情况,正常情况下输出中error或则drop应当为0。

linux丢包_丢包率高有什么后果_丢包率100%是什么意思

假如硬件或则驱动没有问题,通常网卡丢包是由于设置的缓存区(ringbuffer)太小,可以使用ethtool查看和设置网卡的ringbuffer。

ethtool-g可以查看某个网卡的ringbuffer,例如下边的事例

# ethtool -g eth0
Ring parameters for eth0:
Pre-set maximums:
RX:        4096
RX Mini:    0
RX Jumbo:    0
TX:        4096
Current hardware settings:
RX:        256
RX Mini:    0
RX Jumbo:    0
TX:        256

Pre-set表示网卡最大的ringbuffer值,可以使用ethtool-Geth0rx8192设置它的值。

Linux系统丢包

linux系统丢包的诱因好多,常见的有:UDP报文错误、防火墙、UDPbuffersize不足、系统负载过低等,这儿对这种丢包缘由进行剖析。

UDP报文错误

假如在传输过程中UDP报文被更改,会造成checksum错误,或则宽度错误,linux在接收到UDP报文时会对此进行校准,一旦发明错误会把报文遗弃。

假如希望UDP报文checksum及时有错也要发送给应用程序,可以在通过socket参数禁用UDPchecksum检测:

int disable = 1;
setsockopt(sock_fd, SOL_SOCKET, SO_NO_CHECK, (void*)&disable, sizeof(disable)

防火墙

假如系统防火墙丢包,表现的行为通常是所有的UDP报文都未能正常接收,其实不排除防火墙只drop一部份报文的可能性。

假如遇见丢包百分比特别大的情况,请先检测防火墙规则,保证防火墙没有主动dropUDP报文。

UDPbuffersize不足

linux系统在接收报文以后,会把报文保存到缓存区中。由于缓存区的大小是有限的,假如出现UDP报文过大(超过缓存区大小或则MTU大小)、接收到报文的速度太快,都可能造成linux由于缓存满而直接丢包的情况。

在系统层面,linux设置了receivebuffer可以配置的最大值linux丢包,可以在下边的文件中查看,通常是linux在启动的时侯会依照显存大小设置一个初始值。

然而这种初始值并不是为了应对大流量的UDP报文,倘若应用程序接收和发送UDP报文特别多,须要讲这个值调大。可以使用sysctl命令让它立刻生效:

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

也可以更改/etc/sysctl.conf中对应的参数在上次启动时让参数保持生效。

假如报文报文过大,可以在发送方对数据进行分割,保证每位报文的大小在MTU内。

另外一个可以配置的参数是netdev_max_backlog,它表示linux内核从网卡驱动中读取报文后可以缓存的报文数目,默认是1000,可以调大这个值,例如设置成2000:

sudo sysctl -w net.core.netdev_max_backlog=2000

系统负载过低

系统CPU、memory、IO负载过低都有可能造成网路丢包,例如CPU假如负载过低,系统没有时间进行报文的checksum估算、复制显存等操作,进而造成网卡或则socketbuffer出丢包;memory负载过低,会应用程序处理过慢,难以及时处理报文;IO负载过低,CPU都拿来响应IOwait,没有时间处理缓存中的UDP报文。

linux系统本身就是互相关联的系统,任何一个组件出现问题都有可能影响到其他组件的正常运行。对于系统负载过低,要么是应用程序有问题,要么是系统不足。对于后者须要及时发觉,debug和修补;对于前者,也要及时发觉并扩容。

应用丢包

里面提及系统的UDPbuffersize红旗linux安装,调节的sysctl参数只是系统容许的最大值,每位应用程序在创建socket时须要设置自己socketbuffersize的值。

linux系统会把接受到的报文放在socket的buffer中,应用程序从buffer中不断地读取报文。所以这儿有两个和应用有关的诱因会影响是否会丢包:socketbuffersize大小以及应用程序读取报文的速率。

对于第一个问题,可以在应用程序初始化socket的时侯设置socketreceivebuffer的大小,例如下边的代码把socketbuffer设置为20MB:

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

丢包率100%是什么意思_linux丢包_丢包率高有什么后果

倘若不是自己编撰和维护的程序,更改应用代码是件不好甚至不太可能的事情。好多应用程序会提供配置参数来调节这个值,请参考对应的官方文档;若果没有可用的配置参数,只能给程序的开发者提issue了。

很显著,降低应用的receivebuffer会降低丢包的可能性,但同时会造成应用使用更多的显存,所以须要慎重使用。

另外一个诱因是应用读取buffer中报文的速率,对于应用程序来说,处理报文应当采取异步的方法

包丢在哪些地方

想要详尽了解linux系统在执行那个函数时丢包的话,可以使用dropwatch工具,它窃听系统丢包信息,并复印出丢包发生的函数地址:

# dropwatch -l kas
Initalizing kallsyms db
dropwatch> start
Enabling 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)

通过这种信息,找到对应的内核代码处,能够晓得内核在那个步骤中把报文遗弃,以及大致的丢包缘由。

据悉,还可以使用linuxperf工具窃听kfree_skb(把网路报文遗弃时会调用该函数)风波的发生:

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

关于perf命令的使用和剖析,网上有好多文章可以参考。

总结参考资料

本文原创地址://lrxjmw.cn/yztjslxtjswl.html编辑:刘遄,审核员:暂无