程序锅

  • 首页
  • 分类
  • 标签
  • 归档
  • 关于

  • 搜索
基础知识 Etcd LeetCode 计算机体系结构 Kubernetes Containerd Docker 容器 云原生 Serverless 项目开发维护 ELF 深入理解程序 Tmux Vim Linux Kernel Linux numpy matplotlib 机器学习 MQTT 网络基础 Thrift RPC OS 操作系统 Clang 研途 数据结构和算法 Java 编程语言 Golang Python 个人网站搭建 Nginx 计算机通用技术 Git

Kubernetes APIServer-限流

发表于 2023-10-26 | 分类于 Kubernetes | 0 | 阅读次数 2234

MaxInFlightLimit(server 级别整体限流)

在 APF 出现之前,API Server 进行限流的方式是使用 API Server 的 --max-requests-inflight 和 --max-mutating-requests-inflight 参数。其中

  • --max-requests-inflight:在给定时间内的最大 non-mutating 请求数(非mutating操作:get,list 等查询操作)

  • --max-mutating-requests-inflight:在给定时间内的最大 mutating 请求数(mutating 操作:update, delete 等操作)

也就是说 API Server 的并发量受到上述两者参数的限制。

watch 请求不受 --max-requests-inflight 限制

源码

staging/src/k8s.io/apiserver/pkg/server/filters/maxinflight.go:WithMaxInFlightLimit()

参数推荐

默认值节点数1000-3000节点数 > 3000
max-requests-inflight40015003000
max-mutating-requests-inflight2005001000

缺点

  • 粒度粗:无法为不同用户,不同场景设置不同的限流

  • 单队列:共享限流窗口/桶,一个坏用户可能会将整个系统堵塞,其他正常用户的请求无法被及时处理

  • 不公平:正常用户的请求会被排到队尾,无法及时处理而饿死

  • 无优秀级:重要的系统指令一并被限流,系统故障难以恢复

APF

kubernetes 文档:https://kubernetes.io/zh-cn/docs/concepts/cluster-administration/flow-control/
设计文档:https://github.com/kubernetes/enhancements/tree/master/keps/sig-api-machinery/1040-priority-and-fairness

为了解决 API Server 限流机制存在的问题,API Server 添加了 APF 机制(1.15以上,alpha版本),

  • APF 可以以更细粒度(user/resource/namespace)的方式对请求进行分类和隔离,比如针对 pod 查询的请求进行请求限制和优先级分配。
  • 引入了空间有限的排队机制,因此在非常短暂的突发情况下,API Server 不会拒绝任何请求。
  • 通过使用公平排队技术从队列中分发请求,这样,一个行为不佳的控制器就不会饿死其他控制器(即使优先级相同)。

APF 的核心是

  • 多等级
  • 多队列

采用 APF 机制之后,API Server 限制的总流量为 --max-requests-inflight 和 --max-mutating-requests-inflight 的总和,不再区分是否是 mutating 操作,而总和又会被分配到一组可配置的优先级中(每个请求最终都会对应一个优先级)。

APF 的实现依赖两个非常重要的资源 FlowSchema、PriorityLevelConfiguration,

  • 传入的请求都会匹配到一个 FlowSchema,FlowSchema 内的请求又会根据 distinguisher 进一步划分为不同的 Flow。同时,FlowSchema 会设置一个 PriorityLevelConfiguration,也就是请求最终都会被分配给相应的 PriorityLevel。
  • PriorityLevelConfiguration 用于维护相应的并发限制,不同 PriorityLevel 的并发资源是隔离的,这样不同 PriorityLevel 的请求,就不会相互排挤,加强了隔离度。
  • 针对同一个 PriorityLevelConfiguration 分配到的请求,公平排队算法可以防止不同 flow 的请求不会相互饿死。该算法将请求排队,通过排队机制,防止在平均负载较低时,通信量突然而导致请求失败。

FlowSchema

每个入站请求都会对所有 FlowSchema 测试是否匹配,首先会从 matchingPrecedence 数值最低的匹配开始(我们认为这是逻辑上匹配度最高),然后依次进行,直接首个匹配出现。FlowSchema 匹配了一些入站请求后,会将它们分配给相应的优先级。匹配的规则见 rules 字段,相应的优先级见 priorityLevelConfiguration 字段。

apiVersion: flowcontrol.apiserver.k8s.io/v1beta1
kind: FlowSchema
metadata:
  name: kube-scheduler				# FlowSchema 名
spec:
  distinguisherMethod:
    type: ByNamespace					# Distinguisher,和 FlowSchema 一起,共同确定一个 flow
  matchingPrecedence: 800			# 规则优先级		
  priorityLevelConfiguration:	# 对应的队列优先级
    name: workload-high
  rules:
  - resourceRules:
    - resources:
      - '*'
      verbs:
      - '*'
    subjects:
    - kind: User
      user:
        name: system:kube-scheduler

上述 FlowSchema 的意思是:用户 system:kube-scheduler 发出的请求(rules 字段),会根据 namespace 分成不同的 flow,同时这些请求都会被分配到 workload-high 这个优先级。

需要注意的是:

  • PriorityLevelConfiguration 中会维护了一个 QueueSet 用于缓存不能及时处理的请求,请求不会因为超出 PriorityLevelConfiguration 的并发限制而被丢弃。
  • FlowSchema 中的每个 Flow 通过 shuffle sharding 算法从 QueueSet 选取特定的 queues 缓存请求。
  • 每次从 QueueSet 中取请求执行时,会先应用 fair queuing 算法从 QueueSet 中选中一个 queue,然后从这个 queue 中取出 oldset 请求执行。所以即使是同一个 PriorityLevelConfiguration 内的请求,也不会出现一个 Flow 内的请求一直占用资源的不公平现象。

kubernetes 有默认提供以下几个 FlowSchema,

$ kubectl get FlowSchema
NAME                           PRIORITYLEVEL     MATCHINGPRECEDENCE   DISTINGUISHERMETHOD   AGE   MISSINGPL
exempt                         exempt            1                    <none>                12d   False
probes                         exempt            2                    <none>                12d   False
system-leader-election         leader-election   100                  ByUser                12d   False
workload-leader-election       leader-election   200                  ByUser                12d   False
system-nodes                   system            500                  ByUser                12d   False
kube-controller-manager        workload-high     800                  ByNamespace           12d   False
kube-scheduler                 workload-high     800                  ByNamespace           12d   False
kube-system-service-accounts   workload-high     900                  ByNamespace           12d   False
service-accounts               workload-low      9000                 ByUser                12d   False
global-default                 global-default    9900                 ByUser                12d   False
catch-all                      catch-all         10000                ByUser                12d   False

PriorityLevelConfiguration

PriorityLevelConfiguration 其实是一个优先级等级的配置,它会指定该优先级限制的流量占总流量的比例(使用 assuredConcurrencyShares 字段表示),最终限制的流量为:总流量*(该优先级的 assuredConcurrencyShares /所有优先级 assuredConcurrencyShares 的总和)。

apiVersion: flowcontrol.apiserver.k8s.io/v1beta1
kind: PriorityLevelConfiguration
metadata:
  ...
  name: global-default
spec:
  limited:
    assuredConcurrencyShares: 20
    ...
  type: Limited
status: {}

需要注意的是:

  • 一个 PriorityLevelConfiguration 可以分配给多个 FlowSchema。

kubernetes 有默认提供以下几个优先级,包括针对领导者选举请求、内置控制器请求和 Pod 请求都单独设置优先级。这表示即使异常 Pod 向 API Server 发送大量请求,也无法阻止领导者选举或内置控制器的操作执行成功。

$ kubectl get PriorityLevelConfiguration
NAME              TYPE      ASSUREDCONCURRENCYSHARES   QUEUES   HANDSIZE   QUEUELENGTHLIMIT   AGE
catch-all         Limited   5                          <none>   <none>     <none>             7d4h
exempt            Exempt    <none>                     <none>   <none>     <none>             7d4h
global-default    Limited   20                         128      6          50                 7d4h
leader-election   Limited   10                         16       4          50                 7d4h
system            Limited   30                         64       6          50                 7d4h
workload-high     Limited   40                         128      6          50                 7d4h
workload-low      Limited   100                        128      6          50                 7d4h

启用/禁用 APF

APF 特性通过 feature gate 来启动和禁用, 它的 feature gate 是 APIPriorityAndFairness,默认是开启的。而它使用的 API 组中,v1alpha1 版本,默认被禁用,而 v1beta1 和 v1beta2 版本,默认被启用。

如下的配置,则会禁用 APF 和 v1beta1、v1beta2 两个 API 版本。

kube-apiserver \
--feature-gates=APIPriorityAndFairness=false \
--runtime-config=flowcontrol.apiserver.k8s.io/v1beta1=false,flowcontrol.apiserver.k8s.io/v1beta2=false \
  # ...其他配置不变

--runtime-config=flowcontrol.apiserver.k8s.io/v1alpha1=true 启用 API 组的 v1alpha1 版本。

另外,设置命令行标志 --enable-priority-fairness=false 将彻底禁用 APF 特性,此时即使设置其他标志启用 APF 也是无效的。

总结

APF 采用的方式是先将请求根据 user/resource/namespace 进行隔离,隔离之后的每组都会绑定相应的优先级。不同优先级的请求具有不同的并发限制,并且不会互相影响。隔离之后的每组请求又可能根据 namespace 等信息划分到不同的 queue 中。在从一个优先级中取请求的时候,它会采用公平算法选择一个 queue,然后从这个 queue 中取出最老的请求进行处理。

举个例子,比如将来自 scheduler 的请求进行隔离,并且都绑定到一个优先级中。由于该优先级会分配到一定的并发数,因此 scheduler 的并发数就受到这个优先级的限制,但是不会影响其他请求。同时对于都来自 scheduler 的请求,可能又会按照 namespace 进行区分,分到不同 queue 中,对于同一优先级中的请求,每次它是选择一个 queue,然后取出一个请求,又避免了同一个优先级中的请求隔离的问题。

简单来说的话,其实就是先将请求分成大类,然后再从大类中分出小类。大类本身就有隔离,而小类在隔离的基础之上再进行隔离。

其他限流方式

Client 限流

client-go默认的qps为5,但是只支持客户端限流,集群管理员无法控制用户行为。

EventRateLimit 限流

EventRateLimit在1.13之后支持,只限制event请求,集成在apiserver内部webhoook中,可配置某个用户、namespace、server等event操作限制,通过webhook形式实现。

具体原理可以参考提案,每个eventratelimit 配置使用一个单独的令牌桶限速器,每次event操作,遍历每个匹配的限速器检查是否能获取令牌,如果可以允许请求,否则返回429。

卷死我
dawnguo 微信支付

微信支付

dawnguo 支付宝

支付宝

  • 本文作者: dawnguo
  • 本文链接: /archives/250
  • 版权声明: 本博客所有文章除特别声明外,均采用CC BY-NC-SA 3.0 许可协议。转载请注明出处!
# Kubernetes
Kubernetes APIServer-审计
Kubernetes APIServer-RBAC
  • 文章目录
  • 站点概览
dawnguo

dawnguo

215 日志
24 分类
37 标签
RSS
Creative Commons
© 2018 — 2025 程序锅
0%