概述
在使用tcpdump等命令抓包时,如果有请求包,没有回复包,那么就可能是发生了丢包。丢包有很多种原因,下面分别介绍一下。
1.路由器或交换机问题
在数据包传输等过程中,会经过交换机,路由器,如果在这些设备上面有做过设置,就可能学习不到路由,导致网络无法访问。也可能链路中某个设备关机了,导致丢包。
2.防火墙拒绝
iptables/firewalld/selinux
检查报文是否有命中 iptables 规则:
iptables -t filter -nvL
iptables -t nat -nvL
iptables -t raw -nvL
iptables -t mangle -nvL
iptables-save
查看更新firewalld规则:
systemctl status firewalld.service
firewall-cmd --list-all
firewall-cmd --permanent --add/remove-port=999/tcp
firewall-cmd --zone=public --add-rich-rule 'rule family="ipv4" source address="10.45.2.35" accept'
firewall-cmd --reload
查看selinux状态:
getenforce
ecs安全组
检查ecs安全组出入方向的规则,看是否允许相关端口或ip。
硬件防火墙F5等
一般大型公司在出口还会有一个硬件防火墙F5,这里面也会有设定规则。
slb白名单
云上的应用出外网的话一般都是设置ingress为loadbalancer类型,再绑定一个公网slb。slb是可以设置白名单的,需要检查ip是否在白名单内。
3.MTU 不一致导致丢包
如果容器内网卡 MTU 和另一端宿主机内的网卡 MTU 不一致(通常是 CNI 插件问题),数据包就可能被截断导致一些数据丢失:
- 如果容器内的 MTU 更大,发出去的包如果超过 MTU 可能就被丢弃了。
- 如果容器内的 MTU 更小,进来的包如果超过 MTU 可能就被丢弃。
查看MTU 大小:
ip address show
ifconfig
4.PPS 限速丢包
一般在购买ecs时,会选择网卡带宽,如果超过阈值后就不保证能正常转发,可能就丢包了。
5.listen 了源 port_range 范围内的端口
查看内核和apiserver配置:
net.ipv4.ip_local_port_range=32768 60999
- --service-node-port-range=1-65535
当client发送请求时,选取其中的一个端口比如33000,而nodePort已经使用了33000端口,那么就会选取失败,导致丢包。
6.socket buffer 满导致丢包
查看buffer errors:
netstat -s | grep "buffer errors"
如果数量在持续增加,说明流量较大,socket buffer 不够用,需要调大下 buffer 容量:
net.ipv4.tcp_wmem = 4096 16384 4194304
net.ipv4.tcp_rmem = 4096 87380 6291456
net.ipv4.tcp_mem = 381462 508616 762924
net.core.rmem_default = 8388608
net.core.rmem_max = 26214400
net.core.wmem_max = 26214400
6.连接队列满导致丢包
对于 TCP 连接,三次握手建立连接,没建连成功前存储在半连接队列,建连成功但还没被应用层 accept 之前,存储在全连接队列。队列大小是有上限的,如果慢了就会丢包:
- 如果并发太高或机器负载过高,半连接队列可能会满,新来的 SYN 建连包会被丢包。
- 如果应用层 accept 连接过慢,会导致全连接队列堆积,满了就会丢包,通常是并发高、机器负载高或应用hang死等原因。
确认方法:
netstat -s | grep -E 'drop|overflow'
全连接队列可以观察 Rec-Q:
ss -lnt
调整队列大小:
net.ipv4.tcp_max_syn_backlog = 8096 # 调整半连接队列上限
net.core.somaxconn = 32768 # 调整全连接队列上限
7.源端口耗尽
当作为 client 发请求,或外部流量从 NodePort 进来时进行 SNAT,会从当前 netns 中选择一个端口作为源端口,端口范围由 net.ipv4.ip_local_port_range 这个内核参数决定,如果并发量大,就可能导致源端口耗尽,从而丢包。