Azure Kubernetes 服务 (AKS) 中大型工作负载的性能和缩放最佳做法

注释

本文重点介绍了“大型工作负载”的一般最佳做法。 有关特定于“中小型工作负载”的最佳做法,请参阅 Azure Kubernetes 服务 (AKS) 中的中小型工作负载的性能和缩放最佳做法

在 AKS 中部署和维护群集时,可以使用以下最佳做法来帮助优化性能和缩放。

请记住,“大”是一个相对的术语。 Kubernetes 具有多维度的缩放范围,而工作负载的缩放范围取决于你使用的资源。 例如,具有 100 个节点和数千个 Pod 或 CRD 的群集可能被认为是大群集。 而从控制平面的角度来看,1,000 个节点的群集具有 1,000 个 Pod 和其他各种资源可能被认为是小群集。 Kubernetes 控制平面的最佳缩放信号是 API 服务器 HTTP 请求成功率和延迟,因为它是控制平面负载量的代理。

在本文中,你将了解:

  • 节点扩容
  • AKS 和 Kubernetes 控制平面可伸缩性。
  • Kubernetes 客户端最佳做法,包括退避、监视和分页。
  • Azure API 和平台带宽限制。
  • 功能限制。
  • 网络最佳做法。

节点缩放

将 AKS 群集缩放到更大的缩放点时,请记住以下节点缩放最佳做法:

  • 在大规模 AKS 群集运行时,请尽可能使用 群集自动缩放程序节点自动预配 ,以确保根据计算资源的需求动态缩放节点。
  • 如果在不使用群集自动缩放程序的情况下缩放到超过 1000 个节点,我们建议一次最多分批缩放 500 到 700 个节点。 这些缩放操作应在纵向扩展操作之间有两到五分钟的等待时间,以避免受到 Azure API 带宽限制。 有关详细信息,请参阅 API 管理:缓存和带宽限制策略
  • 对于系统节点池,请使用“Standard_D16ds_v5”SKU 或等效的具有临时 OS 磁盘的核心/内存 VM SKU,为 kube-system Pod 提供足够的计算资源。
  • 由于 AKS 对每个节点池的节点数限制为 1000 个,因此我们建议至少创建五个用户节点池以纵向扩展到 5000 个节点。

AKS 和 Kubernetes 控制平面可伸缩性

在 Kubernetes 中,群集中运行的所有对象都由控制平面管理,由 AKS 管理。 虽然 AKS 优化了 Kubernetes 控制平面及其组件,用以实现可伸缩性和性能优化,但其仍受到上游项目限制的约束。

Kubernetes 具有多维扩展框架,每种资源类型都代表一个维度,并且并非所有资源在开销上都相同。 例如,Secrets 通常由多个控制器和 Pod 进行监视,每个都会进行初始的 LIST 调用以同步状态。 由于机密通常很大且经常更新,因此它们在控制平面上会比那些不常被监视的资源施加更多负载。

在一个维度中扩展群集越多,就越难在其他维度中进行扩展。 例如,在 AKS 群集中运行数十万个 Pod 会影响控制平面支持的 Pod 流失率(每秒 Pod 突变数)的多少。

AKS 支持三个控制平面层作为基本 SKU 的一部分:免费层、标准层和高级层。 有关详细信息,请参阅 AKS 群集管理的免费、标准和高级定价层

重要

对生产或大规模工作负荷使用标准层或高级层。 AKS 会自动纵向扩展 Kubernetes 控制平面以支持以下缩放限制:

  • 每个 AKS 群集最多有 5,000 个节点
  • 每个 AKS 群集有 200,000 个 Pod(使用 Azure CNI 覆盖)

在大多数情况下,超过缩放限制阈值会导致性能下降,但不会导致群集立即进行故障转移。 若要管理 Kubernetes 控制平面上的负载,请考虑按批次缩放,最大缩放比例为当前缩放的 10-20%。 例如,对于 5,000 个节点的群集,按增量缩放 500-1,000 个节点。 虽然 AKS 可以自动缩放控制平面,但它不会立即发生。

若要确认控制平面是否已扩容,请查找 configmap large-cluster-control-plane-scaling-status

kubectl describe configmap large-cluster-control-plane-scaling-status -n kube-system

Kubernetes 扩展范围与控制平面事项

Kubernetes 客户端是应用程序组件(例如操作员或监视代理),在群集中运行,并与 kube-apiserver 通信以读取或修改资源。 必须优化这些客户端的行为方式,以减少它们在 kube-apiserver 和 Kubernetes 控制平面上放置的负载。

API 服务器在任何给定时刻主动处理的请求数量是由 --max-requests-inflight--max-mutating-requests-inflight 标志决定的。 AKS 对这些标志使用 400 个和 200 个请求的默认值,允许在给定时间调度总共 600 个请求。 当我们将 API 服务器扩展到更大规模时,我们也会相应地增加未决请求。

两种 Kubernetes 对象类型 (PriorityLevelConfiguration 和 FlowSchema (APF)确定 API 服务器如何跨请求类型划分请求总容量。 AKS 使用默认配置。

每个 PriorityLevelConfiguration 都被分配了一部分允许的请求份额。 若要查看群集中的 PriorityLevelConfiguration 对象及其分配的请求共享,请运行以下命令。

kubectl get --raw /metrics | grep apiserver_flowcontrol_nominal_limit_seats

FlowSchema 将 API 服务器请求映射到 PriorityLevelConfiguration。 如果多个 FlowSchema 对象与请求匹配,则 API 服务器将选择具有最低匹配优先级的流对象。

可以使用以下命令查看 FlowSchemas 到 PriorityLevelConfigurations 的映射:

kubectl get flowschemas

若要确认是否由于 APF 而删除了任何请求,请运行以下命令:

kubectl get --raw /metrics | grep apiserver_flowcontrol_rejected_requests_total

Kubernetes 客户端最佳做法

未优化客户端发出的 LIST 调用通常是限制群集可伸缩性的最大因素之一。 当处理可能包含数千个小型对象或超过几百个大型对象的列表时,应考虑以下准则:

  • 在定义新资源类型 (CRD) 时,请考虑最终期望存在的对象数 (CR)。
  • etcd 和 API 服务器上的负载主要依赖于响应的大小。 本指南适用于客户端是针对大型对象发出少量 LIST 请求,还是针对较小的对象发出大量 LIST 请求。

使用信息器

  • 如果代码需要维护内存中对象的更新列表,则使用客户端访问库中的 通知器 可让你根据事件而不是轮询更改来监视资源更改的好处。 这是避免未优化且重复的 LIST 的最佳方法。

使用 API 服务器缓存

  • 使用 resourceVersion=0 从 API 服务器缓存中返回结果。 这可以防止从 etcd 中提取对象,从而减少 etcd 加载, 但不支持分页

    /api/v1/namespaces/default/pods?resourceVersion=0
    

高效的 Kubernetes API 使用情况

  • 建议尽可能使用 watch 参数。 如果没有参数,默认行为是列出对象。 请参阅以下示例。

    /api/v1/namespaces/default/pods?watch=true
    

    使用具有resourceVersion的监视器,将其设置为从前面的列表或监视器接收到的最新已知值。 这是在 client-go 中自动完成处理的。 但是,请验证你是否使用其他语言的 Kubernetes 客户端。

    /api/v1/namespaces/default/pods?watch=true&resourceVersion=<resourceversion>
    
  • 如果控制器或操作员必须使用 LIST 调用,则应避免在没有标签或字段选择器的情况下轮询群集范围资源,尤其是在大型群集中。 以下示例演示优化和未优化的 LIST 调用。

    优化列表:

    /api/v1/namespaces/default/pods?fieldSelector=status.phase=Running
    

    未优化的列表:

    /api/v1/pods
    
  • 如果客户端必须从 etcd 提取数据,请使用分页来减小 LIST 响应的大小。 以下示例使用 limit 参数将响应限制为 100 个对象。

    /api/v1/namespaces/default/pods?fieldSelector=status.phase=Running&limit=100
    

    如果希望 LIST 继续返回上述示例中的所有 Pod 对象,请使用具有限制的 continue 参数。

    /api/v1/namespaces/default/pods?fieldSelector=status.phase=Running&limit=100&continue=<continue_token>
    

    如果正在使用 kubectl, --chunk-size 则可以将参数直接应用于分页响应。

    kubectl get pods -n default --chunk-size=100
    
  • 如果您的控制器或操作员使用租约更新进行领导选举,请通过调优 leaseDurationrenewDeadlineretryPeriod 来确保它们能在暂时性连接问题中具有弹性,并能够最适合您的工作负荷。 对于使用客户端引导式领导人选举的 Kubernetes 控制器,请使用以下公式:

    lease_duration > renew_deadline > retry_period
    

守护程序集

  • 单个控制器列出对象和在每个节点上运行的 DaemonSet 执行相同的操作之间存在显著差异。 如果客户端应用程序的多个实例定期列出大量对象,则解决方案在大型群集中不会很好地缩放。

  • 在具有数千个节点的群集上,创建新的 DaemonSet、更新 DaemonSet 或增加节点数可能会导致在控制平面上放置高负载。 如果 DaemonSet Pod 在 Pod 启动时发出昂贵的 API 服务器请求,则它们可能会导致大量并发请求在控制平面上使用大量资源。

  • 使用 RollingUpdate 策略逐步推出新的 DaemonSet pod。 更新 DaemonSet 模板后,控制器会以受控方式将旧 Pod 替换为新 Pod。 如果未显式配置滚动更新策略,Kubernetes 将默认创建 maxUnavailable 为 1、maxSurge 为 0、minReadySeconds 为 0 的 RollingUpdate。 请参阅以下示例。

      minReadySeconds: 30
      updateStrategy:
        type: RollingUpdate
        rollingUpdate:
          maxSurge: 0
          maxUnavailable: 1
    
  • RollingUpdate 策略仅适用于现有的 DaemonSet Pod。 它不会限制添加新节点(这将创建其他 DaemonSet Pod 或部署全新的 DaemonSets)的影响。

  • 若要在节点横向扩展或新的 DaemonSet 部署后防止 DaemonSet 在启动时同时向 API 服务器发送 LIST 请求,请在容器启动时引入抖动,并为 5xx 或 429 响应配置适当的 指数回退重试策略,以防止对大型 LIST 请求进行重复重试。

      spec:
        template:
          spec:
            containers:
            - name: my-daemonset-container
              image: <image>
              command: ["/bin/sh", "-c", "sleep $(( (RANDOM % 60) + 1 )); exec /path/to/your/app --args"]
    

注释

你可以通过 Kube 审核日志来分析 API 服务器流量和客户端行为。 有关详细信息,请参阅 Kubernetes 控制平面故障排除

etcd 优化

  • 保持整体 etcd 大小较小,不要将 etcd 用作常规用途数据库。 AKS 默认提供 8 GB 的 etcd 存储,但较大的 etcd 数据库会增加碎片整理时间,这可能会导致读取和写入性能问题。 如果未优化客户端频繁从 etcd 提取大量对象,则较大的 etcd 数据库还可以增加 API 服务器和 etcd 可靠性问题的概率。 如果 etcd 数据库大小超过 2 GB,请考虑使用下面列出的对象大小缩减技术。
  • 若要减少 Pod 规范大小,请将环境变量从 Pod 规范移动到 ConfigMaps。
  • 将大型机密或 ConfigMap 拆分为更小、更易于管理的部分。
  • 将机密存储在 Azure 密钥保管库 而不是 Kubernetes 机密中,尽可能减少存储在 etcd 中的机密数。
  • 清理未使用的对象
    • 删除过时的任务和已完成的 Pod。 在作业上使用 ttlSecondsAfterFinished,以便自动删除完成的对象。
    • 确保控制器设置所有者引用。 这使 Kubernetes 垃圾回收能够在删除父资源时自动删除依赖对象。
    • 通过设置 successfulJobsHistoryLimit 和 failedJobsHistoryLimit 来限制 CronJob 历史记录,以仅保留少量已完成的作业记录。
    • 缩减部署发布历史记录。 旧 ReplicaSet 也存储为 API 对象。 默认值为 10。
  • 使用 --history-max 参数减少 Helm 修订历史记录。 在大型群集中,使其保持在 5 以下。

关键控制平面平台指标

AKS 在Azure Monitor中公开以下平台指标,用于监视 API 服务器和 etcd 运行状况。 这些指标在未启用托管 Prometheus 的情况下可用,可以直接在 AKS 群集的 Metrics 下的 Azure 门户中查看。

API 服务器指标:

Metric Description
apiserver_cpu_usage_percentage API 服务器 Pod 跨实例使用的最大 CPU 百分比(基于当前限制)。
apiserver_memory_usage_percentage API 服务器 Pod 跨实例使用的最大内存百分比(基于当前限制)。
apiserver_current_inflight_requests (预览版) API 服务器上当前处于活动状态的飞行请求数上限,每个请求类型。

Etcd 指标:

Metric Description
etcd_cpu_usage_percentage etcd Pod 跨实例使用的最大 CPU 百分比(基于当前限制)。
etcd_memory_usage_percentage etcd Pod 跨实例使用的最大内存百分比(基于当前限制)。
etcd_database_usage_percentage 不同实例之间的最大 etcd 数据库利用率。 密切监视此情况,以避免超出 etcd 存储限制。

一致地监视 apiserver_cpu_usage_percentageapiserver_memory_usage_percentage 检测 API 服务器上的资源压力。 如果 etcd_database_usage_percentage 一直高于 50%,请查看 Etcd 优化 部分以减少数据库大小。 有关可用指标的完整列表,请参阅 AKS 监视数据参考

功能限制

将 AKS 群集缩放到更大的规模点时,请记住以下功能限制:

  • 默认情况下,AKS 支持为所有标准层/LTS 群集扩展到最多 5,000 个节点。 AKS 根据群集大小和 API 服务器资源利用率在运行时缩放群集的控制平面。 若要帮助排查缩放性能或可靠性问题,请参阅以下资源:

    注释

    在缩放控制平面的操作期间,可能会遇到 API 服务器延迟增加或超时长达 15 分钟的情况。 如果在缩放到支持的限制时始终存在问题,请提交支持工单

  • Azure 网络策略管理器 (Azure npm) 最多支持 250 个节点。

  • 在纵向扩展控制平面后,某些 AKS 节点指标(包括节点磁盘使用情况、节点 CPU/内存使用情况和网络传入/传出)无法在 Azure 监视平台指标访问。

  • 对于具有 100 个以上节点的群集,不能使用“停止”和“启动”功能。 有关详细信息,请参阅停止和启动 AKS 群集

Azure API 和平台限流

云应用程序上的负载可能随着时间的推移而变化,这取决于活动用户数或用户执行的操作类型等因素。 如果系统的处理要求超过可用资源的容量,则系统可能会过载,导致性能下降和故障。

若要在云应用程序中处理不同负载大小,可以允许应用程序使用最多指定限制的资源,然后在达到限制时对其进行限制。 在 Azure 上,带宽限制在两个级别发生。 Azure 资源管理器 (ARM) 限制对订阅和租户的请求。 如果请求低于订阅和租户的带宽限制阈值,ARM 会将该请求路由到资源提供程序。 然后,资源提供程序将应用针对其操作定制的带宽限制。 有关详细信息,请参阅 ARM 带宽限制请求

管理 AKS 中的带宽限制

Azure API 限制通常在订阅区域组合级别上定义。 例如,给定区域中订阅的所有客户端共享指定 Azure API(例如虚拟机规模集 PUT API)的 API 限制。 每个 AKS 群集都有多个 AKS 拥有的客户端,例如云提供商或群集自动缩放程序,或客户拥有的客户端,例如 Datadog 或自托管 Prometheus,它们都可调用 Azure API。 在给定区域内的订阅中运行多个 AKS 群集时,群集内所有 AKS 拥有的和客户拥有的客户端共享一组常见的 API 限制。 因此,可以在订阅区域中部署的群集数取决于已部署的客户端数、其调用模式以及群集的总体规模和弹性。

请记住上述的注意事项,客户通常能够在每个订阅区域部署 20-40 个中小型群集。 可以使用以下最佳做法使订阅规模最大化:

始终将 Kubernetes 群集升级到最新版本。 较新版本包含许多改进,可解决性能和带宽限制方面的问题。 如果使用已升级版本的 Kubernetes,但由于实际负载或订阅中的客户端数而导致仍然看到带宽限制,可以尝试以下选项:

  • 使用 AKS 诊断和解决问题分析错误:可以使用 AKS 诊断和解决问题 来分析错误、识别根本原因并获取解决方法建议。
    • 增加群集自动缩放程序扫描间隔:如果诊断报告显示检测到群集自动缩放程序带宽限制,则可以增加扫描间隔以减少从群集自动缩放程序调用虚拟机规模集的次数。
    • 重新配置第三方应用程序以减少调用:如果在“查看请求速率和限制详情”诊断中根据“用户代理”进行筛选,并看到第三方应用程序(如监视应用程序)发出大量 GET 请求,则可以更改这些应用程序的设置以减少 GET 调用的频率。 在调用 Azure API 时,确保应用程序客户端使用指数退避。
  • 将群集拆分为不同的订阅或区域:如果有大量使用虚拟机规模集的群集和节点池,则可以将它们拆分为不同的订阅或同一订阅中的不同区域。 大多数 Azure API 限制在订阅区域级别共享,因此可以将群集移动或缩放到不同的订阅或区域,以便解除 Azure API 带宽限制阻止。 如果希望群集具有高活动性,此选项特别有用。 这些限制没有通用准则。 如果想要特定指导,可以创建支持票证。

网络

将 AKS 群集缩放到更大的规模点时,请记住以下网络最佳做法:

  • 对群集流出量使用托管 NAT,并且 NAT 网关上至少有 2 个公共 IP。 有关详细信息,请参阅为 AKS 群集创建托管 NAT 网关

  • 如果使用 Azure 标准负载均衡器,请至少使用 2 个出站公共 IP。 此外,在规划大型群集时,请考虑 LoadBalancer 服务后端规则限制。 Azure标准负载均衡器每个前端 IP 最多支持 10,000 个后端 IP 配置。 每种类型:LoadBalancer 服务为每个公开的端口创建一个负载均衡规则,并将所有群集节点与负载均衡器后端池相关联。 例如,为单个服务公开 5 个端口将在 2000 个节点时达到此限制。

    1 service * 5 ports * 2000 nodes = 10000 backend IP configurations
    
  • 使用 Azure CNI 覆盖以纵向扩展到每个群集的 200,000 个 Pod 和 5,000 个节点。 有关详细信息,请参阅在 AKS 中配置 Azure CNI 覆盖网络

  • 如果应用程序需要跨群集的直接 Pod 到 Pod 通信,请使用具有动态 IP 分配的 Azure CNI,并纵向扩展到每个群集 50,000 个应用程序 Pod,并且每个 Pod 有一个可路由 IP。 有关详细信息,请参阅为 AKS 中的动态 IP 分配配置 Azure CNI 网络

  • 在内部负载均衡器后面使用内部 Kubernetes 服务时,建议创建一个低于 750 节点规模的内部负载均衡器或服务,以获得最佳的缩放性能和负载均衡器弹性。

  • Azure网络策略管理器(NPM)最多支持 250 个节点。 若要为较大的群集强制实施网络策略,请考虑使用由 Cilium 提供支持的 Azure CNI,它将 Azure CNI 的可靠控制平面与 Cilium 数据平面相结合,以提供高性能的网络和安全性。

  • 在节点池上启用 LocalDNS ,以减少 DNS 解析延迟并卸载集中式 CoreDNS Pod。 在具有高 DNS 查询卷的大型群集中,集中式 DNS 解析可能会成为瓶颈。 LocalDNS 在每个节点上部署 DNS 代理即 systemd 服务,在本地解析查询,消除 conntrack 表压力,并升级与 TCP 的连接以避免 conntrack 争用情况。 LocalDNS 还支持在上游 DNS 不可用时提供过时缓存的响应,从而在暂时性故障期间提高工作负荷复原能力。 有关详细信息,请参阅 AKS 中的 DNS 解析

群集升级注意事项和最佳做法

  • 当群集达到 5,000 个节点限制时,会阻止群集升级。 此限制会阻止升级,因为最大激增属性限制中没有可用的节点容量执行滚动更新。 如果你的群集达到此限制,建议在尝试群集升级之前将群集缩减为 3,000 个节点以下。 这将为节点变动提供额外的容量,并最大限度地减少控制平面上的负载。
  • 升级节点超过 500 个节点的群集时,建议使用节点池容量 的最大激增配置 为 10-20%。 AKS 会将升级配置为使用最大激增的默认值 (10%)。 可以为每个节点池自定义最大激增设置,以便在升级速度与工作负载中断之间进行权衡。 增加最大激增设置时,升级过程会更快完成,但在升级过程中可能会遇到中断。 更多信息,请参阅自定义节点激增升级
  • 有关群集升级的详细信息,请参阅 升级 AKS 群集