背景
目前的场景下,任务管理集群 API Server 有 6 个节点,Agent 集群的数量有 36w+。之前的算法是 Agent 通过注册中心获取 API Server 全量的节点数,并建立连接,所以每个 API Server 上维护了 36w+ 的连接池。
当集群负载高时,扩容 API Server 节点并不能解决负载的问题,因为新节点并不能平摊其他节点的连接数,为此需要采用 Sharding 的方式,让每个 Agent 连接到部分的 API Server 节点,并且这个过程需要是幂等的,就是如果 API Server 节点没有变更,那么 Agent 节点获取到的 API Server 节点是不变的。
方案
采用的方案是《SRE Google 运维解密》书中提到的子集选择算法二:确定性子集。
用 Golang 实现了这个算法,在实际使用中,Backends 保存了 API Server 节点的 IP,ClientID 是将原 Client 的 IP 地址做了 CRC 处理,转成 int,SubsetSize 就是子集的大小。
func Subset(backends []string, clientId int, subsetSize int) []string {
subSetCount := len(backends) / subsetSize
round := clientId / subSetCount
rand.Seed(int64(round))
rand.Shuffle(len(backends), func(i, j int) {
backends[i], backends[j] = backends[j], backends[i]
})
subsetId := clientId % subSetCount
start := subsetId * subsetSize
return backends[start : start+subsetSize]
}

