本文发表已超过一年。较旧的文章可能包含过时内容。请检查页面中的信息自发布以来是否仍然准确。

API 优先级与公平性 Alpha

本博客介绍了 Kubernetes 1.18 中一个新的 Alpha 特性:“API 优先级与公平性”。API 优先级与公平性允许集群管理员将控制平面的并发能力划分为不同的加权优先级级别。到达 kube-apiserver 的每个请求都将被归类到其中一个优先级级别,并获得该控制平面吞吐量的公平份额。

这解决了什么问题?

目前,apiserver 有一个简单的机制来保护自身免受 CPU 和内存过载:对可变和只读请求设置最大并发数限制。除了可变和只读的区别外,请求之间没有其他区别;因此,可能会出现不受欢迎的情况,即一部分请求挤占了其他请求。

简而言之,Kubernetes 工作负载很容易意外地对 apiserver 进行 DoS 攻击,导致其他重要流量——例如系统控制器或领导者选举——间歇性失败。在最糟糕的情况下,少数故障节点或控制器可以将繁忙的集群推向崩溃边缘,将局部问题变成控制平面中断。

我们如何解决这个问题?

新特性“API 优先级与公平性”旨在泛化每个 apiserver 中现有的最大并发请求处理机制,使其行为更加智能和可配置。总体方法如下。

  1. 每个请求都由一个 Flow Schema 进行匹配。Flow Schema 指定了匹配请求的优先级级别,并为这些请求分配一个“流标识符”。流标识符是系统判断请求是否来自同一来源的方式。
  2. 优先级级别可以配置为多种行为。每个优先级级别都有自己独立的并发池。优先级级别还引入了将无法立即处理的请求进行排队的概念。
  3. 为了防止任何单个用户或命名空间垄断某个优先级级别,可以将它们配置为拥有多个队列。“乱序分片 (Shuffle Sharding)” 用于将每个请求流分配到队列的一个子集。
  4. 最后,当有容量处理请求时,使用“公平排队”算法来选择下一个请求。在每个优先级级别内,队列之间以均等公平的方式竞争。

早期结果非常有希望!请查看这篇分析

我如何尝试这个特性?

要尝试此特性,你需要准备以下内容

  • 下载并安装 v1.18.0 版本或更高的 kubectl
  • 在 kube-apiserver 上使用命令行标志 --runtime-config="flowcontrol.apiserver.k8s.io/v1alpha1=true" 启用新的 API 组
  • 在 kube-apiserver 上使用命令行标志 --feature-gates=APIPriorityAndFairness=true" 开启特性门控

成功启动 kube-apiserver 后,你将在集群中看到一些默认的 FlowSchema 和 PriorityLevelConfiguration 资源。这些默认配置旨在为集群提供一般的保护和流量管理。你可以通过运行常用工具来检查和自定义默认配置,例如:

  • kubectl get flowschemas
  • kubectl get prioritylevelconfigurations

这个特性内部如何工作?

请求到达处理程序后,将被精确地分配到一个优先级级别和该优先级级别内的精确一个流。因此,理解 FlowSchema 和 PriorityLevelConfiguration 如何工作将有助于你管理通过 kube-apiserver 的请求流量。

  • FlowSchema:FlowSchema 将识别一个 PriorityLevelConfiguration 对象,并计算请求的“流标识符”。目前我们支持根据以下信息匹配请求:发出请求的身份、动词和目标对象。身份可以匹配用户名、用户组名或 ServiceAccount。对于目标对象,我们可以按 apiGroup、resource[/subresource] 和 namespace 进行匹配。

    • 流标识符用于乱序分片,因此如果请求来自同一来源,拥有相同的流标识符非常重要!我们喜欢考虑“大象”(发送许多/重量级请求)与“老鼠”(发送少量/轻量级请求)的场景:确保大象的所有请求都获得相同的流标识符非常重要,否则它们在系统看来就像许多不同的老鼠!
    • 请参阅此处的 API 文档!
  • PriorityLevelConfiguration:定义一个优先级级别。

    • 对于 apiserver 自身的请求以及任何重入流量(例如,自身发出 API 请求的准入 Webhook),可以将优先级级别标记为“豁免”,这意味着不会进行任何形式的排队或限制。这是为了防止优先级反转。
    • 每个非豁免优先级级别都配置了若干“并发份额”,并获得一个独立的并发池供其使用。当池未满时,该优先级级别的请求在该池中运行,绝不在其他地方运行。每个 apiserver 配置了一个总并发限制(即旧的针对可变和只读请求的限制之和),然后根据优先级级别的并发份额比例将其分配给各个优先级级别。
    • 非豁免优先级级别可以选择用于乱序分片的队列数量和“手牌大小 (hand size)”。乱序分片以一种优于一致性哈希的方式将流映射到队列。给定的流可以访问一小组队列,对于每个传入请求,选择最短的队列。当一个优先级级别拥有队列时,它还会设置一个队列长度限制。此外,还限制了请求在队列中等待的时间;这是 apiserver 请求超时的一个固定比例。无法执行且无法(再)排队的请求将被拒绝。
    • 或者,非豁免优先级级别可以选择立即拒绝,而不是在队列中等待。
    • 请参阅此特性的API 文档

还缺少什么?何时会有 Beta 版本?

我们已经在计划基于 Alpha 版本进行一些增强,并且随着用户向社区发送反馈,还会有更多增强。以下是增强列表:

  • WATCH 和 EXEC 请求的流量管理
  • 调整和改进默认的 FlowSchema/PriorityLevelConfiguration 集
  • 增强对此特性工作方式的可观测性
  • 加入此处的讨论

根据 LIST 请求结果大小的估计,可能以不同方式处理 LIST 请求。

我如何参与?

一如既往!可以通过 Slack #sig-api-machinery 或通过邮件列表联系我们。我们有很多令人兴奋的特性要构建,需要各种帮助。

非常感谢为这一特性做出贡献的贡献者:Aaron Prindle, Daniel Smith, Jonathan Tomer, Mike Spreitzer, Min Kim, Bruce Ma, Yu Liao, Mengyi Zhou!