网站首页 > 技术文章 正文
目录
iptables
iptables 的原理
iptables -nvL 查看iptables配置
hping3模拟访问
检查端口状态
tcpdump
TCP 交互的流程图
为什么刚才用 hping3 时不丢包,现在换成 GET 就收不到了呢?
再次执行curl命令
上一节,我们一起学习了如何分析网络丢包的问题,特别是从链路层、网络层以及传输层等主要的协议栈中进行分析。
不过,通过前面这几层的分析,我们还是没有找出最终的性能瓶颈。看来,还是要继续深挖才可以。今天,我们就来继续分析这个未果的案例。
在开始下面的内容前,你可以先回忆一下上节课的内容,并且自己动脑想一想,除了我们提到的链路层、网络层以及传输层之外,还有哪些潜在问题可能会导致丢包呢?
iptables
首先我们要知道,除了网络层和传输层的各种协议,iptables 和内核的连接跟踪机制也可能会导致丢包。所以,这也是发生丢包问题时,我们必须要排查的一个因素。
我们先来看看连接跟踪,我已经在 如何优化 NAT 性能 文章中,给你讲过连接跟踪的优化思路。要确认是不是连接跟踪导致的问题,其实只需要对比当前的连接跟踪数和最大连接跟踪数即可。
不过,由于连接跟踪在 Linux 内核中是全局的(不属于网络命名空间),我们需要退出容器终端,回到主机中来查看。
你可以在容器终端中,执行 exit ;然后执行下面的命令,查看连接跟踪数:
root@nginx:/# exit
exit
You have mail in /var/spool/mail/root
[root@hadoop100 /usr/local/src/sysstat-11.5.5]#
[root@hadoop100 /usr/local/src/sysstat-11.5.5]#sysctl net.netfilter.nf_conntrack_max
net.netfilter.nf_conntrack_max = 10485760
[root@hadoop100 /usr/local/src/sysstat-11.5.5]#sysctl net.netfilter.nf_conntrack_count
net.netfilter.nf_conntrack_count = 19
连接跟踪数只有 19,而最大连接跟踪数则是 10485760。显然,这里的丢包,不可能是连接跟踪导致的。
接着,再来看 iptables。
iptables 的原理
它基于 Netfilter 框架,通过一系列的规则,对网络数据包进行过滤(如防火墙)和修改(如 NAT)。
这些 iptables 规则,统一管理在一系列的表中,
- 包括 filter(用于过滤)
- nat(用于 NAT)
- mangle(用于修改分组数据)
- raw(用于原始数据包)等。
而每张表又可以包括一系列的链,用于对 iptables 规则进行分组管理。
对于丢包问题来说,最大的可能就是被 filter 表中的规则给丢弃了。要弄清楚这一点,就需要我们确认,那些目标为 DROP 和 REJECT 等会弃包的规则,有没有被执行到。
你可以把所有的 iptables 规则列出来,根据收发包的特点,跟 iptables 规则进行匹配。不过显然,如果 iptables 规则比较多,这样做的效率就会很低。
当然,更简单的方法,就是直接查询 DROP 和 REJECT 等规则的统计信息,看看是否为 0。如果统计值不是 0 ,再把相关的规则拎出来进行分析。
iptables -nvL 查看iptables配置
我们可以通过 iptables -nvL 命令,查看各条规则的统计信息。比如,你可以执行下面的 docker exec 命令,进入容器终端;然后再执行下面的 iptables 命令,就可以看到 filter 表的统计数据了:
[root@hadoop100 /usr/local/src/sysstat-11.5.5]#docker exec -it nginx bash
root@nginx:/#
root@nginx:/# iptables -t filter -nvL
Chain INPUT (policy ACCEPT 42 packets, 1680 bytes)
pkts bytes target prot opt in out source destination
19 760 DROP all -- * * 0.0.0.0/0 0.0.0.0/0 statistic mode random probability 0.29999999981
Chain FORWARD (policy ACCEPT 0 packets, 0 bytes)
pkts bytes target prot opt in out source destination
Chain OUTPUT (policy ACCEPT 27 packets, 1188 bytes)
pkts bytes target prot opt in out source destination
10 440 DROP all -- * * 0.0.0.0/0 0.0.0.0/0 statistic mode random probability 0.29999999981
root@nginx:/#
从 iptables 的输出中,你可以看到,两条 DROP 规则的统计数值不是 0,它们分别在 INPUT 和 OUTPUT 链中。这两条规则实际上是一样的,指的是使用 statistic 模块,进行随机 30% 的丢包。
再观察一下它们的匹配规则。0.0.0.0/0 表示匹配所有的源 IP 和目的 IP,也就是会对所有包都进行随机 30% 的丢包。看起来,这应该就是导致部分丢包的“罪魁祸首”了。
既然找出了原因,接下来的优化就比较简单了。比如,把这两条规则直接删除就可以了。我们可以在容器终端中,执行下面的两条 iptables 命令,删除这两条 DROP 规则:
root@nginx:/# iptables -t filter -D INPUT -m statistic --mode random --probability 0.30 -j DROP
root@nginx:/# iptables -t filter -D OUTPUT -m statistic --mode random --probability 0.30 -j DROP
hping3模拟访问
?
这次输出你可以看到,现在已经没有丢包了,并且延迟的波动变化也很小。看来,丢包问题应该已经解决了。
检查端口状态
到目前为止,我们一直使用的 hping3 工具,只能验证案例 Nginx 的 80 端口处于正常监听状态,却还没有访问 Nginx 的 HTTP 服务。所以,不要匆忙下结论结束这次优化,我们还需要进一步确认,Nginx 能不能正常响应 HTTP 请求。
curl 命令,检查 Nginx 对 HTTP 请求的响应:
[root@hadoop101 yum.repos.d]# curl --max-time 3 http://192.168.56.10
curl: (28) Operation timed out after 3001 milliseconds with 0 out of -1 bytes received
[root@hadoop101 yum.repos.d]#
从 curl 的输出中,你可以发现,这次连接超时了。可是,刚才我们明明用 hping3 验证了端口正常,现在却发现 HTTP 连接超时,是不是因为 Nginx 突然异常退出了呢?
不妨再次运行 hping3 来确认一下:
$ hping3 -c 3 -S -p 80 192.168.0.30
HPING 192.168.0.30 (eth0 192.168.0.30): S set, 40 headers + 0 data bytes
len=44 ip=192.168.0.30 ttl=63 DF id=0 sport=80 flags=SA seq=0 win=5120 rtt=7.8 ms
len=44 ip=192.168.0.30 ttl=63 DF id=0 sport=80 flags=SA seq=1 win=5120 rtt=7.7 ms
len=44 ip=192.168.0.30 ttl=63 DF id=0 sport=80 flags=SA seq=2 win=5120 rtt=3.6 ms
--- 192.168.0.30 hping statistic ---
3 packets transmitted, 3 packets received, 0% packet loss
round-trip min/avg/max = 3.6/6.4/7.8 ms
奇怪,hping3 的结果显示,Nginx 的 80 端口确确实实还是正常状态。这该如何是好呢?别忘了,我们还有个大杀器——抓包操作。看来有必要抓包看看了。
tcpdump
接下来,我们切换回终端一,在容器终端中,执行下面的 tcpdump 命令,抓取 80 端口的包:
root@nginx:/# tcpdump -i eth0 -nn port 80
tcpdump: verbose output suppressed, use -v or -vv for full protocol decode
listening on eth0, link-type EN10MB (Ethernet), capture size 262144 bytes
07:31:12.317183 IP 192.168.56.11.49184 > 172.17.0.2.80: Flags [S], seq 1611768987, win 29200, options [mss 1460,sackOK,TS val 1229349728 ecr 0,nop,wscale 7], length 0
07:31:12.317224 IP 172.17.0.2.80 > 192.168.56.11.49184: Flags [S.], seq 1676587755, ack 1611768988, win 4880, options [mss 256,sackOK,TS val 1217733337 ecr 1229349728,nop,wscale 7], length 0
07:31:12.317536 IP 192.168.56.11.49184 > 172.17.0.2.80: Flags [.], ack 1, win 229, options [nop,nop,TS val 1229349728 ecr 1217733337], length 0
07:31:15.316612 IP 192.168.56.11.49184 > 172.17.0.2.80: Flags [F.], seq 78, ack 1, win 229, options [nop,nop,TS val 1229352729 ecr 1217733337], length 0
07:31:15.316753 IP 172.17.0.2.80 > 192.168.56.11.49184: Flags [.], ack 1, win 40, options [nop,nop,TS val 1217736336 ecr 1229349728,nop,nop,sack 1 {78:79}], length 0
经过这么一系列的操作,从 tcpdump 的输出中,我们就可以看到:
- 前三个包是正常的 TCP 三次握手,这没问题;
- 但第四个包却是在 3 秒以后了,并且还是客户端(VM2)发送过来的 FIN 包,也就说明,客户端的连接关闭了。
我想,根据 curl 设置的 3 秒超时选项,你应该能猜到,这是因为 curl 命令超时后退出了。
也可以把tcpdump的包保存下来,在wireshark中个分析
1、容器中 root@nginx:/# tcpdump -i eth0 -nn port 80 -w nginx48.pcap
2、容器外 [root@hadoop100 /usr/local/src/sysstat-11.5.5]#docker cp nginx:/nginx48.pcap /tmp
TCP 交互的流程图
?
这里比较奇怪的是,我们并没有抓取到 curl 发来的 HTTP GET 请求。那么,究竟是网卡丢包了,还是客户端压根儿就没发过来呢?
我们可以重新执行 netstat -i 命令,确认一下网卡有没有丢包问题:
root@nginx:/# netstat -i
Kernel Interface table
Iface MTU RX-OK RX-ERR RX-DRP RX-OVR TX-OK TX-ERR TX-DRP TX-OVR Flg
eth0 100 122 0 84 0 60 0 0 0 BMRU
lo 65536 0 0 0 0 0 0 0 0 LRU
从 netstat 的输出中,你可以看到,接收丢包数(RX-DRP)是 84,果然是在网卡接收时丢包了。不过问题也来了
为什么刚才用 hping3 时不丢包,现在换成 GET 就收不到了呢?
不妨先去查查工具和方法的原理。我们可以对比一下这两个工具:
- hping3 实际上只发送了 SYN 包;(-S 选项)
- 而 curl 在发送 SYN 包后,还会发送 HTTP GET 请求。
HTTP GET ,本质上也是一个 TCP 包,但跟 SYN 包相比,它还携带了 HTTP GET 的数据。(1、这个包是多大呢?ifconfig可以看;2、怎么看是否允许拆包呢?)
那么,通过这个对比,你应该想到了,这可能是 MTU 配置错误导致的。为什么呢?
其实,仔细观察上面 netstat 的输出界面,第二列正是每个网卡的 MTU 值。eth0 的 MTU 只有 100,而以太网的 MTU 默认值是 1500,这个 100 就显得太小了。
当然,MTU 问题是很好解决的,把它改成 1500 就可以了。我们继续在容器终端中,执行下面的命令,把容器 eth0 的 MTU 改成 1500:
?
再次执行curl命令
?
?
猜你喜欢
- 2024-10-23 微软发布6月Win11累积更新KB5039212/KB5039213
- 2024-10-23 快速体验之《gor+diffy实现线上流量复制到测试环境》
- 2024-10-23 Colbie Caillat: Try(colbiecaillattry歌词)
- 2024-10-23 基于阿里云 ASK 的 Istio 微服务应用部署初探
- 2024-10-23 浅谈ElasticSearch 集群部署(elastic集群配置)
- 2024-10-23 Python项目中跟踪系统导入Zipkin(基于python的目标跟踪算法)
- 2024-10-23 JVM参数及调优(jvm调优常用参数)
- 2024-10-23 Elasticsearch的路由routing的应用技巧
- 2024-10-23 如何将Elasticsearch的快照备份至OSS
- 2024-10-23 利用工具curl来查看http请求和https请求
- 11-27echarts图形报表的入门案例
- 11-27Echarts仿电梯运行图
- 11-27微信小程序开发之wepy 引入echarts统计图方法 亲测可用
- 11-27yarn安装echarts教程
- 11-27微信小程序使用 ECharts
- 11-274、echarts 如何画图?(必会)
- 11-27JavaScript 前端数据可视化——ECharts.js
- 11-27vue+echarts使用
- 最近发表
- 标签列表
-
- cmd/c (57)
- c++中::是什么意思 (57)
- sqlset (59)
- ps可以打开pdf格式吗 (58)
- phprequire_once (61)
- localstorage.removeitem (74)
- routermode (59)
- vector线程安全吗 (70)
- & (66)
- java (73)
- org.redisson (64)
- log.warn (60)
- cannotinstantiatethetype (62)
- js数组插入 (83)
- resttemplateokhttp (59)
- gormwherein (64)
- linux删除一个文件夹 (65)
- mac安装java (72)
- reader.onload (61)
- outofmemoryerror是什么意思 (64)
- flask文件上传 (63)
- eacces (67)
- 查看mysql是否启动 (70)
- java是值传递还是引用传递 (58)
- 无效的列索引 (74)