就是要你懂 TCP | 通过案例来学习 MSS、MTU
- 最近要通过 Docker 的方式把产品部署到客户机房, 过程中需要部署一个 hbase 集群,hbase 总是部署失败(在我们自己的环境没有问题)
- 发现 hbase 卡在同步文件,人工登上 hbase 所在的容器中看到在 hbase 节点之间 scp 同步一些文件的时候,同样总是失败(稳定重现)
- 手工尝试 scp 那些文件,发现总是在传送某个文件的时候 scp 卡死了
- 尝试单独 scp 这个文件依然卡死
- 在这个容器上 scp 其它文件没问题
- 换一个容器 scp 这个文件没问题
分析过程
实在很难理解为什么单单这个文件在这个容器上 scp 就卡死了,既然 scp 网络传输卡死,那么就同时在两个容器上 tcpdump 抓包,想看看为什么传不动了
在客户端抓包如下:(33 端口是服务端的 sshd 端口,10.16.11.108 是客户端 ip)
screenshot
从抓包中可以得到这样一些结论:
- 从抓包中可以明显知道 scp 之所以卡死是因为丢包了,客户端一直在重传,图中绿框
- 图中篮框显示时间间隔,时间都是花在在丢包重传等待的过程
- 奇怪的问题是图中橙色框中看到的,网络这时候是联通的,客户端跟服务端在这个会话中依然有些包能顺利到达(Keep-Alive 包)
- 同时注意到重传的包长是 1442,包比较大了,看了一下 tcp 建立连接的时候 MSS 是 1500,应该没有问题
- 查看了 scp 的两个容器的网卡 mtu 都是 1500,正常
- 基本上看到这里,能想到是因为丢包导致的scp卡死,因为两个容器mtu都正常,包也小于mss,那只能是网络路由上某个环节mtu太小导致这个1442的包太大过不去,所以一直重传,看到的现状就是scp卡死了
接下来分析网络传输链路
scp 传输的时候实际路由大概是这样的
- 容器A--->宿主机1--->……中间的路由设备……--->宿主机2--->容器B
- 前面提过其它容器 scp 同一个文件到容器 B 没问题,所以我认为中间的路由设备没问题,问题出在两台宿主机上
- 在宿主机 1 上抓包发现抓不到丢失的那个长度为 1442 的包,也就是问题出在了 容器 A—> 宿主机 1 上
查看宿主机 1 的 dmesg 看到了这样一些信息
- 2016 - 08 - 08T08: 15 : 27.125951 + 00 : 00 server kernel: openvswitch: ens2f0.627 : dropped over - mtu packet: 1428 > 1400 2016 - 08 - 08T08: 15 : 27.536517 + 00 : 00 server kernel: openvswitch: ens2f0.627 : dropped over - mtu packet: 1428 > 1400
结论
- 到这里问题已经很明确了 openvswitch 收到了 一个 1428 大小的包因为比 mtu1400 要大,所以扔掉了,接着查看宿主机 1 的网卡 mtu 设置果然是 1400,悲催,马上修改 mtu 到 1500,问题解决。
最后的总结
- 因为这是客户给的同一批宿主机默认想当然的认为他们的配置到一样,尤其是 mtu 这种值,只要不是故意捣乱就不应该乱修改才对,我只检查了两个容器的 mtu,没看宿主机的 mtu,导致诊断中走了一些弯路
- 通过这个案例对 mtu/mss 等有了进一步的了解
- 从这个案例也理解了 vlan 模式下容器、宿主机、交换机之间的网络传输链路
- 其实抓包还发现了比 1500 大得多的包顺利通过,反而更小的包无法通过,这是因为网卡基本都有拆包的功能了
常见问题
Q: 传输的包超过 MTU 后表现出来的症状?
A:卡死,比如 scp 的时候不动了,或者其他更复杂操作的时候不动了,卡死的状态。
Q: 为什么我的 MTU 是 1500,但是抓包看到有个包 2700,没有卡死?
A: 有些网卡有拆包的能力,具体可以 Google:LSO、TSO,这样可以减轻 CPU 拆包的压力,节省 CPU 资源。
企业级互联网架构 Aliware,让您的业务能力云化: https://www.aliyun.com/aliware
来源: http://www.tuicool.com/articles/JRZraqv