1.服务器环境以及配置
处理器: | Intel 32核 |
内存: | 128G |
整机类型/架构: | x86_64虚拟机 |
【内核版本】
4.19.90-25.22.v2101.kylin.x86_64
【OS镜像版本】
kylin server V10 SP2
【第三方软件】
开阳k8s
2.问题现象描述
前端机器访问后端容器超时,业务中断。
3.问题分析
3.1. 网络环境拓扑
centos前端访问腾讯负载均衡CLB的9083端口,CLB从k8s集群的20个节点中选择一台将前端的访问请求转发到其30170端口,转发节点再将前端的访问请求转发到提供所需服务的worker node,由worker node的pod为前端提供服务。
3.2. 2月20日网络数据包文件分析
hive.n920e1nodap0050.0220.pcap为2月20日复现问题时在转发节点n920e1nodap0050捕获的网络数据包文件。
转发节点n920e1nodap0050,tcp stream 171为前端和后端之间的TCP连接。
前端发送给转发节点的783号包的seq为2879,tcp data len为4。
图 2
前端发送给转发节点的784号包的tcp data len为1398, IP首部带有不允许分片的flag。
图 3
前端发送给转发节点的785号包的tcp data len为1307。
图 5
转发节点发送给前端的786号包的ack为2883,这正好是783号的seq+len。说明,后端pod收到了783号包,786号包是对783包的ack。
图 6
786号包带有TCP选项SACK,向发送端(前端)报告了一个空缺,后端pod还未收到seq为2883到4280(长度为1398)的数据,即784号包,就已经收到了seq为4281到5587(长度为1307)的数据,即785号包。
图 7
前端收到786号包后,了解到后端pod已经收到了785号包,但是没有收到784号包,于是重传784号包,重传多次,均未收到后端pod对该包的ack,最终导致TCP连接中断。
图 8
图 9
3.3. 2月29日网络数据包文件分析
n920e1infap0001.0229.pcap为2月29日复现问题时在转发节点n920e1infap0001捕获的网络数据包文件。tcp stream 59为转发节点和后端pod之间的TCP连接。
图 10
转发节点发送给后端pod的864号包包含seq从2939到2942长度为4的tcp data。
图 11
转发节点发送给后端pod的865号包包含seq从4341到5073长度为733的tcp data。还未发送seq为2943到4340长度为1398的tcp data,就已经发送了seq从4341到5073长度为733的tcp data。因次,wireshark给865号包打上了”TCP Previous segment not captured”的提示。和2月20日的情形一致,后端pod均未收到长度为1398的tcp data。
图 12
3.4 长度为1398的tcp data丢包原因分析
由3.2部分的分析可知,后端转发节点的eth0网卡收到了frame len为1464,tcp len为1398的tcp数据包,但是后端pod并未收到。由3.3部分的分析可知,后端转发节点的eth0网卡并未将tcp len为1398的tcp数据包转发给后端pod。
后端转发节点的eth0网卡收到前端发送的数据包之后,在转发给后端pod前,会先交给后端转发节点的tunl0网卡处理(设置IP头部数据等)。
因此,tcp len为1398的tcp数据包是在转发节点的tunl0网卡的接收或者转发过程中丢失的。
小包可以成功接收,但收不到大包,一个常见的原因是IP数据报的长度超过了网卡的mtu。
tcp len为1398的tcp数据包的IP数据报的长度为20(IP首部长度)+32(TCP首部长度)+1398(应用数据)=1450。
图 13
k8s集群节点的tunl0网卡的mtu为1440,小于tcp len为1398的IP数据报的长度1450。由图 4可知,前端发送的数据包IP首部带有不允许分片的flag。因此,该数据包会在转发节点的tunl0网卡接收过程中被drop掉。
图 14
4.问题分析结果
前端机器访问后端容器超时的原因是: 前端发送的长度超过后端转发节点的tunl0网卡的mtu的IP数据报在传输过程中被后端转发节点的tunl0网卡drop,前端多次重传,均收不到对该类包的ack,最终导致TCP连接中断。
5.后续计划与建议
建议联系k8s厂商或客户侧k8s环境管理员,适当调整集群节点的tunl0网卡的mtu。