Kubernetes运维:KubeProxy长连接问题
文章目录
问题描述
当 kube-proxy 使用 ipvs 模式时,客户端段长连接静默时间超过 15min 时,连接将被重置。
问题分析
通过 ipvsadm -lnc 命令可以查看节点上 ipvs 连接的持久化时间:
ipvs 管理连接超时时间有以下两方面的考量:
-
ipvs 支持 persistence_timeout ,通过这个参数用户可以在持续时间内把同一个 Client IP 的请求转发到同一个 RS。
-
TCP 在传输过程中可能出现报文分片,ipvs 即使不配置 persistence_timeout 时也需要管理连接的超时机制,以此保证把来自同一个 Client(IP+Port)的不同分片调度同一个 RS。
上述两点对应了两不同的超时设置,但 ipvs 将他们记录在同一张表中并用不同的 state 区别。
通过 ipvsadm -l –timeout 可以查看 ipvs 的超时时间设置,包括 tcp、tcpfin、udp 三种不同类型的超时间:
- tcp 超时时间:如果客户端和服务端建立了连接,则 ipvs 中会出现一条 ESTABLISHED 的记录。每当客户端和服务端的连接中有信息交互时,该超时时间都会刷新为初始值。如果连接处于空闲状态,即一直没有信息交互,则等到该值超时后,ESTABLISHED 的记录会被 ipvs 直接清理。这种情况下如果 Client 后续发送的请求(Client 不知道服务端已经删除了记录),ipvs 将重新调度请求到一个新的RS,这将导致连接中断。
- tcpfin 超时时间:如果客户端发起了 FIN 断连,则 ipvs 中连接状态会从 ESTABLISHED 变为 FIN_WAIT ,此时等待 tcpfin 时间后,记录将被移除。
通过 ipvsadm –set tcp tcpfin udp 可以全局设置该超时时间(重启主机失效):
用户如果为服务指定了 persistence_timeout ,这种情况下对每个 ClientIP 会出现一条 ASSURED 记录,表示指定 persistence_timeout 时间内,对应 ClientIP 的请求将转发到相同的 RS:
kube-proxy 在创建 Service 时支持指定 sessionAffinity 参数为 None 或者 ClientIP,当指定为 ClientIP 可以进一步指定 SessionAffinityConfig 参数,该参数即对应 ipvs 规则的 persistence_timeout 参数。
解决方案
根据上述描述我们知道,当 Client 不主动对长连接进行保活时 900s 后 ipvs 主动删除连接记录,导致长连接被重置。为此我们可以修订系统 tcp keepalive 配置,每隔 600s 发送一次保活心跳,以重置 ipvs 的连接超时计数。
|
|
在内核 4.13 版本中,tcp_keepalive_* 属性是独立 namespace 的,因此 Pod 不会独立从宿主机继承该配置,因此需要对在容器的 securityContext 中手工指定上述参数。
注意:参考 kubernetes 官方 issues/71358 , ipvs 中 timeout 是全局的,用户无法单独为某个服务设置超时时间。
参考
文章作者 yoaz
上次更新 2023-05-16
许可协议 MIT