网卡驱动丢包
查看:ifconfig eth1/eth0 等接口
1.RX errors: 表示总的收包的错误数量,还包括too-long-frames错误,Ring Buffer 溢出错误,crc 校验错误,帧同步错误,fifo overruns 以及 missed pkg 等等。
2.RX dropped: 表示数据包已经进入了 Ring Buffer,但是由于内存不够等系统原因,导致在拷贝到内存的过程中被丢弃。
3.RX overruns: 表示了 fifo 的 overruns,这是由于 Ring Buffer(aka Driver Queue) 传输的 IO 大于 kernel 能够处理的 IO 导致的,而 Ring Buffer 则是指在发起 IRQ 请求之前的那块 buffer。很明显,overruns 的增大意味着数据包没到 Ring Buffer 就被网卡物理层给丢弃了,而 CPU 无法即使的处理中断是造成 Ring Buffer 满的原因之一,上面那台有问题的机器就是因为 interruprs 分布的不均匀(都压在 core0),没有做 affinity 而造成的丢包。
4. RX frame: 表示 misaligned 的 frames。
5. 对于 TX 的来说,出现上述 counter 增大的原因主要包括 aborted transmission, errors due to carrirer, fifo error, heartbeat erros 以及 windown error,而 collisions 则表示由于 CSMA/CD 造成的传输中断。
驱动溢出丢包
etdev_max_backlog是内核从NIC收到包后,交由协议栈(如IP、TCP)处理之前的缓冲队列。每个CPU核都有一个backlog队列,与Ring Buffer同理,当接收包的速率大于内核协议栈处理的速率时,CPU的backlog队列不断增长,当达到设定的netdev_max_backlog值时,数据包将被丢弃。
通过查看/proc/net/softnet_stat可以确定是否发生了netdev backlog队列溢出:
其中:每一行代表每个CPU核的状态统计,从CPU0依次往下;每一列代表一个CPU核的各项统计:第一列代表中断处理程序收到的包总数;第二列即代表由于netdev_max_backlog队列溢出而被丢弃的包总数。从上面的输出可以看出,这台服务器统计中,并没有因为netdev_max_backlog导致的丢包。
解决方案:
netdev_max_backlog的默认值是1000,在高速链路上,可能会出现上述第二统计不为0的情况,可以通过修改内核参数net.core.netdev_max_backlog来解决:
$ sysctl -w net.core.netdev_max_backlog=2000
单核负载高导致丢包
单核CPU软中断占有高, 导致应用没有机会收发或者收包比较慢,即使调整netdev_max_backlog队列大小仍然会一段时间后丢包,处理速度跟不上网卡接收的速度;
查看:mpstat -P ALL 1
单核软中断占有100%,导致应用没有机会收发或者收包比较慢而丢包;
解决方案 :
1.调整网卡RSS队列配置:
查看:ethtool -x ethx;
调整:ethtool -X ethx xxxx;
2.看一下网卡中断配置是否均衡 cat /proc/interrupts
调整:
1) irqbalance 调整;
# 查看当前运行情况
service irqbalance status
# 终止服务
service irqbalance stop
2) 中断绑CPU核 echo mask > /proc/irq/xxx/smp_affinity
3.根据CPU和网卡队列个数调整网卡多队列和RPS配置
-CPU大于网卡队列个数:
查看网卡队列 ethtool -x ethx;
协议栈开启RPS并设置RPS;
echo $mask(CPU配置)> /sys/class/net/$eth/queues/rx-$i/rps_cpus
echo 4096(网卡buff)> /sys/class/net/$eth/queues/rx-$i/rps_flow_cnt
2)CPU小于网卡队列个数,绑中断就可以,可以试着关闭RPS看一下效果:
echo 0 > /sys/class/net/<dev>/queues/rx-<n>/rps_cpus
4.numa CPU调整,对齐网卡位置,可以提高内核处理速度,从而给更多CPU给应用收包,减缓丢包概率;
查看网卡numa位置:
ethtool -i eth1|grep bus-info
lspci -s bus-info -vv|grep node
上面中断和RPS设置里面mask需要重新按numa CPU分配重新设置;
5.可以试着开启中断聚合(看网卡是否支持)
查看 :
ethtool -c ethx
Coalesce parameters for eth1:
Adaptive RX: on TX: on
stats-block-usecs: 0
sample-interval: 0
pkt-rate-low: 0
pkt-rate-high: 0
rx-usecs: 25
rx-frames: 0
rx-usecs-irq: 0
rx-frames-irq: 256
tx-usecs: 25
tx-frames: 0
tx-usecs-irq: 0
tx-frames-irq: 256
rx-usecs-low: 0
rx-frame-low: 0
tx-usecs-low: 0
tx-frame-low: 0
rx-usecs-high: 0
rx-frame-high: 0
tx-usecs-high: 0
tx-frame-high: 0
调整:
ethtool -C ethx adaptive-rx on
内核协议栈丢包
以太网链路层丢包
neighbor系统arp丢包
arp_ignore配置丢包
arp_ignore参数的作用是控制系统在收到外部的arp请求时,是否要返回arp响应。arp_ignore参数常用的取值主要有0,1,2,3~8较少用到;
查看:sysctl -a|grep arp_ignore
解决方案 :根据实际场景设置对应值;
0:响应任意网卡上接收到的对本机IP地址的arp请求(包括环回网卡上的地址),而不管该目的IP是否在接收网卡上。
1:只响应目的IP地址为接收网卡上的本地地址的arp请求。
2:只响应目的IP地址为接收网卡上的本地地址的arp请求,并且arp请求的源IP必须和接收网卡同网段。
3:如果ARP请求数据包所请求的IP地址对应的本地地址其作用域(scope)为主机(host),则不回应ARP响应数据包,如果作用域为全局(global)或链路(link),则回应ARP响应数据包。
arp_filter配置丢包
在多接口系统里面,这些接口都可以回应arp请求,导致对端有可能学到不同的mac地址,后续报文发送可能由于mac地址和接收报文接口mac地址不一样而导致丢包,arp_filter主要是用来适配这种场景;
查看:
sysctl -a | grep arp_filter
解决方案:
根据实际场景设置对应的值,一般默认是关掉此过滤规则,特殊情况可以打开;
0:默认值,表示回应arp请求的时候不检查接口情况;
1:表示回应arp请求时会检查接口是否和接收请求接口一致,不一致就不回应;
arp表满导致丢包
比如下面这种情况,由于突发arp表项很多 超过协议栈默认配置,发送报文的时候部分arp创建失败,导致发送失败,从而丢包:
查看:
- 查看arp状态:cat /proc/net/stat/arp_cache ,table_fulls统计:
- 查看dmesg消息(内核打印):
dmesg|grep neighbour
neighbour: arp_cache: neighbor table overflow!
- 查看当前arp表大小:ip n|wc -l
查看系统配额:
sysctl -a |grep net.ipv4.neigh.default.gc_thresh
gc_thresh1:存在于ARP高速缓存中的最少层数,如果少于这个数,垃圾收集器将不会运行。缺省值是128。
gc_thresh2 :保存在 ARP 高速缓存中的最多的记录软限制。垃圾收集器在开始收集前,允许记录数超过这个数字 5 秒。缺省值是 512。
gc_thresh3 :保存在 ARP 高速缓存中的最多记录的硬限制,一旦高速缓存中的数目高于此,垃圾收集器将马上运行。缺
一般在内存足够情况下,可以认为gc_thresh3 值是arp 表总大小;
解决方案 :根据实际arp最大值情况(比如访问其他子机最大个数),调整arp表大小
$ sudo sysctl -w net.ipv4.neigh.default.gc_thresh1=1024
$ sudo sysctl -w net.ipv4.neigh.default.gc_thresh2=2048
$ sudo sysctl -w net.ipv4.neigh.default.gc_thresh3=4096
$ sudo sysctl -p
arp请求缓存队列溢出丢包
查看:
cat /proc/net/stat/arp_cache ,unresolved_discards是否有新增计数
解决方案:根据客户需求调整缓存队列大小unres_qlen_bytes: