问题

最近,决策引擎上线了kunpeng-gateway网关,hermod直连kunpeng-gateway的内网域名,存在少量的rst。应用服务端客户端都没有更多的日志信息。
connection reset日志

排查经过

针对该问题,我们内部讨论,首先排查域名使用问题,其次确认集群内容器内访问svc数据包的流向。(kunpeng-gw ip 10.158.158.44)

traceroute排查域名

在我们cni为kube-router的集群上,数据包从容器内出来,直接送到容器所在物理机的kube-dummy-if 网卡。经过本机的ipvs规则(集群外调用svc就很难找到哪个节点的ipvs规则在生效)dnat到目标容器10.157.32.66。


既然起作用的ipvs就是客户端容器所在物理机,这下问题排查起来就容易很多了。除了客户端服务端容器内抓包,我观察客户端所在ipvs规则就可以了。

导入一笔测试流量,在客户端抓包。可以看到tcp三次握手,以及后续push的数据包,并没有收到fin包。客户端到服务端使用了长链接方式。触发一次测试调用后,我收不到任何数据包了就。

看了下客户端到服务端的链接是存在的。

客户端

服务端

ipvs,其中第二列为过期时间,具体过期时间多少?

看下ipvs会话保持的超时时间。tcp:针对establish的链接的超时时间。tcpfins:客户端发起fin挥手后,FIN_WAIT状态超时时间,udp:udp包超时时间。

系统运维组 > hermod调用kunpeng-gateway域名Connection rest问题 > image2022-3-28 17:51:35.png

conntrack 转发的五元组信息。

系统运维组 > hermod调用kunpeng-gateway域名Connection rest问题 > image2022-3-28 17:55:39.png

系统运维组 > hermod调用kunpeng-gateway域名Connection rest问题 > image2022-3-31 14:21:33.png

起初测试同学帮我在stag环境做了压测,持续压测一段时间后,ipvsadm -lnc 看到的过期时间一直是14:59(超时时间900s换算的倒计时)。观察一段时间,业务日志也没有复现Connection rest现象。

之后我把持续压测的流量停了,ipvs倒计时开始走起来了。

系统运维组 > hermod调用kunpeng-gateway域名Connection rest问题 > image2022-3-29 10:21:56.png

继续观察,期间不再压测。客户端服务端没有数据交互,也没有心跳包。等15分钟倒计时后,ipvs把这个转发的四元组给删了。

再发一笔调用。调用失败。

系统运维组 > hermod调用kunpeng-gateway域名Connection rest问题 > image2022-3-29 10:23:8.png

客户端有rst日志,问题复现。

系统运维组 > hermod调用kunpeng-gateway域名Connection rest问题 > image2022-3-29 10:23:47.png

原因:
系统运维组 > hermod调用kunpeng-gateway域名Connection rest问题 > image2022-3-29 10:39:0.png

如上图,A (hermod)和 B(kunpeng-gateway) 通过NAT 建链,客户端服务端没有流量,同时hermod到kunpeng-gateway之间也没有任何保活机制,当这个时间超过ipvs设置的超时时间15分钟后。

ipvs这个中间人就会把之前建立好的转发规则给删掉了,再之后客户端还使用原先的链路进行push数据被rst了。

下面是出错请求时的报文。

客户端:

系统运维组 > hermod调用kunpeng-gateway域名Connection rest问题 > image2022-3-29 10:34:28.png

由于ipvs的转发链路不存在,服务端没有收到任何报文。

系统运维组 > hermod调用kunpeng-gateway域名Connection rest问题 > image2022-3-29 10:35:16.png

修复:
方案(一)
1.修改内核参数
查阅参考文章了解到tcp保活的几个相关的内核参数。

net.ipv4.tcp_keepalive_intvl、net.ipv4.tcp_keepalive_probes、net.ipv4.tcp_keepalive_time

宿主机:

系统运维组 > hermod调用kunpeng-gateway域名Connection rest问题 > image2022-3-29 10:40:47.png

容器:

系统运维组 > hermod调用kunpeng-gateway域名Connection rest问题 > image2022-3-29 10:42:20.png

容器net namespace有独立的内核参数,不使用k8s-node节点的配置,所以容器内的tcp_keepalive_time为7200s(2小时)。

一旦客户端服务端没有流量,客户端要2小时才能发出第一个心跳包,而ipvs等15分钟就把规则删了。所以这里明显有问题了。

修改容器内的内核参数。(k8s修改内核参数的方式https://kubernetes.io/docs/tasks/administer-cluster/sysctl-cluster/)

这边加个initcontainer赋给root权限,没有直接给业务容器root权限。

  initContainers:
  - command:
    - /bin/sh
    - -c
    - |
      sysctl -w net.ipv4.tcp_keepalive_time=60
      sysctl -w net.ipv4.tcp_keepalive_intvl=10
      sysctl -w net.ipv4.tcp_keepalive_probes=3
    image: registry.hz.td/cd/busybox:latest
    imagePullPolicy: Always
    name: init-sysctl
    resources: {}
    securityContext:
      privileged: true

继续发一笔流量,长链接建立,倒计时开始,预期的60s到了并没有发现有心跳包发出,还有问题。

修改业务代码:
继续谷歌,参考 https://tldp.org/HOWTO/html_single/TCP-Keepalive-HOWTO/#whyuse 4.2、4.3有C程序关闭和开启了tcp keepalive的例子。对比不难看出来

,业务创建socket时需要开启SO_KEEPALIVE类似的机制,然后才能用得上以上三个内核参数的配置。

在周军文帮助下修改了hermod代码,客户端开启tcp keepalive机制。

系统运维组 > hermod调用kunpeng-gateway域名Connection rest问题 > image2022-3-29 11:12:16.png

客户端服务端建链后,每隔net.ipv4.tcp_keepalive_time时间发送一个心跳包。

系统运维组 > hermod调用kunpeng-gateway域名Connection rest问题 > image2022-3-29 11:19:55.png

至此,再也不会遇到ipvs因为15分钟超时时间而把转发链路删掉的情况了,缺点也看出来了,只要客户端、服务端不主动断链,这条链路几乎不会被释放。

感谢 陈慧同学 提供关于httpclinet 自定义长链接保持时间的设置方法

系统运维组 > hermod调用kunpeng-gateway域名Connection rest问题 > image2022-4-18 15:53:14.png

方案(二)
业务在出现hermod rst的情况后,通过改成原有的使用方式调用forseti-gateway,forseti-gateway再调用kunpeng-gateway来止损,这样用没有rst的情况。

同样的k8s集群,业务也是没有使用,也没法使用4层的保活机制的。因为容器内内核参数的配置导致2小时才有一个心跳包。(后面发现可以通过命令netstat -aptn --timer Time查看是否开启tcp keepalive保活)

当forseti-gateway做为hermod服务端时,持续10分钟左右(我肉眼估计的时间,小于ipvs的超时时间)没有数据交互,服务端forseti-gateway会主动断链。后续hermod再有新的请求,使用重新握手,所以没有rst。

系统运维组 > hermod调用kunpeng-gateway域名Connection rest问题 > image2022-3-29 16:44:55.png

系统运维组 > hermod调用kunpeng-gateway域名Connection rest问题 > image2022-3-29 16:50:56.png

当forseti-gateway做为kunpeng-gateway客户端时,同样forseti-gateway也会主动断链。

得益于forseti-gateway 主动断开没有数据的tcp连接,且断开时间小于ipvs 删除转发规则的时间,所以一直没有出现Connect rest问题。

参考:

https://blog.csdn.net/qq_22543991/article/details/115217953

https://tldp.org/HOWTO/html_single/TCP-Keepalive-HOWTO/