11.3. 使用性能配置集调整节点以实现低延迟

性能配置集可让您控制属于特定机器配置池的节点的延迟调整方面。指定设置后,PerformanceProfile 对象将编译为执行实际节点级别调整的多个对象:

  • 操作节点的 MachineConfig 文件。
  • 用于配置拓扑管理器、CPU Manager 和 OpenShift Container Platform 节点的 KubeletConfig 文件。
  • 配置 Node Tuning Operator 的 Tuned 配置集。

您可以使用性能配置集指定是否将内核更新至 kernel-rt,分配大页面,以及划分 CPU 以执行内务处理或运行工作负载。

注意

您可以手动创建 PerformanceProfile 对象,或使用 Performance Profile Creator (PPC) 生成性能配置集。有关 PPC 的更多信息,请参见以下的其他资源。

性能配置集示例

apiVersion: performance.openshift.io/v2
kind: PerformanceProfile
metadata:
 name: performance
spec:
 cpu:
  isolated: "4-15" 1
  reserved: "0-3" 2
 hugepages:
  defaultHugepagesSize: "1G"
  pages:
  - size: "1G"
    count: 16
    node: 0
 realTimeKernel:
  enabled: true  3
 numa:  4
  topologyPolicy: "best-effort"
 nodeSelector:
  node-role.kubernetes.io/worker-cnf: "" 5

1
使用此字段隔离要用于工作负载的应用容器的特定 CPU。设置一个偶数的隔离 CPU 数量,以便在启用超线程时运行 pod 不会出现错误。
2
使用此字段保留要用于 infra 容器进行内务的特定 CPU。
3
使用此字段在节点上安装实时内核。有效值为 true 或者 false。设置 true 值将安装实时内核。
4
使用此字段配置拓扑管理器策略。有效值为 none (默认)、best-effortrestrictedsingle-numa-node。如需更多信息,请参阅拓扑管理器策略
5
使用此字段指定节点选择器,将性能配置集应用到特定的节点。

其他资源

  • 有关使用 Performance Profile Creator (PPC) 生成性能配置集的详情,请参考创建性能配置集

11.3.1. 配置巨页

节点必须预先分配在 OpenShift Container Platform 集群中使用的巨页。使用 Node Tuning Operator 在特定节点中分配巨页。

OpenShift Container Platform 提供了创建和分配巨页的方法。Node Tuning Operator 提供了一种更易于使用性能配置集的方法。

例如,在性能配置集的 hugepages pages 部分,您可以指定多个块的 sizecount 以及可选的 node:

hugepages:
   defaultHugepagesSize: "1G"
   pages:
   - size:  "1G"
     count:  4
     node:  0 1
1
node 是分配巨页的 NUMA 节点。如果省略了 node,该页面将平均分布在所有 NUMA 节点中。
注意

等待显示更新已完成的相关机器配置池状态。

这些是分配巨页的唯一配置步骤。

验证

  • 要验证配置,请查看节点上的 /proc/meminfo 文件:

    $ oc debug node/ip-10-0-141-105.ec2.internal
    # grep -i huge /proc/meminfo

    输出示例

    AnonHugePages:    ###### ##
    ShmemHugePages:        0 kB
    HugePages_Total:       2
    HugePages_Free:        2
    HugePages_Rsvd:        0
    HugePages_Surp:        0
    Hugepagesize:       #### ##
    Hugetlb:            #### ##

  • 使用 oc describe 报告新大小:

    $ oc describe node worker-0.ocp4poc.example.com | grep -i huge

    输出示例

                                       hugepages-1g=true
     hugepages-###:  ###
     hugepages-###:  ###

11.3.2. 分配多个巨页大小

您可以在同一容器下请求具有不同大小的巨页。这样,您可以定义由具有不同巨页大小的容器组成的更复杂的 pod。

例如,您可以把大小定义为 1G2M,Node Tuning Operator 会在节点上配置这两个大小,如下所示:

spec:
  hugepages:
    defaultHugepagesSize: 1G
    pages:
    - count: 1024
      node: 0
      size: 2M
    - count: 4
      node: 1
      size: 1G

11.3.3. 为 IRQ 动态负载平衡配置节点

为 IRQ 动态负载平衡配置集群节点,以控制哪些内核可以接收设备中断请求 (IRQ)。

先决条件

  • 对于内核隔离,所有服务器硬件组件都必须支持 IRQ 关联性。要检查服务器的硬件组件是否支持 IRQ 关联性,请查看服务器的硬件规格或联系您的硬件供应商。

流程

  1. 以具有 cluster-admin 权限的用户身份登录 OpenShift Container Platform 集群。
  2. 将性能配置集 apiVersion 设置为使用 performance.openshift.io/v2
  3. 删除 globallyDisableIrqLoadBalancing 字段,或把它设置为 false
  4. 设置适当的隔离 CPU 和保留的 CPU。以下片段演示了保留 2 个 CPU 的配置集。对于在 isolated CPU 集中运行的 pod,启用 IRQ 负载均衡:

    apiVersion: performance.openshift.io/v2
    kind: PerformanceProfile
    metadata:
      name: dynamic-irq-profile
    spec:
      cpu:
        isolated: 2-5
        reserved: 0-1
    ...
    注意

    当您配置保留的和隔离的 CPU 时,pod 中的 infra 容器将使用保留的 CPU,应用程序容器则使用隔离的 CPU。

  5. 创建使用独有 CPU 的 pod,并将 irq-load-balancing.crio.iocpu-quota.crio.io 注解设置为 disable。例如:

    apiVersion: v1
    kind: Pod
    metadata:
      name: dynamic-irq-pod
      annotations:
         irq-load-balancing.crio.io: "disable"
         cpu-quota.crio.io: "disable"
    spec:
      containers:
      - name: dynamic-irq-pod
        image: "registry.redhat.io/openshift4/cnf-tests-rhel8:v4.13"
        command: ["sleep", "10h"]
        resources:
          requests:
            cpu: 2
            memory: "200M"
          limits:
            cpu: 2
            memory: "200M"
      nodeSelector:
        node-role.kubernetes.io/worker-cnf: ""
      runtimeClassName: performance-dynamic-irq-profile
    ...
  6. 以 performance-<profile_name> 格式输入 pod 的 runtimeClassName,其中 <profile_name> 是来自 PerformanceProfile YAML 的 name,在本例中是 performance-dynamic-irq-profile
  7. 将节点选择器设置为以 cnf-worker 为目标。
  8. 确保 pod 正确运行。状态应该为 running,并应正确设置了 cnf-worker 节点:

    $ oc get pod -o wide

    预期输出

    NAME              READY   STATUS    RESTARTS   AGE     IP             NODE          NOMINATED NODE   READINESS GATES
    dynamic-irq-pod   1/1     Running   0          5h33m   <ip-address>   <node-name>   <none>           <none>

  9. 获取为 IRQ 动态负载均衡配置的 pod 运行 CPU:

    $ oc exec -it dynamic-irq-pod -- /bin/bash -c "grep Cpus_allowed_list /proc/self/status | awk '{print $2}'"

    预期输出

    Cpus_allowed_list:  2-3

  10. 确保正确应用节点配置。登录节点以验证配置。

    $ oc debug node/<node-name>

    预期输出

    Starting pod/<node-name>-debug ...
    To use host binaries, run `chroot /host`
    
    Pod IP: <ip-address>
    If you don't see a command prompt, try pressing enter.
    
    sh-4.4#

  11. 验证可以使用节点文件系统:

    sh-4.4# chroot /host

    预期输出

    sh-4.4#

  12. 确保默认系统 CPU 关联性掩码不包括 dynamic-irq-pod CPU,如 CPU 2 和 3。

    $ cat /proc/irq/default_smp_affinity

    输出示例

    33

  13. 确定系统 IRQ 没有配置为在 dynamic-irq-pod CPU 中运行:

    find /proc/irq/ -name smp_affinity_list -exec sh -c 'i="$1"; mask=$(cat $i); file=$(echo $i); echo $file: $mask' _ {} \;

    输出示例

    /proc/irq/0/smp_affinity_list: 0-5
    /proc/irq/1/smp_affinity_list: 5
    /proc/irq/2/smp_affinity_list: 0-5
    /proc/irq/3/smp_affinity_list: 0-5
    /proc/irq/4/smp_affinity_list: 0
    /proc/irq/5/smp_affinity_list: 0-5
    /proc/irq/6/smp_affinity_list: 0-5
    /proc/irq/7/smp_affinity_list: 0-5
    /proc/irq/8/smp_affinity_list: 4
    /proc/irq/9/smp_affinity_list: 4
    /proc/irq/10/smp_affinity_list: 0-5
    /proc/irq/11/smp_affinity_list: 0
    /proc/irq/12/smp_affinity_list: 1
    /proc/irq/13/smp_affinity_list: 0-5
    /proc/irq/14/smp_affinity_list: 1
    /proc/irq/15/smp_affinity_list: 0
    /proc/irq/24/smp_affinity_list: 1
    /proc/irq/25/smp_affinity_list: 1
    /proc/irq/26/smp_affinity_list: 1
    /proc/irq/27/smp_affinity_list: 5
    /proc/irq/28/smp_affinity_list: 1
    /proc/irq/29/smp_affinity_list: 0
    /proc/irq/30/smp_affinity_list: 0-5

11.3.4. 关于 IRQ 关联性设置的支持

有些 IRQ 控制器缺少对 IRQ 关联性设置的支持,并将始终将所有在线 CPU 公开为 IRQ 掩码。这些 IRQ 控制器在 CPU 0 上运行。

以下是红帽了解对 IRQ 关联性设置的支持的驱动程序和硬件示例。以下是相关的列表(并没有包括所有):

  • 一些 RAID 控制器驱动程序,如 megaraid_sas
  • 许多非易失性内存表达 (NVMe) 驱动程序
  • 主板 (LOM) 网络控制器上的一些 LAN
  • 驱动程序使用 managed_irqs
注意

不支持 IRQ 关联性设置的原因可能与主板中的处理器类型、IRI 控制器或断路器连接等因素相关。

如果任何 IRQ 的有效关联性被设置为一个隔离的 CPU,则可能代表一些硬件或驱动程序不支持 IRQ 关联性设置。要查找有效的关联性,请登录到主机并运行以下命令:

$ find /proc/irq -name effective_affinity -printf "%p: " -exec cat {} \;

输出示例

/proc/irq/0/effective_affinity: 1
/proc/irq/1/effective_affinity: 8
/proc/irq/2/effective_affinity: 0
/proc/irq/3/effective_affinity: 1
/proc/irq/4/effective_affinity: 2
/proc/irq/5/effective_affinity: 1
/proc/irq/6/effective_affinity: 1
/proc/irq/7/effective_affinity: 1
/proc/irq/8/effective_affinity: 1
/proc/irq/9/effective_affinity: 2
/proc/irq/10/effective_affinity: 1
/proc/irq/11/effective_affinity: 1
/proc/irq/12/effective_affinity: 4
/proc/irq/13/effective_affinity: 1
/proc/irq/14/effective_affinity: 1
/proc/irq/15/effective_affinity: 1
/proc/irq/24/effective_affinity: 2
/proc/irq/25/effective_affinity: 4
/proc/irq/26/effective_affinity: 2
/proc/irq/27/effective_affinity: 1
/proc/irq/28/effective_affinity: 8
/proc/irq/29/effective_affinity: 4
/proc/irq/30/effective_affinity: 4
/proc/irq/31/effective_affinity: 8
/proc/irq/32/effective_affinity: 8
/proc/irq/33/effective_affinity: 1
/proc/irq/34/effective_affinity: 2

有些驱动程序使用 managed_irqs,其关联性由内核在内部管理,用户空间无法更改关联性。在某些情况下,这些 IRQ 可能会分配给隔离的 CPU。有关 managed_irqs 的更多信息,请参阅 无法更改受管中断的关联性,即使它们目标隔离 CPU

11.3.5. 为集群配置超线程

要为 OpenShift Container Platform 集群配置超线程,请将性能配置集中的 CPU 线程设置为为保留或隔离的 CPU 池配置的相同内核。

注意

如果您配置了性能配置集,然后更改主机的超线程配置,请确保更新 PerformanceProfile YAML 中的 CPU isolatedreserved字段以匹配新配置。

警告

禁用之前启用的主机超线程配置可能会导致 PerformanceProfile YAML 中列出的 CPU 内核 ID 错误。此不正确的配置可能会导致节点不可用,因为无法找到列出的 CPU。

先决条件

  • 使用具有 cluster-admin 角色的用户访问集群。
  • 安装 OpenShift CLI(oc)。

流程

  1. 确定在您要配置的主机的 CPU 上运行哪些线程。

    您可以通过登录到集群并运行以下命令来查看在主机 CPU 上运行哪些线程:

    $ lscpu --all --extended

    输出示例

    CPU NODE SOCKET CORE L1d:L1i:L2:L3 ONLINE MAXMHZ    MINMHZ
    0   0    0      0    0:0:0:0       yes    4800.0000 400.0000
    1   0    0      1    1:1:1:0       yes    4800.0000 400.0000
    2   0    0      2    2:2:2:0       yes    4800.0000 400.0000
    3   0    0      3    3:3:3:0       yes    4800.0000 400.0000
    4   0    0      0    0:0:0:0       yes    4800.0000 400.0000
    5   0    0      1    1:1:1:0       yes    4800.0000 400.0000
    6   0    0      2    2:2:2:0       yes    4800.0000 400.0000
    7   0    0      3    3:3:3:0       yes    4800.0000 400.0000

    在这个示例中,在四个物理 CPU 内核中运行了八个逻辑 CPU 内核。CPU0 和 CPU4 在物理 Core0 中运行,CPU1 和 CPU5 在物理 Core 1 中运行,以此类推。

    另外要查看为特定物理 CPU 内核设定的线程(以下示例中的cpu0 ),打开命令提示符并运行以下命令:

    $ cat /sys/devices/system/cpu/cpu0/topology/thread_siblings_list

    输出示例

    0-4

  2. PerformanceProfile YAML 中应用隔离和保留的 CPU。例如,您可以将逻辑内核 CPU0 和 CPU4 设置为 isolated;将逻辑内核 CPU1 到 CPU3 以及 CPU5 到 CPU7 设置为 reserved。当您配置保留的和隔离的 CPU 时,pod 中的 infra 容器将使用保留的 CPU,应用程序容器则使用隔离的 CPU。

    ...
      cpu:
        isolated: 0,4
        reserved: 1-3,5-7
    ...
    注意

    保留和隔离的 CPU 池不得重叠,并且必须一起跨越 worker 节点中的所有可用内核。

重要

大多数 Intel 处理器上默认启用超线程。如果启用超线程,特定内核处理的所有线程都必须被隔离或者在同一个内核中处理。

11.3.5.1. 禁用低延迟应用程序超线程

在为低延迟进程配置集群时,请考虑是否要在部署集群前禁用超线程。要禁用超线程,请执行以下操作:

  1. 创建一个适合您的硬件和拓扑的性能配置集。
  2. nosmt 设为附加内核参数。以下示例的性能配置集演示了此设置:

    apiVersion: performance.openshift.io/v2
    kind: PerformanceProfile
    metadata:
      name: example-performanceprofile
    spec:
      additionalKernelArgs:
        - nmi_watchdog=0
        - audit=0
        - mce=off
        - processor.max_cstate=1
        - idle=poll
        - intel_idle.max_cstate=0
        - nosmt
      cpu:
        isolated: 2-3
        reserved: 0-1
      hugepages:
        defaultHugepagesSize: 1G
        pages:
          - count: 2
            node: 0
            size: 1G
      nodeSelector:
        node-role.kubernetes.io/performance: ''
      realTimeKernel:
        enabled: true
    注意

    当您配置保留的和隔离的 CPU 时,pod 中的 infra 容器将使用保留的 CPU,应用程序容器则使用隔离的 CPU。

11.3.6. 了解工作负载提示

下表描述了节能和实时设置对延迟的影响。

注意

可以手动配置以下工作负载提示。您还可以使用 Performance Profile Creator 来使用工作负载提示。有关性能配置集的更多信息,请参阅"创建性能配置集"部分。如果手动配置工作负载提示,并且未明确设置 realTime 工作负载提示,则默认为 true

性能配置集创建器设置提示环境描述

Default(默认)

workloadHints:
highPowerConsumption: false
realTime: false

没有延迟要求的高吞吐量集群

仅通过 CPU 分区实现的性能。

Low-latency

workloadHints:
highPowerConsumption: false
realTime: true

地区数据中心

节能和低延迟都需要考虑的:在电源管理、延迟和吞吐量之间进行妥当调节。

Ultra-low-latency

workloadHints:
highPowerConsumption: true
realTime: true

对于远边缘集群,对延迟非常敏感的工作负载

实现最小延迟和最大确定性会增加电源消耗的成本。

每个 pod 电源管理

workloadHints:
realTime: true
highPowerConsumption: false
perPodPowerManagement: true

关键和非关键工作负载

允许每个 pod 进行电源管理。

其他资源

  • 有关使用 Performance Profile Creator (PPC) 生成性能配置集的详情,请参考创建性能配置集

11.3.7. 手动配置工作负载提示

流程

  1. 按照 "Understanding workload hints" 的表,创建一个适合环境的硬件和拓扑的 PerformanceProfile。调整配置集以匹配预期的工作负载。在这个示例中,我们针对最低的延迟进行优化。
  2. 添加 highPowerConsumptionrealTime 工作负载提示。这里两者都设为 true

        apiVersion: performance.openshift.io/v2
        kind: PerformanceProfile
        metadata:
          name: workload-hints
        spec:
          ...
          workloadHints:
            highPowerConsumption: true 1
            realTime: true 2
    1
    如果 highPowerConsumptiontrue,则节点将针对实现非常低的延迟进行调优,从而增加了电源消耗的成本。
    2
    禁用一些可能会影响系统延迟的调试和监控功能。
注意

当在性能配置集中将 realTime 工作负载 hint 标志设置为 true 时,将 cpu-quota.crio.io: disable 注解添加到带有固定 CPU 的每个保证 pod。此注解是防止 pod 中进程性能降级所必需的。如果没有显式设置 realTime 工作负载提示,则默认为 true

其他资源

11.3.8. 为 infra 和应用程序容器限制 CPU

通用内务处理和工作负载任务使用 CPU 的方式可能会影响对延迟敏感的进程。默认情况下,容器运行时使用所有在线 CPU 一起运行所有容器,这可能导致上下文切换和延迟激增。对 CPU 进行分区可防止无状态进程通过相互分离来干扰对延迟敏感的进程。下表描述了在使用 Node Tuning Operator 调整节点后在 CPU 上运行的进程:

表 11.2. 进程的 CPU 分配

进程类型详情

BurstableBestEffort pod

在除了运行低延迟工作负载外的任意 CPU 上运行

基础架构 pod

在除了运行低延迟工作负载外的任意 CPU 上运行

中断

重定向到保留的 CPU(OpenShift Container Platform 4.7 及更新的版本中的可选)

内核进程

固定保留的 CPU

对延迟敏感的工作负载 pod

固定到隔离池中的特定专用 CPU

OS 进程/systemd 服务

固定保留的 CPU

在一个节点上的对于所有 QoS 进程类型( BurstableBestEffortGuaranteed )的 pod 的可分配容量等于隔离池的容量。保留池的容量已从节点的总内核容量中删除,供集群和操作系统日常任务使用。

示例 1

节点具有 100 个内核的容量。通过使用性能配置集,集群管理员将 50 个内核分配给隔离池,将 50 个内核分配给保留池。集群管理员为 QoS 为 BestEffortBurstable 的 pod 分配 25 个内核,为 Guaranteed 的 pod 分配 25 个内核。这与隔离池的容量匹配。

示例 2

节点具有 100 个内核的容量。通过使用性能配置集,集群管理员将 50 个内核分配给隔离池,将 50 个内核分配给保留池。集群管理员为 QoS 为 BestEffortBurstable 的 pod 分配一个内核,为 Guaranteed 的 pod 分配 50 个内核。这超过了隔离池容量一个内核。Pod 调度因为 CPU 容量不足而失败。

使用的确切分区模式取决于许多因素,如硬件、工作负载特性和预期的系统负载。以下是一些用例示例:

  • 如果对延迟敏感的工作负载使用特定的硬件,如网络接口控制器(NIC),请确保隔离池中的 CPU 尽可能地与这个硬件接近。至少,您应该将工作负载放在同一个非统一内存访问 (NUMA) 节点中。
  • 保留的池用于处理所有中断。根据系统网络,分配一个足够大小的保留池来处理所有传入的数据包中断。在 4.13 及更高版本中,工作负载可以选择性地被标记为敏感版本。

在决定哪些特定 CPU 用于保留和隔离分区时,需要详细分析和测量。设备和内存的 NUMA 紧密度等因素扮演了角色。选择也取决于工作负载架构和具体的用例。

重要

保留和隔离的 CPU 池不得重叠,并且必须一起跨越 worker 节点中的所有可用内核。

为确保内务处理任务和工作负载不会相互干扰,请在性能配置集的 spec 部分指定两组 CPU。

  • isolated - 指定应用程序容器工作负载的 CPU。这些 CPU 的延迟最低。这个组中的进程没有中断,例如,可以达到更高的 DPDK 零数据包丢失带宽。
  • reserved - 为集群和操作系统日常任务指定 CPU。reserved 组中的线程经常会比较繁忙。不要在 reserved 组中运行对延迟敏感的应用程序。对延迟敏感的应用程序在 isolated 组中运行。

流程

  1. 创建适合环境硬件和拓扑的性能配置集。
  2. 使用您想要为 infra 和应用程序容器保留和隔离的 CPU 添加 reservedisolated 参数:

    apiVersion: performance.openshift.io/v2
    kind: PerformanceProfile
    metadata:
      name: infra-cpus
    spec:
      cpu:
        reserved: "0-4,9" 1
        isolated: "5-8" 2
      nodeSelector: 3
        node-role.kubernetes.io/worker: ""
    1
    指定 infra 容器用于执行集群和操作系统日常任务的 CPU。
    2
    指定应用程序容器运行工作负载的 CPU。
    3
    可选:指定一个节点选择器,以将性能配置集应用到特定的节点。