k8s下的长连接负载均衡

前言

本文开写的原因是在 《k8s in action》一书的十七章提到了,在pod关闭时,避免客户端断开连接。

即当客户端与 pod 之间存在长连接, pod 存在多副本时, pod 关闭,但是长连接(比如 gRPC)不会断开。

原书这里有些没看明白。书里主要提及的情况是 kube-proxy 还为来得及修改iptables,pod便被关闭,会导致客户端得到连接被拒绝的结果

所以为了防止这种情况,应该在pod被删除时,通过删除钩子让他暂停5s之类的,等待 kube-proxy 完成对 iptables 的修改后再关闭。

但是为什么修改了iptables,连接就不会断了?不是很明白,所以就有了这篇文章

对于长连接的结论

个人的结论是

一定是要断的。

哪怕能做到 四元组啥的都不变,tcp连接时的那个连接随机数,后续连接也是拿不出来的。

所以如果是 kube-proxy 这种,也就是说连接直达pod,中间没有代理服务之类的情况。那么对于客户端来说连接必定是会断开的。

无外乎是自己断开还是服务端断开的区别

k8s 长连接负载均衡

在寻找长连接处理方式的过程中,发现了一些关于长连接负载均衡的问题

比如 gRPC 基于HTTP2的 连接复用的特性。会导致大量的流量其实是复用的同一个连接,于是全部流量打到了podA上,其他 pod 完全处于“一核有难,七核围观”的状态。

因而对于 gRPC这类长连接,需要使用特殊的负载均衡

这里结合

客户端建立多个连接

也就是 客户端 与每一个 pod 都建立连接,并将连接放入自己维护的连接池中。

复杂度不低

要么需要客户端实时监控k8s集群资源,或者通过headless,或者通过订阅某些服务注册组件的信息

来获得对应的pod的四元组,然后让客户端与每一个pod建立长连接,并且自己管理连接池

服务端主动断开

可以令 服务端 主动断开连接,使与它连接的客户端转而与其他pod连接

但是这是问题最大的方法

目前找到的 可靠的服务端断开连接而不是停止监听的方法使配置 keepalive 的 Max ConnectionAge

var kasp = keepalive.ServerParameters{
	MaxConnectionIdle:     15 * time.Second, // If a client is idle for 15 seconds, send a GOAWAY
	MaxConnectionAge:      30 * time.Second, // If any connection is alive for more than 30 seconds, send a GOAWAY
	MaxConnectionAgeGrace: 5 * time.Second,  // Allow 5 seconds for pending RPCs to complete before forcibly closing connections
	Time:                  5 * time.Second,  // Ping the client if it is idle for 5 seconds to ensure the connection is still active
	Timeout:               1 * time.Second,  // Wait 1 second for the ping ack before assuming the connection is dead
}

func main(){
	...
	s := grpc.NewServer( grpc.KeepaliveParams(kasp))
	...
}

这里的一个问题是,它是固定的,而非动态,并不是我们预想的调用某个参数,来中断某些连接

另一个问题是,如果在超时时,正好在执行业务,将会带来额外的风险。

所以写在这里只做参考

中间层分发

在实际的服务前,放一个自己或者开源的负载均衡中间层。

将计算与传输分开。 比如gRPC请求全部给到一个自己开发的 middle pod,再有pod 来根据各个计算pod的负载情况,建立对应的连接

这里 k8s官方博客推荐了 Linkerd

目前看也是最简洁方便的解法

未来探究的内容

根据咨询,得知诸如 tcp连接随机数这些东西,可以通过 eBPF 获取

那么 cilium 不正好是使用 eBFP的?

那么cilium是否可有做到无痛缩容(连接的A pod被删除,长连接无痛转移到B pod)?

参考文档

k8s上的gRPC负载均衡

长连接的负载均衡问题

Close the connection from the gRPC server side