k8s集群高并发场景下,kube-proxy ipvs模式下的优缺点
问题说明
k8s集群在IPVS模式下,通过Service方式访问集群内部服务,偶现1秒延时的情况,引起该问题的主要原因为社区IPVS连接复用Bug。
IPVS连接复用参数说明
IPVS对端口的复用策略主要由内核参数net.ipv4.vs.conn_reuse_mode决定。
- 当net.ipv4.vs.conn_reuse_mode=0时,IPVS不会对新连接进行重新负载,而是复用之前的负载结果,将新连接转发到原来的RS(IPVS的后端)上。
- 当net.ipv4.vs.conn_reuse_mode=1时,IPVS则会对新连接进行重新负载。
在 Debian 10 操作系统中,没有内核参数名为 net.ipv4.vs.conn_reuse_mode
,但是在使用 IPVS(IP Virtual Server)时,可以设置 net.ipv4.vs.conn_reuse_mode
参数来控制 IPVS 是否复用连接。具体含义和作用如下:
需要安装ipvs模块:apt install conntrack ipset ipvsadm -y
- 默认值
net.ipv4.vs.conn_reuse_mode
的默认值为 0,表示 IPVS 不会复用连接。 - 含义
net.ipv4.vs.conn_reuse_mode
参数用于控制 IPVS 是否复用已经建立的连接。当该参数设置为 1 时,IPVS 会尝试复用已经建立的连接;当该参数设置为 0 时,IPVS 每次需要建立新的连接。 - 作用 TCP 连接的复用可以减少连接建立的开销,提高网络传输的效率。当 IPVS 需要大量的 TCP 连接时,使用连接复用模式可以显著减少连接建立的时间和开销,提升网络性能。但是,如果网络传输的数据量较小,连接复用的效果可能不明显。
- 与 IPVS 的关系 IPVS 是一个高性能的负载均衡器,通过在内核空间实现负载均衡,可以提高网络传输的效率和可靠性。
net.ipv4.vs.conn_reuse_mode
参数是 IPVS 的一个参数,用于控制连接复用的方式。通过设置该参数,可以调整 IPVS 的连接复用模式,提高负载均衡的效率和性能。 总的来说,net.ipv4.vs.conn_reuse_mode
参数可以根据网络传输的特点和需求进行配置,以提高网络传输的效率和性能。
kube-proxy 使用 IPVS 、iptables模式时,默认情况下会将 net.ipv4.vs.conn_reuse_mode
参数设置为 1,即开启连接复用模式。
如何查看ipvs内核参数?
sysctl net.ipv4.vs.conn_reuse_mode
所以需要手动把该参数关闭
#永久关闭
vim /etc/sysctl.conf
# Disable IPVS connection reuse mode
net.ipv4.vs.conn_reuse_mode=0
sysctl -p
如果将 net.ipv4.vs.conn_reuse_mode
参数设置为 0,即禁止连接复用模式,可能会导致以下问题:
- 增加连接创建和销毁的开销,降低网络吞吐量和性能。
- 由于 kube-proxy 在 IPVS 模式下使用了连接池技术,禁用连接复用可能会导致连接池中的连接不能被有效地复用和管理,从而可能会出现连接耗尽的情况。 如果开启和关闭连接复用模式的性能区别,取决于具体的网络环境和负载情况。一般来说,开启连接复用模式可以提高网络性能和吞吐量,但也可能会增加一些额外的开销和复杂性。如果禁用连接复用模式,在某些情况下可能会提高连接的可靠性和稳定性,但也会降低网络性能和吞吐量。因此,需要根据具体的应用场景和负载情况来选择是否开启连接复用模式。
如果将 net.ipv4.vs.conn_reuse_mode
参数设置为 1,即开启连接复用模式,可能会导致以下问题:
- 开启连接复用模式可以提高网络性能和吞吐量,因为它可以减少连接创建和销毁的开销,同时减少了连接的延迟和开销,从而提高了网络的响应速度和效率。但是,在高并发和高负载的情况下,如果连接复用过多,可能会导致连接池中的连接资源被过度占用,从而影响其他连接的使用和管理,甚至可能导致网络拥塞和故障。 另外,需要注意的是,开启连接复用模式可能会增加一些额外的开销和复杂性,例如需要对连接池进行管理和优化,以及处理连接复用带来的一些关联问题。因此,在选择是否开启连接复用模式时,需要根据具体的网络环境和负载情况,结合实际的需求和性能指标进行权衡和选择。 总之,在使用
ipvs
时,需要综合考虑连接复用模式的优缺点,根据实际的需求和性能指标进行选择和调整,以达到最优的网络性能和效率。同时,还需要加强对连接池的管理和优化,避免出现连接资源过度占用和管理不当的情况。 - 只要有
client ip:client port
匹配上 ip_vs_conn (发生复用),就直接转发给对应的 rs,不管 rs 当前是什么状态,即便 rs 的 weight 为 0 (通常是TIME_WAIT
状态) 也会转发,TIME_WAIT
的 rs 通常是 Terminating 状态已销毁的 Pod,转发过去的话连接就必然异常。 - 在高并发的情况下,如果大量地复用连接,可能会导致新的连接没有被正确地调度到后端的服务上,而是直接被转发到已经复用的连接所对应的服务上,导致一些服务被过度占用,而其他服务却空闲。这样就会导致一些新的连接被“固化”到部分服务上,而其他服务却无法得到合理的利用。
- 举个例子来说,假设有三个后端服务 A、B、C,它们都可以处理客户端的请求。当客户端发起一个新的连接时,如果连接池中已经存在一个与客户端 IP 和端口相同的连接,那么这个新连接就会被复用,并直接转发到这个已有连接所对应的服务上。但是,如果复用过多,就可能会出现这样的情况:如果大量的连接都被复用到了服务 A 上,而服务 B 和 C 却一直处于空闲状态,这就会导致新的连接无法得到合理的分配和利用,从而影响整个系统的性能和效率。 在使用连接复用时,需要注意对连接的调度和分配,避免出现连接资源被过度占用和服务资源利用不均衡的情况,从而保证整个系统的稳定性和性能。
- 再举个列子,如果有新的连接请求与已有连接的 IP 和端口相同,就会直接复用已有的连接,而不会去调度新的后端服务。 如果服务 A 正在滚动更新,也就是说服务 A 正在逐步停止服务并更新,那么这时候如果有新的连接请求到达,如果这些新的连接与已有连接的 IP 和端口相同,就会直接复用已有的连接,即使这个连接对应的是服务 A,也不会去调度其他后端服务,因为连接复用模式是不会改变已有连接对应的服务的,还是会转发到服务 A 上。因此,在这种情况下,流量仍然会转发到正在销毁的服务 A身上,这就导致了请求异常。 所以,在进行滚动更新等操作时,需要注意控制连接复用模式的使用,避免出现连接资源被过度占用和服务资源利用不均衡的情况,从而保证整个系统的稳定性和性能。
总结:业务中实际遇到的现象可能有很多种:
- 滚动更新连接异常。 被访问的服务滚动更新时,Pod 有新建有销毁,ipvs 发生连接复用时转发到了已销毁的 Pod 导致连接异常 (
no route to host
)。 - 滚动更新负载不均。 由于复用时不会重新调度连接,导致新连接也被 “固化” 在某些 Pod 上了。
- 新扩容的 Pod 接收流量少。 同样也是由于复用时不会重新调度连接,导致很多新连接被 “固化” 在扩容之前的这些 Pod 上了。
规避方案:
南北向流量
- 使用 LB 直通 Pod。对于南北向流量,通常依赖 NodePort 来暴露,前面的负载均衡器将流量先转到 NodePort 上,然后再通过 ipvs 转发到后端 Pod。现在很多云厂商都支持 LB 直通 Pod,这种模式下负载均衡器直接将请求转发到 Pod,不经过 NodePort,也就没有 ipvs 转发,从而在流量接入层规避这个问题。
- 使用 ingress 转发。在集群中部署 ingress controller (比如 nginx ingress),流量到达 ingress 再向后转时 (转发到集群内的 Pod),不会经过 service 转发,而是直接转发到 service 对应的
Pod IP:Port
,也就绕过了 ipvs。Ingress controller 本身结合使用前面所说的 LB 直通 Pod 方式部署,效果更佳。(推荐)
东西向流量
集群内的服务间调用 (东西向流量),默认还是会走 ipvs 转发。对于有这种高并发场景的业务,我们可以考虑使用 Serivce Mesh (如 istio) 来治理服务流量,服务间转发由 sidecar 代理,并且不会经过 ipvs。
出于稳定性考虑,建议不开启连接复用功能, net.ipv4.vs.conn_reuse_mode
参数设置为 0
如何模拟复现连接是否被复用?
下面是一个可能的复现步骤:
- 在 Kubernetes 集群中启用 IPVS 模式,使用端口复用。
- 创建一个 Service,并将其绑定到一个端口上,同时指定多个 Pod 作为其 Endpoint。
- 删除其中一个 Pod,查看连接池中,该 Pod 是否能够正常从 Endpoint 列表中移除。
kubectl get endpoints dnstools
- 同时在worker节点查看ipvsadm规则
ipvsadm -Sn |grep 10.43.23.126
如果出现了 RS 无法移除的问题,可能需要检查以下几点:
-
端口复用是否已经启用,如果没有启用,可以尝试启用端口复用。
-
是否存在其他未知的问题,例如网络延迟、防火墙设置等等。
-
检查 IPVS 的相关配置和内核参数是否正确。 在 Kubernetes 中,RS(Real Server)指的是 Service 的后端 Pod,用于接收来自客户端的请求,并提供相应的服务。在 IPVS 模式下,RS 可以通过配置 Endpoint 来进行定义和管理。