1. 什么是 QPS 和 Burst ?
在 kubernetes client-go 中,QPS 和 Burst 是用于控制客户端与 Kubernetes API 交互速率的两个关键参数:
QPS (Queries Per Second)
定义:表示每秒允许发送的请求数量,即限速器的平滑速率。
用途:用来控制客户端与 API Server 的持续请求速率。
场景:适用于需要长时间维持均匀的 API 调用的情况。
Burst
定义:表示瞬时允许发送的最大请求数量,即限速器的突发容量。
用途:允许在短时间内发送的请求数量上限,适用于突发性调用场景。
场景:例如,客户端初始化时,需要快速获取大量资源。
2. 实验验证
可以通过编写代码,发送大量 API 请求来验证 QPS 和 Burst 的行为。以下是一个实验示例:
go
package main
import (
"context"
"flag"
"fmt"
"log"
"sync"
"time"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/client-go/kubernetes"
"k8s.io/client-go/tools/clientcmd"
)
func main() {
// 加载 kubeconfig
kubeconfig := flag.String("kubeconfig", "~/.kube/config", "Path to kubeconfig file")
flag.Parse()
config, err := clientcmd.BuildConfigFromFlags("", *kubeconfig)
if err != nil {
log.Fatalf("Failed to load kubeconfig: %v", err)
}
// 设置 QPS 和 Burst
config.QPS = 5.0 // 每秒 5 个请求,也是默认设置
config.Burst = 10 // 突发允许 10 个请求,也是默认设置
// 创建客户端
clientset, err := kubernetes.NewForConfig(config)
if err != nil {
log.Fatalf("Failed to create clientset: %v", err)
}
// 统计开始时间
startTime := time.Now()
// 使用 WaitGroup 追踪请求完成
var wg sync.WaitGroup
totalRequests := 50
wg.Add(totalRequests)
// 发送大量请求
for i := 0; i < totalRequests; i++ {
go func(i int) {
defer wg.Done()
_, err := clientset.CoreV1().Pods("").List(context.TODO(), metav1.ListOptions{})
if err != nil {
log.Printf("Request %d failed: %v", i, err)
} else {
log.Printf("Request %d succeeded", i)
}
}(i)
}
wg.Wait()
fmt.Printf("Total time taken: %v\n", time.Since(startTime))
}
配置 QPS 和 Burst:
设置 QPS = 5,表示每秒最多发送 5 个请求。
设置 Burst = 10,允许在瞬时突发时最多发送 10 个请求。
当发生客户端限流时,会出现类似如下输出:
sh
2025/01/10 15:01:50 Request 32 succeeded
I0110 15:01:50.468917 3083 request.go:729] Waited for 1.19372275s due to client-side throttling, not priority and fairness, request: GET:https://127.0.0.1:63092/api/v1/pods
2025/01/10 15:01:50 Request 33 succeeded
当发生客户端限流时,请求排队,实际完成时间会被延长。
实验结果:
当设置 QPS = 5,Burst = 10 时,请求全部成功,完成耗时 8s
当设置 QPS = 1,Burst = 2 时,请求全部成功,完成耗时 48s
调整建议
如果需要高频请求,可适当增大 QPS 和 Burst,避免客户端过度限流。
同时,合理设置参数,可以避免客户端过高的并发负载影响集群稳定性。
源码机制
client-go 使用令牌桶进行速率限制,桶容量为 burst 大小,按照每秒生成 QPS 个令牌的速率产生令牌(不会实际启动协程生成令牌,而是根据时钟计算),只有拿到令牌才能请求 kube-apiserver,如下图所示:
reference: client-go QPS、Burst和令牌桶