技术分享之 解决Kubernetes APIServer流量不均衡问题

解决Kubernetes APIServer流量不均衡问题

Posted by 董江 on Monday, July 11, 2022

解决Kubernetes APIServer流量不均衡问题

版本: 1.8版本 <= kubernetes verison < 1.18版本 都存在

在 kubernetes 1.8以上,对kubelet 和 client-go SDK进行性能提升,将与apiserver的HTTP1.1协议改为HTTP2协议,支持多路复用长连接;

问题现象

这样对于大集群(多kubelet)、多Controller(client-go)集群, 会发现APIServer的稳态情况下的连接数请求QPS是不均衡的。

APiServer No Rebalance

重启apiserver后, HTTP2的流量负载到其他两个节点上了. 现象一致

原因分析

由于 APIServerclient server 是使用 HTTP2 协议连接,HTTP2 的多个请求都会复用底层的同一个 TCP 连接并且长时间不断开。而在 APIServer 发生 RollingUpdate 或者某个 APIServer 实例重启时,又或者 APIServer 使用 MaxSurge=Replica 方式升级后, LoadBalance 没有及时的将所有副本挂载完毕,client server 能敏感的感知到连接的断开并立刻发起新的请求,这时候很容易引起较后启动(或者较后挂载 LoadBalance)的 APIServer 没有一点流量,并且可能永远都得不到负载均衡。

解决方案

Kubernetes 1.18版本中,新增了 GOAWAY Chance 新特性.

增加了一种通用的 HTTP filterAPIServer 概率性(建议 1/1000)的随机关闭和 Client 的链接(向 Client 发送 GOAWAY)。关闭是优雅的关闭,不会影响 APIServerclient server 正在进行中的长时间请求(如 Watch 等),但是收到 GOAWAY 之后,client server 新的请求就会重新建立一个新的 TCP 链接去访问 APIServer 从而能让 LoadBalance 再做一次负载均衡。

开启方式

–goaway-chance float 为防止 HTTP/2 客户端卡在单个 API 服务器上,可启用随机关闭连接(GOAWAY)。 客户端的其他运行中请求将不会受到影响,并且客户端将重新连接, 可能会在再次通过负载平衡器后登陆到其他 API 服务器上。 此参数设置将发送 GOAWAY 的请求的比例。 具有单个 API 服务器或不使用负载平衡器的集群不应启用此功能。 最小值为0(关闭),最大值为 .02(1/50 请求);建议使用 .001(1/1000)。

spec:
  containers:
  - command:
    - kube-apiserver
    - --advertise-address=x.x.x.x
    - --basic-auth-file=/xxx/user
    - --bind-address=0.0.0.0
    - --feature-gates=ExpandInUsePersistentVolumes=true,VolumeSnapshotDataSource=true
    - --client-ca-file=/xxx/ca.crt
    - --enable-admission-plugins=NodeRestriction
    - --enable-bootstrap-token-auth=true
    - --endpoint-reconciler-type=lease
    - ...
    - --goaway-chance=0.001  # 1/1000的连接 请求后,断开connection

调试测试

* 注意点⚠️(条件)

  • kubenetes版本 : 1.18.2
  • 硬件环境:Mac Pro 4Core, 8G
  • 业务复杂: kubemark mock 1000个 Node Kubelet
  • 受环境、网络影响,性能数据 无绝对值意义,有相对值值意义
测试Case 平均值(ms) P50(ms) P90(ms) P95(ms) P99(ms) 与基线比例(%)
no goaway chance 44 29 65 96 426 -
–goaway-chance=0.01 48 30 80 125 419 9%
–goaway-chance=0.001 46 30 59 90 540 4.5%
  • APIServer平均性能(response time)ms 对比 基线下降 5%左右

效果

APIServer API Balance

结论: 启用goaway chance后,虽达不到绝对均衡,整体效果不错。 建议设置--goaway-chance=0.001

源码研习

type probabilisticGoawayDecider struct {
	chance float64
	next   func() float64  // 内部有个sync.poo来做当前请求连接数据,本身 pop 和 push 会有非常小的开销
}

// 判断迭代器是否触发上线
func (p *probabilisticGoawayDecider) Goaway(r *http.Request) bool {
	if p.next() < p.chance {
		return true
	}

	return false
}

func (p *goaway) ServeHTTP(w http.ResponseWriter, r *http.Request) {
	if r.Proto == "HTTP/2.0" && p.decider.Goaway(r) {
		// apiserver 主动将HTTP2 关闭连接。 client-go 完成本次请求后主动断开连接
		w.Header().Set("Connection", "close")
	}

	p.handler.ServeHTTP(w, r)
}

扩展思路

Pod之间TCP请求也会请求流量不均衡情况,这个下次介绍。 原理一样,但是解法不同

社区最新更新信息

版本: kubernetes 1.18 版本以上版本已解决 给社区提交的修复 PR 已经被合入 88567

「如果这篇文章对你有用,请随意打赏」

Kubeservice博客

如果这篇文章对你有用,请随意打赏

使用微信扫描二维码完成支付