

本文属于机器翻译版本。若本译文内容与英语原文存在差异，则一律以英文原文为准。

# Kubernetes 上游 SLOs
<a name="kubernetes_upstream_slos"></a>

Amazon EKS 运行的代码与上游 Kubernetes 版本相同，并确保 EKS 集群在 Kubernetes 社区 SLOs 定义的范围内运行。Kubernetes [可扩展性特别兴趣小组 (SIG)](https://github.com/kubernetes/community/tree/master/sig-scalability) 定义了可扩展性目标，并通过和调查性能瓶颈。 SLIs SLOs

SLIs 是我们衡量系统的方式，例如可用于确定系统运行的 “良好” 的指标或衡量标准，例如请求延迟或计数。 SLOs 定义系统运行 “良好” 时的预期值，例如请求延迟保持在 3 秒以内。Kubernetes SLOs SLIs 侧重于 Kubernetes 组件的性能，完全独立于注重 EKS 集群终端节点可用性的亚马逊 EKS 服务 SLAs 。

Kubernetes 具有许多功能，允许用户使用自定义插件或驱动程序扩展系统，例如 CSI 驱动程序、准入 webhook 和自动缩放器。这些扩展可能会以不同的方式极大地影响 Kubernetes 集群的性能，也就是说，如果 webhook 目标不可用，则带有准入 webhook 的 webhook `failurePolicy=Ignore` 可能会增加 K8s API 请求的延迟。Kubernetes 可扩展性 SIG 使用 [“你承诺，我们承诺](https://github.com/kubernetes/community/blob/master/sig-scalability/slos/slos.md#how-we-define-scalability)” 的框架来定义可扩展性：

如果您承诺：-正确配置您的集群-“合理” 使用可扩展性功能-将集群中的负载保持在[建议](https://github.com/kubernetes/community/blob/master/sig-scalability/configs-and-limits/thresholds.md)的限制之内 

那么我们保证你的集群会扩展，即：-所有 SLOs 都得到满足。

## Kubernetes SLOs
<a name="_kubernetes_slos"></a>

Kubernetes SLOs 没有考虑到所有可能影响集群的插件和外部限制，例如工作节点扩展或准入 webhook。它们 SLOs 侧重于 [Kubernetes 组件](https://kubernetes.io/docs/concepts/overview/components/)，并确保 Kubernetes 的操作和资源按预期运行。它们 SLOs 可以帮助 Kubernetes 开发人员确保对 Kubernetes 代码的更改不会降低整个系统的性能。

[Kuberntes 可扩展性 SIG 定义了以下官方](https://github.com/kubernetes/community/blob/master/sig-scalability/slos/slos.md) SLO/。SLIsAmazon EKS 团队定期在 EKS 集群上运行可扩展性测试， SLOs/SLIs 以监控随着更改和新版本发布而出现的性能下降。


| 目标 | 定义 | SLO | 
| --- | --- | --- | 
|  API 请求延迟（变更）  |  处理每对（资源、动词）的单个对象的变异 API 调用的延迟，以过去 5 分钟内的第 99 个百分位数来衡量  |  在默认的 Kubernetes 安装中，对于每对（资源、动词），不包括虚拟资源和聚合资源以及自定义资源定义，每个集群日的第 99 个百分位数 <= 1s  | 
|  API 请求延迟（只读）  |  处理每个（资源、范围）对的非流式只读 API 调用的延迟，以过去 5 分钟内的第 99 个百分位数来衡量  |  在默认 Kubernetes 安装中，对于每对（资源、范围），不包括虚拟和聚合资源以及自定义资源定义，每个集群日的第 99 个百分位数：(a) 如果 (b) <= 1s 否则为 <= 30s`scope=resource`（如果或）`scope=namespace``scope=cluster`  | 
|  Pod 启动延迟  |  可调度的无状态 pod 的启动延迟，不包括拉取镜像和运行 init 容器的时间，从 pod 创建时间戳到所有容器都报告为已启动并通过 watch 观察的时间来衡量，以过去 5 分钟内的第 99 个百分位数来衡量  |  在默认的 Kubernetes 安装中，每个集群日的第 99 个百分位数 <= 5s  | 

### API 请求延迟
<a name="_api_request_latency"></a>

`kube-apiserver`已`--request-timeout`定义为`1m0s`默认值，这意味着请求最多可以运行一分钟（60 秒），然后才会被超时和取消。L SLOs atency 的定义按正在发出的请求类型进行细分，可以是变异请求或只读请求：

#### 变异
<a name="_mutating"></a>

Kubernetes 中的变异请求会对资源进行更改，例如创建、删除或更新。这些请求非常昂贵，因为在返回更新的对象之前，必须将这些更改写入 [etcd 后端](https://kubernetes.io/docs/concepts/overview/components/#etcd)。[Etcd](https://etcd.io/) 是一种分布式键值存储，用于所有 Kubernetes 集群数据。

这种延迟是以 Kubernetes 资源对（资源、动词）在 5 分钟内的第 99 个百分位来衡量的，例如，这将衡量 Create Pod 请求和更新节点请求的延迟。请求延迟必须为 <= 1 秒才能满足 SLO。

#### Read-only
<a name="_read_only"></a>

只读请求会检索单个资源（例如 Get Pod X）或集合（例如 “从命名空间 X 获取所有 Pod”）。`kube-apiserver`维护对象的缓存，因此可以从缓存中返回请求的资源，或者可能需要先从 etcd 中检索它们。这些延迟也是以 5 分钟内的第 99 个百分位数来衡量的，但是只读请求可以有不同的范围。SLO 定义了两个不同的目标：
+ 对于针对*单个*资源（即`kubectl get pod -n mynamespace my-controller-xxx`）发出的请求，请求延迟应保持 <= 1 秒。
+ 对于对命名空间或集群（例如`kubectl get pods -A`）中的多个资源发出的请求，延迟应保持 <= 30 秒

对于不同的请求范围，SLO 具有不同的目标值，因为对 Kubernetes 资源列表发出的请求需要在 SLO 中返回请求中所有对象的详细信息。在大型集群或大型资源集合上，这可能会导致响应大小过大，可能需要一些时间才能返回。例如，在运行成千上万个 Pod 且每个 Pod 以 JSON 编码时大约 1 KiB 的集群中，返回集群中的所有 Pod 将包含 10MB 或更多。Kubernetes 客户端可以使用分[ APIList块检索大量资源来帮助缩小响应大](https://kubernetes.io/docs/reference/using-api/api-concepts/#retrieving-large-results-sets-in-chunks)小。

### Pod 启动延迟
<a name="_pod_startup_latency"></a>

这个 SLO 主要关注从 Pod 创建 Pod 到该 Pod 中的容器实际开始执行所花费的时间。为了衡量这一点，计算了与 Pod 上记录的创建时间戳以及该 Pod [上的 WAT](https://kubernetes.io/docs/reference/using-api/api-concepts/#efficient-detection-of-changes) CH 报告容器已启动时的差异（不包括容器镜像拉取和初始化容器执行时间）。为了满足 SLO，此 Pod 启动延迟中每个集群日的第 99 个百分位数必须保持 <=5 秒。

请注意，此 SLO 假设此集群中已经存在工作节点，处于可以调度 Pod 的就绪状态。此 SLO 不考虑图像拉取或初始化容器执行，还将测试限制在不利用持久存储插件的 “无状态 pod” 上。

## Kubernetes SLI 指标
<a name="_kubernetes_sli_metrics"></a>

Kubernetes 还通过 SLIs 向随时间跟踪这些指标的 Kubernetes 组件中添加 Prometheus [指标](https://prometheus.io/docs/concepts/data_model/)来改善可观察性。 SLIs 使用 [Prometheus 查询语言 (PromQL)，我们可以构建查询，在 Prom](https://prometheus.io/docs/prometheus/latest/querying/basics/) etheus 或 Grafana 仪表板等工具中显示一段时间内的 SLI 性能，以下是上述的一些示例。 SLOs 

### API 服务器请求延迟
<a name="_api_server_request_latency"></a>


| 指标 | 定义 | 
| --- | --- | 
|  apiserver\$1request\$1sli\$1duration\$1seconds  |  每个动词、组、版本、资源、子资源、范围和组件的响应延迟分布（不包括 webhook 持续时间以及优先级和公平性队列等待时间），以秒为单位。  | 
|  apiserver\$1request\$1持续时间\$1秒  |  每个动词、试运行值、组、版本、资源、子资源、范围和组件的响应延迟分布（以秒为单位）。  | 

**注意**  
该`apiserver_request_sli_duration_seconds`指标从 Kubernetes 1.27 开始可用。

您可以使用这些指标来调查 API 服务器的响应时间以及 Kubernetes 组件或其他插件/组件中是否存在瓶颈。以下查询基于[社区 SLO 控制面板](https://github.com/kubernetes/perf-tests/tree/master/clusterloader2/pkg/prometheus/manifests/dashboards)。

 **API 请求延迟 SLI（变异）**-此时间*不*包括 webhook 的执行或队列中的等待时间。 `histogram_quantile(0.99, sum(rate(apiserver_request_sli_duration_seconds_bucket{verb=~"CREATE|DELETE|PATCH|POST|PUT", subresource!~"proxy|attach|log|exec|portforward"}[5m])) by (resource, subresource, verb, scope, le)) > 0`

 **API 请求延迟总计（变更）**-这是请求在 API 服务器上花费的总时间，此时间可能比 SLI 时间长，因为它包括 webhook 执行以及 API 优先级和公平性等待时间。 `histogram_quantile(0.99, sum(rate(apiserver_request_duration_seconds_bucket{verb=~"CREATE|DELETE|PATCH|POST|PUT", subresource!~"proxy|attach|log|exec|portforward"}[5m])) by (resource, subresource, verb, scope, le)) > 0`

在这些查询中，我们排除了不会立即返回的流式传输 API 请求，例如`kubectl port-forward`或`kubectl exec`请求 (`subresource!~"proxy|attach|log|exec|portforward"`)，并且我们只筛选修改对象的 Kubernetes 动词 ()。`verb=~"CREATE|DELETE|PATCH|POST|PUT"`然后，我们将计算过去 5 分钟内延迟的第 99 个百分位数。

我们可以对只读 API 请求使用类似的查询，我们只需修改要筛选的动词以包含只读操作`LIST`和`GET`。根据请求的范围，也存在不同的 SLO 阈值，即获取单个资源或列出多个资源。

 **API 请求延迟 SLI（只读）**-此时间*不*包括 webhook 的执行或队列中的等待时间。对于单个资源（范围=资源，阈值=1s）`histogram_quantile(0.99, sum(rate(apiserver_request_sli_duration_seconds_bucket{verb=~"GET", scope=~"resource"}[5m])) by (resource, subresource, verb, scope, le))` 

对于同一命名空间中的资源集合（scope=namespace，threshold=5s）`histogram_quantile(0.99, sum(rate(apiserver_request_sli_duration_seconds_bucket{verb=~"LIST", scope=~"namespace"}[5m])) by (resource, subresource, verb, scope, le))` 

对于整个集群中的资源集合（scope=cluster，threshold=30s）`histogram_quantile(0.99, sum(rate(apiserver_request_sli_duration_seconds_bucket{verb=~"LIST", scope=~"cluster"}[5m])) by (resource, subresource, verb, scope, le))` 

 **API 请求延迟总计（只读）**-这是请求在 API 服务器上花费的总时间，此时间可能比 SLI 时间长，因为它包括 webhook 的执行和等待时间。对于单个资源（范围=资源，阈值=1s）`histogram_quantile(0.99, sum(rate(apiserver_request_duration_seconds_bucket{verb=~"GET", scope=~"resource"}[5m])) by (resource, subresource, verb, scope, le))` 

对于同一命名空间中的资源集合（scope=namespace，threshold=5s）`histogram_quantile(0.99, sum(rate(apiserver_request_duration_seconds_bucket{verb=~"LIST", scope=~"namespace"}[5m])) by (resource, subresource, verb, scope, le))` 

对于整个集群中的资源集合（scope=cluster，threshold=30s）`histogram_quantile(0.99, sum(rate(apiserver_request_duration_seconds_bucket{verb=~"LIST", scope=~"cluster"}[5m])) by (resource, subresource, verb, scope, le))` 

SLI 指标通过排除请求在 API 优先级和公平性队列中等待所花费的时间、通过准入 webhook 或其他 Kubernetes 扩展程序运行所花费的时间，从而深入了解 Kubernetes 组件的性能。总指标可以提供更全面的视图，因为它反映了您的应用程序等待 API 服务器响应的时间。比较这些指标可以深入了解请求处理延迟在哪里引入的。

### Pod 启动延迟
<a name="_pod_startup_latency_2"></a>


| 指标 | 定义 | 
| --- | --- | 
|  kubelet\$1pod\$1start\$1sli\$1sli\$1duration\$1seconds  |  启动 Pod 的持续时间（以秒为单位），不包括拉取图像和运行 init 容器的时间，从 pod 创建时间戳到其所有容器都报告为已启动并通过 watch 进行观察的时间进行测量  | 
|  kubelet\$1pod\$1start\$1duration\$1seconds  |  从 kubelet 第一次看到 pod 到 pod 开始运行的持续时间（以秒为单位）。这不包括调度 Pod 或扩展工作节点容量的时间。  | 

**注意**  
 `kubelet_pod_start_sli_duration_seconds`从 Kubernetes 1.27 开始可用。

与上面的查询类似，你可以使用这些指标来深入了解与 Kubelet 操作相比，节点缩放、图像拉取和初始化容器延迟 pod 启动的时间有多长。

 **Pod 启动延迟 SLI-** 这是从创建 Pod 到应用程序容器报告运行的时间。这包括工作节点容量可用和调度 pod 所花费的时间，但这不包括拉取映像或初始化容器运行所花费的时间。 `histogram_quantile(0.99, sum(rate(kubelet_pod_start_sli_duration_seconds_bucket[5m])) by (le))`

 **Pod 启动延迟总计-** 这是 kubelet 首次启动 pod 所花费的时间。这是从 kubelet 通过 WATCH 收到 pod 的时间开始计算的，其中不包括工作节点扩展或调度的时间。这包括拉取映像和初始化容器以供运行的时间。 `histogram_quantile(0.99, sum(rate(kubelet_pod_start_duration_seconds_bucket[5m])) by (le))`

## SLOs 在你的集群上
<a name="_slos_on_your_cluster"></a>

如果您正在从 EKS 集群中的 Kubernetes 资源中收集 Prometheus 指标，则可以更深入地了解 Kubernetes 控制平面组件的性能。

[性能测试存储库包含](https://github.com/kubernetes/perf-tests/) Grafana 仪表板，用于显示测试期间集群的延迟和关键性能指标。性能测试配置利用了配置为收集 Kubernetes 指标的开源项目，但你也可以使用亚马逊[托管 Prometheus 和亚马逊托管](https://aws-observability.github.io/terraform-aws-observability-accelerator/eks/) Grafana。[kube-prometheus-stack](https://github.com/prometheus-community/helm-charts/tree/main/charts/kube-prometheus-stack)

如果您使用的是`kube-prometheus-stack`或类似的 Prometheus 解决方案，则可以安装相同的控制面板来实时观察集群 SLOs 上的情况。

1. 您首先需要安装控制面板中使用的 Prometheus 规则。`kubectl apply -f prometheus-rules.yaml`你可以在这里下载规则的副本：p https://github.com/kubernetes/ erf--tests/blob/master/clusterloader2/pkg/prometheus/manifests/prometheus rules.yaml

   1. 请务必检查文件中的命名空间是否与您的环境相匹配

   1. 如果您使用的是，请验证标签是否与 `prometheus.prometheusSpec.ruleSelector` helm 值匹配 `kube-prometheus-stack` 

1. 然后，您可以在 Grafana 中安装控制面板。这里提供了 json 仪表板和生成它们的 python 脚本： https://github.com/kubernetes/perf-tests/tree/master/clusterloader2/pkg/prometheus/manifests/dashboards

   1.  [`slo.json`控制面板](https://github.com/kubernetes/perf-tests/blob/master/clusterloader2/pkg/prometheus/manifests/dashboards/slo.json)显示集群与 Kubernetes 相关的性能 SLOs

考虑一下， SLOs 它们侧重于集群中 Kubernetes 组件的性能，但是您可以查看其他指标，这些指标可以为集群提供不同的视角或见解。像 [K](https://github.com/kubernetes/kube-state-metrics/tree/main) 这样的 Kubernetes 社区项目ube-state-metrics可以帮助你快速分析集群中的趋势。Kubernetes 社区中大多数常见的插件和驱动程序也会发出 Prometheus 指标，允许你调查诸如自动扩缩程序或自定义调度器之类的内容。

《[可观察性最佳实践指南》提供了](https://aws-observability.github.io/observability-best-practices/guides/containers/oss/eks/best-practices-metrics-collection/#control-plane-metrics)其他 Kubernetes 指标的示例，您可以使用这些指标来获得进一步的见解。