Koordinator 最佳实践系列:精细化 CPU 编排

本文涉及的产品
性能测试 PTS,5000VUM额度
应用实时监控服务-可观测链路OpenTelemetry版,每月50GB免费额度
可观测监控 Prometheus 版,每月50GB免费额度
简介: Koordinator 最佳实践系列:精细化 CPU 编排

作者:乔普、申信


介绍

在云原生环境中,集群提供者常常将不同类型的工作负载部署在同一个集群中,利用不同业务的不同峰值效果,实现资源分时复用,避免资源浪费。然而,不同类型负载之间混合部署常常会导致资源竞争和相互干扰。最为典型的场景便是在线和离线负载的混合部署。当离线较多的占用计算资源时,在线负载的响应时间就会受到影响;当在线长时间较多的占用计算资源时,离线负载的任务完成时间不能得到保证。这种现象属于 Noisy Neighbor 问题。


根据混合部署的程度、资源类型的不同,解决该问题有许多不同的思路。Quota 管理可从整个集群维度限制负载的资源使用量,Koordinator 在这方面提供了多层次弹性 Quota 管理功能[1]。单机维度上看,CPU、内存、磁盘 IO,网络资源都有可能被不同负载共享。Koordinator 在 CPU、内存上已经提供了一些资源隔离和保障的能力,磁盘 IO 和网络资源方面的相关能力正在建设中。


本文主要介绍当不同类型工作负载混合部署在同一个节点上时,Koordinator 如何帮助负载之间(在线和在线、在线和离线)协同地共享 CPU 资源。


问题描述


CPU 资源 Noisy Neighbor 的本质是不同的负载之间无协同地共享 CPU 资源。


  1. Kubernetes 默认的资源模型利用 cgroup(cfs quota) 从 CPU 时间使用量上来限制不同负载对于 CPU 资源的访问。这种情况下,一些负载就可能会被操作系统调度器切换所在的 CPU 核。由于不同 CPU 核对不同物理位置的内存访问时间不同,切换大概率会导致更长的内存访问时间,从而影响负载性能。
  2. 在 NUMA 架构中,SMT 线程(逻辑核)共享物理核的执行单元和 L2 缓存。当同一个物理核中有多种工作负载时,不同工作负载间就会产生资源争抢,导致负载性能下降。


Kubernetes 在单机侧提供了拓扑管理器和 CPU 管理器来尝试解决上述问题。然而,该功能只有在 Pod 已经调度到机器上之后才会尝试生效。这样就有可能导致 Pod 会被调度到 CPU 资源满足但是 CPU 拓扑不满足负载要求的情况。


解决方案


面向应用的 CPU 编排 QoS 语义

针对上述问题和不足,Koordinator 设计了面向应用的 QoS 语义和 CPU 编排协议,如下图所示。

image.png

LS(Latency Sensitive)应用于典型的微服务负载,Koordinator 将其与其它的延迟敏感型负载隔离保障其性能。LSR(Latency Sensitive Reserved)类似于 Kubernetes 的 Guaranteed,在 LS 的基础上增加了应用要求预留绑核的语义。LSE(Latency Sensitive Exclusive)则常见于中间件等对 CPU 特别敏感的应用,Koordinator 除了满足其类似于 LSR 要求绑核的语义外,还确保其所被分配的 CPU 不与任何其它负载共享。


另外,为提高资源利用率,BE 负载可与 LSR 和 LS 共享CPU。为了确保与 BE 共享的延迟敏感型应用不受其干扰,Koordinator 提供了如干扰检测、BE 压制等策略。本文重点不在此,读者可关注后续文章。


丰富的 CPU 编排策略

对于 LSE 类型的应用,当机器是超线程架构时,只能保证负载独占逻辑核。这样当同一个物理核中有其它负载时,应用性能仍会受干扰。为此,Koordinator 支持用户在 Pod Annotation 上配置丰富的 CPU 编排策略来提高性能。


CPU 编排策略分为 CPU 绑定策略和 CPU 独占策略。CPU 绑定策略决定应用所被分配逻辑核在物理核间的分布,可采用物理核间打散或者堆叠。堆叠(FullPCPU)的方式指为应用分配完整的物理内核,可以有效地缓解 Noisy Neighbor 问题。打散(SpreadByPCPU)则主要应用于一些具有多种不同峰谷特性的延迟敏感型应用,可以让应用程序在特定时间充分使用 CPU。CPU 独占策略决定应用所被分配逻辑核的独占级别,可尽量避开已经同独占策略申请的物理核或 NUMANode。


增强的 CPU 调度能力

Koordinator 支持配置 NUMA 的分配策略,决定在调度时如何选择满意的 NUMA 节点。MostAllocated 表示从可用资源最少的 NUMA 节点分配,可以尽可能减少碎片,为后续的负载留下更大的分配空间。但是,这种方式可能会导致依赖 Barrier 的并行代码性能收到影响。DistributeEvenly 表示在 NUMA 节点上平均分配 CPU,可以提高上述并行代码的性能。LeastAllocated 表示从可用资源最多的 NUMA 节点分配。


另外,Koordinator 对 CPU 的分配逻辑是在中心调度器完成的。这样就会有一个全局的视角,避免了 Kubernetes 单机方案可能导致的 CPU 资源量满足但是拓扑不满足的窘境。


最佳实践


由上文可知,Koordinator 精细化 CPU 编排能力能够显著提高多应用混合部署场景下 CPU 敏感型工作负载的性能。为了让读者能够更清楚地使用和直观感受 Koordinator 的精细化 CPU 编排能力,本文将在线应用采用不同方式部署到集群中,观察压测中服务的延迟,来判断 CPU 编排能力的效果。


本文会在同一个机器上部署多个在线应用,压测 10 分钟,以充分模拟生产实践中可能出现的 CPU 核切换场景。对于在线应用和离线应用混合部署的情况,Koordinator 提供了如干扰检测、BE 压制等策略。本文重点不在此,读者可关注后续文章中的实践。



本次实验采用以下指标,评估应用不同部署方式下 Nginx 应用的性能表现:


  • 响应时间 RT(Response Time)分位值RT 是在线应用通常关注的性能指标,RT 越低代表在线服务性能越好。RT 指标通过收集 wrk 压测结束后打印的信息获得,在实验中反映了 Nginx 应用响应 wrk 请求所花费的时间。例如 RT-p50 表示 Nginx 响应前 50% wrk 请求最大所花费的时间(中位数),RT-p90 表示 Nginx 响应前 90% wrk 请求最大所花费的时间。
  • 每秒请求数 RPS(Request Per Second)RPS 是在线应用每秒服务的请求数量,服务承受的 RPS 越多代表在线服务的性能越好。


实验结果如下:

image.png

  • 对比 B 和 A,可以发现采用 LSE QoS 绑核之后,服务响应时间 P99 明显减小,很好地减轻了长尾现象
  • 对比 C 和 B,可以发现采用 LSR QoS 绑核且允许逻辑核占用更多物理核资源之后,在服务响应时间更好的情况下可以承受更多的请求


综上,在线服务部署在同一机器的场景下,采用 koordinator 精细化 CPU 编排能够有效抑制 Noisy Neighbor 问题,减少 CPU 核切换带来的性能下降。


环境

首先,要先准备一个 Kubernetes 集群并安装 Koordinator[2]。本文选择一个 Kubernetes 集群的两个节点来做实验,其中一个节点作为测试机,将运行 Nginx 在线服务器;另一节点作为压测机,将运行客户端的 wrk,向 Nginx 请求 Web 服务,制造压测请求。


在线应用

1. 使用 ColocationProfile[3]为应用注入精细化 CPU 编排协议

B 组精细化 CPU 编排协议:


apiVersion: config.koordinator.sh/v1alpha1
kind: ClusterColocationProfile
metadata:
  name: colocation-profile-example
spec:
  selector:
    matchLabels:
      app: nginx
  # 采用 LSE QoS
  qosClass: LSE
  annotations:
  # 采用物理核间堆叠
    scheduling.koordinator.sh/resource-spec: '{"preferredCPUBindPolicy":"FullPCPUs"}'
  priorityClassName: koord-prod


C 组 CPU 精细化编排协议:


apiVersion: config.koordinator.sh/v1alpha1
kind: ClusterColocationProfile
metadata:
  name: colocation-profile-example
spec:
  selector:
    matchLabels:
      app: nginx
  # 采用 LSR QoS
  qosClass: LSR
  annotations:
  # 采用物理核间打散且独占物理核
    scheduling.koordinator.sh/resource-spec: '{"preferredCPUBindPolicy":"SpreadByPCPUs", "preferredCPUExclusivePolicy":"PCPULevel"}'
  priorityClassName: koord-prod


2. 在线服务本文选用 Nginx 在线服务器,Pod YAML 如下:


---
# nginx应用配置
apiVersion: v1
data:
  config: |-
    user  nginx;
    worker_processes  4; # Nginx的Worker个数,影响Nginx Server的并发。
    events {
        worker_connections  1024;  # 默认值为1024。
    }
    http {
        server {
            listen  8000;
            gzip off;
            gzip_min_length 32;
            gzip_http_version 1.0;
            gzip_comp_level 3;
            gzip_types *;
        }
    }
    #daemon off;
kind: ConfigMap
metadata:
  name: nginx-conf-0
---
# Nginx实例,作为在线类型服务应用。
apiVersion: v1
kind: Pod
metadata:
  labels:
    app: nginx
  name: nginx-0
  namespace: default
spec:
  affinity:
    nodeAffinity:
      requiredDuringSchedulingIgnoredDuringExecution:
        nodeSelectorTerms:
        - matchExpressions:
          - key: kubernetes.io/hostname
            operator: In
            values:
            - "${node_name}"    
  schedulerName: koord-scheduler
  priorityClassName: koord-prod
  containers:
    - image: 'koordinatorsh/nginx:v1.18-koord-exmaple'
      imagePullPolicy: IfNotPresent
      name: nginx
      ports:
        - containerPort: 8000
          hostPort: 8000 # 压测请求访问的端口。
          protocol: TCP
      resources:
        limits:
          cpu: '4'
          memory: 8Gi
        requests:
          cpu: '4'
          memory: 8Gi
      volumeMounts:
        - mountPath: /apps/nginx/conf
          name: config
  hostNetwork: true
  restartPolicy: Never
  volumes:
    - configMap:
        items:
          - key: config
            path: nginx.conf
        name: nginx-conf-0
      name: config


3. 执行以下命令,部署 Nginx 应用


kubectl apply -f nginx-0.yaml


4. 执行以下命令,查看 Nginx 应用的 Pod 状态


kubectl get pod -l app=nginx -o wide


可以看到输出如下,表示 Nginx 应用已经在测试机上正常运行


NAME      READY   STATUS    RESTARTS   AGE     IP           NODE                    NOMINATED NODE   READINESS GATES
nginx-0   1/1     Running   0          2m46s   10.0.0.246   cn-beijing.10.0.0.246   <none>           <none>


5. 在压测机上,执行以下命令,部署压测工具 wrk


wget -O wrk-4.2.0.tar.gz https://github.com/wg/wrk/archive/refs/tags/4.2.0.tar.gz && tar -xvf wrk-4.2.0.tar.gz
cd wrk-4.2.0 && make && chmod +x ./wrk


压测

1. 使用压测工具 wrk,向 Nginx 应用发起压测请求。


# node_ip填写测试机的IP地址,用于wrk向测试机发起压测;8000是Nginx暴露到测试机的端口。
taskset -c 32-45 ./wrk -t120 -c400 -d600s --latency http://${node_ip}:8000/


2. 等待 wrk 运行结束后,获取 wrk 的压测结果,wrk 输出格式如下所示。重复多次测试,以获得相对稳定的结果。


Running 10m test @ http://192.168.0.186:8000/
  120 threads and 400 connections
  Thread Stats   Avg      Stdev     Max   +/- Stdev
    Latency     3.29ms    2.49ms 352.52ms   91.07%
    Req/Sec     0.96k   321.04     3.28k    62.00%
  Latency Distribution
     50%    2.60ms
     75%    3.94ms
     90%    5.55ms
     99%   12.40ms
  68800242 requests in 10.00m, 54.46GB read
Requests/sec: 114648.19
Transfer/sec:     92.93MB


总结


在 Kubernetes 集群中,不同业务负载之间可能存在 CPU、内存等资源的争抢,影响业务的性能和稳定性。面对 Noisy Neighbor 现象,用户可以使用 Koordinator 为应用配置更精细的 CPU 编排策略,使得不同应用可以协同的共享 CPU 资源。我们通过实验说明,Koordinator 的精细化 CPU 编排能力能有效抑制 CPU 资源的争抢,改善应用性能。


非常欢迎你通过 Github/Slack/钉钉/微信 等方式加入我们来参与 Koordinator 开源社区。你是否已经有一些希望与我们社区交流的内容呢?可以通过以下渠道参与讨论:


  • 加入社区 Slack channel (English)
  • 加入社区钉钉群:搜索群号 33383887 (Chinese) 或者扫描下方二维码


相关链接:

[1] 多层次弹性 Quota 管理功能

https://koordinator.sh/docs/user-manuals/multi-hierarchy-elastic-quota-management/

[2] 安装 Koordinator

https://koordinator.sh/docs/installation/

[3] ColocationProfile

https://koordinator.sh/docs/user-manuals/colocation-profile/


点击此处,立即了解 Koordinator 项目!

相关文章
|
Java
[最佳实践] Java线程栈分析 - CPU利用率持续升高
使用应用诊断分析平台ATP的Java线程栈分析功能,诊断CPU利用率持续升高问题
346 0
[最佳实践] Java线程栈分析 - CPU利用率持续升高
|
Cloud Native Linux 应用服务中间件
助力Koordinator云原生单机混部,龙蜥混部技术提升CPU利用率达60%|龙蜥技术
龙蜥社区的三大原生技术为 Koordinator 社区提供了强大的 CPU 混部底层技术支持。
助力Koordinator云原生单机混部,龙蜥混部技术提升CPU利用率达60%|龙蜥技术
|
Kubernetes Cloud Native 安全
Koordinator 0.6:企业级容器调度系统解决方案,引入 CPU 精细编排、资源预留与全新的重调度框架
经过社区多位成员的贡献,Koordinator 0.6 版本正式发布。相较于上一个版本 0.5,新版本进一步完善了 CPU 精细化编排能力,更好的兼容原生用法;支持了资源预留的能力(Reservation),补齐了调度原子语意缺失;发布了全新的重调度框架,支持用户灵活的扩展自定义插件。这些特性源自于阿里巴巴内部的生产实践,并结合上游社区规划思考,为用户带来标准、强大、灵活的调度解决方案。
1063 0
Koordinator 0.6:企业级容器调度系统解决方案,引入 CPU 精细编排、资源预留与全新的重调度框架
|
SQL 缓存 NoSQL
【巡检问题分析与最佳实践】PolarDB MySQL CPU高问题
CPU做为数据库资源最核心的资源,是日常最重点需要关注的指标,CPU用满,会导致应用RT增高、业务卡顿,更严重会导致数据库实例hang死发生ha等问题,严重影响日常生产业务。 一般对于CPU的监控需要设定安全水位,超出安全水位要及时处理,否则会引发不可预期的严重后果。
【巡检问题分析与最佳实践】PolarDB MySQL CPU高问题
|
SQL 监控 NoSQL
【巡检问题分析与最佳实践】Redis CPU高问题
默认情况下,社区版Redis使用单线程模型处理读写请求,这使得CPU的使用率显得尤为重要。当实例的CPU打满时会导致数据库响应缓慢,严重影响线上业务。
【巡检问题分析与最佳实践】Redis CPU高问题
|
SQL 存储 缓存
【巡检问题分析与最佳实践】RDS SQL Server CPU高问题
CPU使用率过高问题是RDS SQL Server用户遇到的性能问题中较常见的一类。当RDS SQL Server实例的CPU使用率持续较高时,很容易导致数据库访问卡慢的情况,例如一些很简单的查询请求的响应时间也会很久甚至超时失败。
【巡检问题分析与最佳实践】RDS SQL Server CPU高问题
|
SQL 监控 关系型数据库
【巡检问题分析与最佳实践】RDS PostgreSQL CPU高问题
当RDS PostgreSQL实例的CPU使用率持续较高时,很容易导致数据库访问卡慢的情况,例如一些很简单的查询请求的响应时间也会很久甚至超时失败。
|
10天前
|
弹性计算 Kubernetes Perl
k8s 设置pod 的cpu 和内存
在 Kubernetes (k8s) 中,设置 Pod 的 CPU 和内存资源限制和请求是非常重要的,因为这有助于确保集群资源的合理分配和有效利用。你可以通过定义 Pod 的 `resources` 字段来设置这些限制。 以下是一个示例 YAML 文件,展示了如何为一个 Pod 设置 CPU 和内存资源请求(requests)和限制(limits): ```yaml apiVersion: v1 kind: Pod metadata: name: example-pod spec: containers: - name: example-container image:
|
19天前
|
存储 关系型数据库 MySQL
查询服务器CPU、内存、磁盘、网络IO、队列、数据库占用空间等等信息
查询服务器CPU、内存、磁盘、网络IO、队列、数据库占用空间等等信息
192 2