文档章节

丢包问题研究

摩云飞
 摩云飞
发布于 2017/04/21 15:40
字数 2645
阅读 614
收藏 1

丢包问题研究

Linux服务器丢包故障的解决思路及引申的TCP/IP协议栈理论

Ring Buffer 溢出

从底向上来看 Linux 接收数据包的处理过程,首先是网卡驱动层。如下图所示,物理介质上的数据帧到达后,首先由 NIC(网络适配器)读取,写入设备内部缓冲区 Ring Buffer 中,再由中断处理程序触发 Softirq 从中消费,Ring Buffer 的大小因网卡设备而异。当网络数据包到达(生产)的速率快于内核处理(消费)的速率时,Ring Buffer 很快会被填满,新来的数据包将被丢弃。

linux-server-packet-fig

确认方法:

  • ethtool -S eth0|grep rx_fifo
  • cat /proc/net/dev

通过观察接收方向的 fifo 丢包数是否有增加来确定;

解决办法:如果发现服务器上某个网卡的 fifo 数持续增大,可以确认一下 CPU 中断是否分配均匀;也可以尝试增加 Ring Buffer 的大小;

  • 查看 eth0 网卡 Ring Buffer 最大值和当前设置
$ ethtool -g eth0
  • 修改网卡 eth0 接收与发送硬件缓存区大小
$ ethtool -G eth0 rx 4096 tx 4096

netdev_max_backlog 溢出

netdev_max_backlog 是内核从 NIC 收包后,交由协议栈(如IP、TCP)处理之前的缓冲队列。每个 CPU 核都有一个 backlog 队列,与 Ring Buffer 同理,当接收包的速率大于内核协议栈处理的速率时,CPU 的 backlog 队列不断增长,当达到设定的 netdev_max_backlog 值时,数据包将被丢弃。

确认方法:通过 cat /proc/net/softnet_stat 可以确定是否发生了 backlog 队列溢出;

[root@wg-esm-hc-1 ~]# cat /proc/net/softnet_stat
0002562c 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000
000851b8 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000
0007d457 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000
000111fb 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000
000278e5 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000
000351a9 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000
0001fcd4 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000
00046236 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000
00001209 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000
00000bb8 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000
00000701 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000
00000eb2 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000
000016d8 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000
00000d92 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000
00000a80 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000
00000ec3 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000
00022569 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000
000523aa 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000
0002f95c 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000
00059baa 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000
00061fec 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000
000549bf 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000
0009e672 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000
000a5f80 00000000 00000001 00000000 00000000 00000000 00000000 00000000 00000000 00000000
000005cc 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000
00000b1d 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000
00000a78 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000
00000a63 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000
0000079c 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000
000007ea 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000
00000641 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000
0000058e 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000
[root@wg-esm-hc-1 ~]#

每一行代表每个 CPU 核的状态统计,从 CPU0 依次往下; 每一列代表一个 CPU 核的各项统计:第一列代表中断处理程序收到的包总数;第二列代表由于 netdev_max_backlog 队列溢出而被丢弃的包总数。

解决办法:netdev_max_backlog 的默认值是 1000 ,在高速链路上,可能会出现上述第二列统计不为 0 的情况,可以通过修改内核参数 net.core.netdev_max_backlog 来解决:

Linux系统网卡中断瓶颈丢包的解决思路

现在机器硬件发展快,硬件价格逐步下降,使用到多核CPU多队列网卡越来越多。

当需要把比较好的硬件发挥到较高水平的时候,需要考虑网卡中断均衡的问题。

特别是还在使用 2.6.3x 版本及其以下的 Linux 内核时,机器的流量很容易造成网卡中断不均衡而产生丢包

问题表现(经验):

  • 千兆网卡,跑到 600Mbps 的时候出现机器丢包;
  • 万兆网卡,跑到 3Gbps 的时候出现丢包;
  • CPU 出现单核的 si 使用率基本 100% ;

如果问题原因是“CPU 出现单核的 si 使用率基本 100%”导致,则

  • 通过命令 cat /proc/interrupts | grep ethX 查看和指定接口相关的系统中断信息;
  • 通过均衡网卡的中断处理到多核上,充分利用多核的性能来解决该问题;
  • 通过手动配置 /proc/irq/{NUM}/smp_affinity 可以实现绑定中断号到某个核上面;
  • 关闭 irqbalance 服务,避免其干扰手动调整中断的 CPU 亲和值;

可用脚本:


用Wireshark解决疑难杂症

抓包的原理

我们常常使用 tcpdumpWireshark 进行抓包,其底层依赖于 libpcap(Windows 下为 winpcap),其抓包过程大致如下:

  1. 网卡加载初始化驱动;
  2. 报文通过网络到达网卡;
  3. DMA 将报文复制到内核内存(Ring Buffer)中;
  4. 复制完毕后,网卡产生硬中断通知系统;
  5. NAPI 处理内核报文;
  6. libpcap 将获取的原始报文复制一份;
  7. 使用设置的过滤器对报文进行过滤,并保存至缓存中;
  8. 应用程序(TcpdumpWireshark)读取缓存中的数据。

丢包原因

为什么会丢包呢?系统缓存是一个 ring buffer,用来缓冲消息提高可靠性。当 buffer 满时,最新的数据会自动覆盖最老的数据,导致数据报文丢失。

解决方法

可以从三个方面着手去降低丢包的可能性:

  1. 根据策略对报文进行负载均衡,降低单台服务器报文数量;
  2. 提高报文处理速度,如 ring0 数据直接映射到 ring3 ,绑定 CPU 与终端等;
  3. 增大缓存的大小;

在实际情况中,我们常用的做法是 2 与 3 。

提高报文处理速度

推荐使用 PF_RING ,它通过优化 buffer 和 CPU 提高处理效率。

在抓包方案选择上,建议是根据流量大小选择不同的抓包方式:

  • 50Mbps 以下,使用原生的 tcpdump 抓包;
  • 50~1000Mbps 之内,使用加载了 PF_RING 驱动的 tcpdump 进行抓包;
  • 1Gbps 以上,推荐旁路抓包,使用 PF_RING ZC 驱动代替原有网卡驱动,再使用加载了 PF_RING 驱动的 tcpdump 抓包;

提高缓存大小

  • 调整网卡驱动的 Ring Buffer :
ethtool -g p5p1  // 查看
ethtool -G p5p1 rx 4096  // 设置
  • 设置 tcpdump 缓存
tcpdump  -B // 设置 buffer size

网络分析技术之葵花宝典

看一下 tcpdump 程序调用模型:

tcpdump程序调用模型

可见,tcpdump 和一般的网络程序完全不同,它依赖的是 libpcap ,而 libpcap 使用的是一种称为**设备层的包接口(packet interface on device level)**的技术。使用这种技术,应用程序可以直接读写内核驱动层面的数据,而不经过完整的 Linux 网络协议栈。

tcpdump 与 iptables 的关系

可能会有疑问,如果一种输入的网络通信(INPUT)被 iptables 给禁止了,那么 tcpdump 还可以抓取到吗?

答案是肯定的。

  • tcpdump 直接从网络驱动层面抓取输入的数据,不经过任何 Linux 网络协议栈。
  • iptables 依赖 netfilter 模块,后者工作在 Linux 网络协议栈中;

因此:

  • iptables 的入栈的策略不会影响到 tcpdump 抓取;
  • iptables 的出栈策略会影响数据包发送到网络驱动层面,因此,出栈策略会影响到 tcpdump 的抓取;

tcpdump 和 iptables 的关系,总结下来就是:

  • tcpdump 可以抓取到被 iptables 在 INPUT 链上 DROP 掉的数据包;
  • tcpdump 不能抓取到被 iptables 在 OUTPUT 链上 DROP 掉的数据包;

丢包原因汇总

在高速复杂网络环境下,可能导致丢包的各种原因:

  • NAPI 之前的 Linux NIC 驱动总是在接收到数据包后立即触发中断进行处理,故 Cpu 处于频繁中断状态,造成接收数据包效率低下;
  • 基于传统 Linux 内核网络协议栈,数据包的处理会经过两次拷贝(polling),从网卡驱动到内核,再从内核到用户空间,浪费了大量时间和资源。
  • 机器的流量很容易造成网卡中断不均衡而产生丢包;当网卡中断全部打在一个核上时,会造成单核处理网卡中断的情况,当该单核达到瓶颈后(top 的 si 指标)就会开始丢包;
  • pcap_next occasionally losing packets on Linux
  • 数据包节流 (Packet throttling),NAPI 之前的 Linux NIC 驱动总是在接收到数据包之后产生一个 IRQ ,接着在中断服务例程里将这个 skb 加入本地的 softnet ,然后触发本地 NET_RX_SOFTIRQ 软中断后续处理。如果包速过高,因为 IRQ 的优先级高于 SoftIRQ ,导致系统的大部分资源都在响应中断,但 softnet 的队列大小有限,接收到的超额数据包也只能丢掉,所以这时这个模型是在用宝贵的系统资源做无用功。而 NAPI 则在这样的情况下,直接把包丢掉,不会继续将需要丢掉的数据包扔给内核去处理,这样,网卡将需要丢掉的数据包尽可能的早丢弃掉,内核将不可见需要丢掉的数据包,这样也减少了内核的压力。
  • NIC Ring Buffer 溢出(rx_fifo);
  • per-CPU backlog queue(softnet)溢出(netdev_max_backlog);
  • tcpdump 缓存溢出;

经验汇总

  • Vanilla Linux 处理速度仅能达到约 1M pps
  • 现代 10Gbps 网卡的处理能力通常能够达到至少 10M pps
  • (经验值)千兆网卡,跑到 600Mbps 的时候出现机器丢包;
  • (经验值)万兆网卡,跑到 3Gbps 的时候出现丢包;
  • (经验值)CPU 出现单核的 si 使用率基本 100% ;
  • 通常的做法是:将网络流量通过交换机旁路镜像的方式送到服务器,然后在服务器上基于 tcpdump 方式进行抓包,后续再通过 tcpdump 进行过滤查找;但这种方式在流量特别大的时候也会遇到一些问题;
  • 流量在 50Mbps 以下,使用原生的 tcpdump 抓包;
  • 流量在 50~1000Mbps 之内,使用加载了 PF_RING 驱动的 tcpdump 进行抓包;
  • 流量在 1Gbps 以上,推荐旁路抓包,使用 PF_RING ZC 驱动代替原有网卡驱动,再使用加载了 PF_RING 驱动的 tcpdump 抓包;

© 著作权归作者所有

共有 人打赏支持
摩云飞
粉丝 370
博文 534
码字总数 952694
作品 0
徐汇
程序员
私信 提问
记一次webservice使用java连接的basic验证问题的坑

我们做了一个通用型的api平台,给全公司的接口使用。很多接口陆陆续续接入了,还面临一个问题,就是目前的代码对使用basic验证的webservice接口无法验证身份。拥有这方面需求的业务开发团队对...

checkboxMan
2018/12/24
0
0
django 实现web接口 python3模拟Post请求

作为抛砖引玉,用python3实现百度云语音解析,首先需要模拟Post请求把音频压缩文件丢给百度解析。 但是遇到一个问题客户端怎麽丢数据都是返回错误,后来在本地用django搭建了一个接口模拟一下...

xh21bao
2017/04/25
0
0
基于RTMP的实时流媒体的QoE分析

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/leixiaohua1020/article/details/14452171 Holly French等人在论文《Real Time Video QoE Analysis of RTMP ...

雷霄骅
2013/11/11
0
0
STM32串口如何代码实现更高效的接收消息

这段时间一直在研究多旋翼飞行器,以及其它的事情,博客好外没更新,再不坚持怕真荒废了哦。 在上篇简单实现MAVLink协议的解析,并演示按照设计好的命令执行对应的事件处理,以及又加入 CRC校...

OceanStack
2014/12/03
0
1
modbus通信丢包如何处理?

近排研究利用VB编写程序通过modbus协议,读取硬件设备的数据,但是通信过程中,发现有时数据会出现跳动,一闪而过,然后数据变为0,然后立刻变回正常值。这个应是通信丢包吧,怎么处理这种情...

OSC首席过客
2012/02/16
1K
4

没有更多内容

加载失败,请刷新页面

加载更多

【结构型】- 享元模式

享元模式 作用:利用共享技术有效地支持大量细粒度对象的复用 享元模式状态 内部状态:在享元对象内部不随外界环境改变而改变的共享部分,存储于享元对象内部 外部状态:随着环境的改变而改变...

ZeroneLove
昨天
1
0
Vue 中使用UEditor富文本编辑器-亲测可用-vue-ueditor-wrap

一、Vue中在使用Vue CLI开发中默认没法使用UEditor 其中UEditor中也存在不少错误,再引用过程中。 但是UEditor相对还是比较好用的一个富文本编辑器。 vue-ueditor-wrap说明 Vue + UEditor + ...

tianma3798
昨天
4
0
php-fpm配置

php-fpm配置 修改bbs.wangzb.cc.conf配置文件,将端口9000改为9001,重新访问网站是失败的 修改配置文件 # vim /etc/nginx/conf.d/bbs.wangzb.cc.conf# nginx -s reloadfastcgi_pass 1...

wzb88
昨天
2
0
配置方案:Redis持久化RDB和AOF

Redis持久化方案 Redis是内存数据库,数据都是存储在内存中,为了避免进程退出导致数据的永久丢失,需要定期将Redis中的数据以某种形式(数据或命令)从内存保存到硬盘。当下次Redis重启时,...

linuxprobe16
昨天
6
0
介绍NoSQL最受欢迎的产品

MongoDB MongoDB是一个基于分布式文件存储的数据库。由C++语言编写。主要解决的是海量数据的访问效率问题,为WEB应用提供可扩展的高性能数据存储解决方案。当数据量达到50GB以上的时候,Mon...

问题终结者
昨天
9
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部