14.4. 置备实时和低延迟工作负载

很多行业和机构需要非常高的计算性能,并需要低且可预测的延迟,特别是银行和电信业。对于这些行业,它们有其特殊的要求,OpenShift Container Platform 提供了一个 Performance Addon Operator 来实现自动调整,以便为 OpenShift Container Platform 应用程序实现低延迟性能和响应时间。

集群管理员可以使用此性能配置集配置以更可靠的方式进行这些更改。管理员可以指定是否将内核更新至 kernel-rt(实时),为集群和操作系统日常任务保留 CPU(包括 pod infra 容器),以及隔离 CPU,以便应用程序容器运行工作负载。

警告

将执行探测与需要保证 CPU 的应用配合使用可能会导致延迟激增。建议使用其他探测(如正确配置的一组网络探测作为替代方案)。

14.4.1. 已知的实时限制

注意

在大多数部署中,只有使用具有三个 control plane 节点和三个 worker 节点的标准集群时,仅在 worker 节点上支持 kernel-rt。OpenShift Container Platform 部署中的紧凑和单一节点会有例外。对于在单一节点上的安装, kernel-rt 在单个 control plane 节点上被支持。

要充分利用实时模式,容器必须使用升级的权限运行。如需了解有关授予特权的信息,请参阅为容器设置能力

OpenShift Container Platform 会限制允许的功能,因此您可能需要创建 SecurityContext

注意

使用 Red Hat Enterprise Linux CoreOS(RHCOS)系统的裸机安装完全支持此步骤。

在确定正确的性能预期时,应该意识到实时内核并不是万能的。它的目的是提供一个持续的、低延迟的确定性机制,从而提供可预测的响应时间。在系统中,会存在与实时内核关联的额外内核开销。这是因为在单独调度的线程中处理硬件中断。某些增加的工作负载开销会导致整个吞吐量下降。实际的影响依赖于特定的负载,范围从 0% 到 30%。然而,这是获得确定性所需要付出的代价。

14.4.2. 使用实时功能置备 worker

  1. 在集群上安装 Performance Addon Operator。
  2. 可选:在 OpenShift Container Platform 集群中添加节点。请参阅设置 BIOS 参数
  3. 使用 oc 命令将标签 worker-rt 添加到需要实时功能的 worker 节点。
  4. 为实时节点创建新机器配置池:

    apiVersion: machineconfiguration.openshift.io/v1
    kind: MachineConfigPool
    metadata:
      name: worker-rt
      labels:
        machineconfiguration.openshift.io/role: worker-rt
    spec:
      machineConfigSelector:
        matchExpressions:
          - {
               key: machineconfiguration.openshift.io/role,
               operator: In,
               values: [worker, worker-rt],
            }
      paused: false
      nodeSelector:
        matchLabels:
          node-role.kubernetes.io/worker-rt: ""

    请注意,为具有标签 worker-rt 标签的节点组创建一个机器配置池 worker-rt

  5. 使用节点角色标签将节点添加到正确的机器配置池。

    注意

    您必须决定使用实时工作负载配置哪些节点。您可以配置集群中的所有节点,或配置节点的子集。期望所有节点都是专用机器配置池的一部分的 Performance Addon Operator。如果使用所有节点,您必须将 Performance Addon Operator 指向 worker 节点角色标签。如果使用子集,您必须将节点分组到新机器配置池中。

  6. 使用正确的 housekeeping 内核和 realTimeKernel: enabled: true 创建 PerformanceProfile
  7. 您必须在 PerformanceProfile 中设置 MachineConfigPoolSelector

      apiVersion: performance.openshift.io/v2
      kind: PerformanceProfile
      metadata:
       name: example-performanceprofile
      spec:
      ...
        realTimeKernel:
          enabled: true
        nodeSelector:
           node-role.kubernetes.io/worker-rt: ""
        machineConfigPoolSelector:
           machineconfiguration.openshift.io/role: worker-rt
  8. 验证匹配的机器配置池是否存在一个标签:

    $ oc describe mcp/worker-rt

    输出示例

    Name:         worker-rt
    Namespace:
    Labels:       machineconfiguration.openshift.io/role=worker-rt

  9. OpenShift Container Platform 将开始配置节点,这可能涉及多次重启。等待节点处于稳定状态。这个过程所需要的时间取决于您所使用的具体硬件,预计每个节点需要 20 分钟。
  10. 验证所有内容是否按预期工作。

14.4.3. 验证实时内核安装

使用这个命令确定安装了实时内核:

$ oc get node -o wide

记录带有角色 worker-rt,包括 4.18.0-211.rt5.23.el8.x86_64 字符串的 worker。

NAME                               	STATUS   ROLES           	AGE 	VERSION                  	INTERNAL-IP
EXTERNAL-IP   OS-IMAGE                                       	KERNEL-VERSION
CONTAINER-RUNTIME
rt-worker-0.example.com	          Ready	 worker,worker-rt   5d17h   v1.22.1
128.66.135.107   <none>    	        Red Hat Enterprise Linux CoreOS 46.82.202008252340-0 (Ootpa)
4.18.0-211.rt5.23.el8.x86_64   cri-o://1.22.1-90.rhaos4.9.git4a0ac05.el8-rc.1
[...]

14.4.4. 创建一个实时工作负载

使用以下步骤准备一个使用实时功能的工作负载。

流程

  1. 创建带有 Guaranteed 类 QoS 类的 pod。
  2. 可选:禁用 DPDK 的 CPU 负载均衡。
  3. 分配正确的节点选择器。

在编写应用程序时,请遵循应用程序调整和部署中的常规建议。

14.4.5. 创建带有 Guaranteed 类 QoS 类的 pod

在创建带有 Guaranteed 类的 QoS 类的 pod 时请注意以下几点:

  • pod 中的每个容器都必须具有内存限制和内存请求,且它们必须相同。
  • pod 中的每个容器都必须具有 CPU 限制和 CPU 请求,且它们必须相同。

以下示例显示了一个容器的 pod 的配置文件。容器设置了内存限制和内存请求,均为 200 MiB。容器具有 CPU 限制和 CPU 请求,均为 1 CPU。

apiVersion: v1
kind: Pod
metadata:
  name: qos-demo
  namespace: qos-example
spec:
  containers:
  - name: qos-demo-ctr
    image: <image-pull-spec>
    resources:
      limits:
        memory: "200Mi"
        cpu: "1"
      requests:
        memory: "200Mi"
        cpu: "1"
  1. 创建 pod:

    $ oc  apply -f qos-pod.yaml --namespace=qos-example
  2. 查看有关 pod 的详细信息:

    $ oc get pod qos-demo --namespace=qos-example --output=yaml

    输出示例

    spec:
      containers:
        ...
    status:
      qosClass: Guaranteed

    注意

    如果容器指定了自己的内存限值,但没有指定内存请求,OpenShift Container Platform 会自动分配与限制匹配的内存请求。同样,如果容器指定了自己的 CPU 限值,但没有指定 CPU 请求,OpenShift Container Platform 会自动分配与限制匹配的 CPU 请求。

14.4.6. 可选:禁用 DPDK 的 CPU 负载均衡

禁用或启用 CPU 负载均衡的功能在 CRI-O 级别实现。CRI-O 下的代码仅在满足以下要求时禁用或启用 CPU 负载均衡。

  • pod 必须使用 performance-<profile-name> 运行时类。您可以通过查看性能配置集的状态来获得正确的名称,如下所示:

    apiVersion: performance.openshift.io/v2
    kind: PerformanceProfile
    ...
    status:
      ...
      runtimeClass: performance-manual
  • pod 必须具有 cpu-load-balancing.crio.io: true 注解。

Performance Addon Operator 负责在相关节点下创建高性能运行时处理器配置片断,并在集群下创建高性能运行时类。它具有与默认运行时处理相同的内容,但它启用了 CPU 负载均衡配置功能。

要禁用 pod 的 CPU 负载均衡,Pod 规格必须包括以下字段:

apiVersion: v1
kind: Pod
metadata:
  ...
  annotations:
    ...
    cpu-load-balancing.crio.io: "disable"
    ...
  ...
spec:
  ...
  runtimeClassName: performance-<profile_name>
  ...
注意

仅在启用了 CPU 管理器静态策略,以及带有保证 QoS 使用整个 CPU 的 pod 时,禁用 CPU 负载均衡。否则,禁用 CPU 负载均衡会影响集群中其他容器的性能。

14.4.7. 分配适当的节点选择器

为节点分配 pod 的首选方法是使用与性能配置集相同的节点选择器,如下所示:

apiVersion: v1
kind: Pod
metadata:
  name: example
spec:
  # ...
  nodeSelector:
    node-role.kubernetes.io/worker-rt: ""

如需更多信息,请参阅使用节点选择器将 pod 放置到特定的节点上

14.4.8. 将工作负载调度到具有实时功能的 worker

使用与附加到机器配置的节点匹配的标签选择器,这些选择器是为低延迟配置的。如需更多信息,请参阅将 pod 分配给节点

14.4.9. 管理设备中断处理保证 pod 隔离 CPU

Performance Addon Operator 可以通过将主机 CPU 划分为保留的 CPU 来管理主机 CPU,以进行集群和操作系统日常任务(包括 pod infra 容器),以及用于应用程序容器运行工作负载的隔离 CPU。这可让您将低延迟工作负载的 CPU 设置为隔离状态。

设备中断在所有隔离和保留 CPU 之间平衡负载,以避免出现 CPU 超载问题,但运行有保证 pod 的 CPU 除外。当为 pod 设置相关注解时,保证 pod CPU 无法处理设备中断。

在性能配置集中,globallyDisableIrqLoadBalancing 用于管理设备中断是否被处理。对于某些工作负载,保留 CPU 并不总是足以处理设备中断,因此不会在隔离的 CPU 上禁用设备中断。默认情况下,Performance Addon Operator 不会禁用隔离 CPU 上的设备中断。

要实现低延迟,有些(而非全部)pod 需要它们运行的 CPU 不处理设备中断。pod 注解 irq-load-balancing.crio.io 用于定义是否处理设备中断。配置后,CRI-O 仅在 pod 正在运行时禁用设备中断。

14.4.9.1. 禁用 CPU CFS 配额

要减少单独保证 pod 的 CPU 节流,创建一个带有注解 cpu-quota.crio.io: "disable" 的 pod 规格。此注释在 pod 运行时禁用 CPU 完全公平调度程序(CFS)配额。以下 pod 规格包含此注解:

apiVersion: performance.openshift.io/v2
kind: Pod
metadata:
  annotations:
      cpu-quota.crio.io: "disable"
spec:
    runtimeClassName: performance-<profile_name>
...
注意

仅在启用了 CPU 管理器静态策略,以及带有保证 QoS 使用整个 CPU 的 pod 时禁用 CPU CFS 配额。否则,禁用 CPU CFS 配额可能会影响集群中其他容器的性能。

14.4.9.2. 禁用 Performance Addon Operator 中的全局设备中断处理

要将 Performance Addon Operator 配置为禁用隔离 CPU 集的全局设备中断,将 performance 配置集中的 globallyDisableIrqLoadBalancing 字段设置为 true。在为 true 时,会忽略有冲突的 pod 注解。在为 false 时,IRQ 负载会在所有 CPU 之间平衡。

一个性能配置集片段演示了这个设置:

apiVersion: performance.openshift.io/v2
kind: PerformanceProfile
metadata:
  name: manual
spec:
  globallyDisableIrqLoadBalancing: true
...

14.4.9.3. 禁用单个 pod 的中断处理

要禁用单个 pod 的中断处理,确保在性能配置集中将 globallyDisableIrqLoadBalancing 设置为 false。然后,在 pod 规格中,将 irq-load-balancing.crio.io pod 注解设置为 disable。以下 pod 规格包含此注解:

apiVersion: performance.openshift.io/v2
kind: Pod
metadata:
  annotations:
      irq-load-balancing.crio.io: "disable"
spec:
    runtimeClassName: performance-<profile_name>
...

14.4.10. 升级性能配置集以使用设备中断处理

当您将 Performance Addon Operator 性能配置集自定义资源定义(CRD)从 v1 或 v1alpha1 升级到 v2 时,现有配置集会将 globallyDisableIrqLoadBalancing 设置为 true

注意

globallyDisableIrqLoadBalancing 切换用于 Isolated CPU 集是否禁用了 IRQ 负载均衡。当选项设置为 true 时,它会禁用 Isolated CPU 集的 IRQ 负载均衡。将选项设置为 false 允许在所有 CPU 之间平衡 IRQ。

14.4.10.1. 支持的 API 版本

Performance Addon Operator 在性能配置集 apiVersion 字段中支持 v2v1v1alpha1。v1 和 v1alpha1 API 相同。v2 API 包括一个可选的布尔值项 globallyDisableIrqLoadBalancing,默认值为 false

14.4.10.1.1. 将 Performance Addon Operator API 从 v1alpha1 升级到 v1

当将 Performance Addon Operator API 版本从 v1alpha1 升级到 v1 时,,v1alpha1 性能配置集会通过"None" Conversion 策略自行转换,并提供给带有 API 版本 v1 的 Performance Addon Operator。

14.4.10.1.2. 将 Performance Addon Operator API 从 v1alpha1 或 v1 升级到 v2

当从旧的 Performance Addon Operator API 版本升级时,现有的 v1 和 v1alpha1 性能配置集将使用转换 Webhook 转换,它将注入 globallyDisableIrqLoadBalancing 字段,值为 true

14.4.11. 为 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: "quay.io/openshift-kni/cnf-tests:4.9"
        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. 确保正确应用节点配置。SSH 到节点以验证配置。

    $ 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

一些 IRQ 控制器不支持 IRQ 重新平衡,并将始终将所有在线 CPU 公开为 IRQ 掩码。这些 IRQ 控制器在 CPU 0 上运行。如需了解主机配置的更多信息,请 SSH 到主机并运行以下命令,将 <irq-num> 替换为您要查询的 CPU 号码:

$ cat /proc/irq/<irq-num>/effective_affinity

14.4.12. 为集群配置超线程

要为 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 处理器上默认启用超线程。如果启用超线程,特定内核处理的所有线程都必须被隔离或者在同一个内核中处理。

14.4.12.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。