Red Hat Training

A Red Hat training course is available for Red Hat Enterprise Linux

6.3. 配置建议

Red Hat Enterprise Linux 提供了很多工具来协助管理员配置系统。本节概述了可用的工具,并提供了如何使用它们来解决 Red Hat Enterprise Linux 7 中的处理器相关性能问题的示例。

6.3.1. 配置内核调整时间

默认情况下,Red Hat Enterprise Linux 7 使用无空循环内核,它不会中断空闲 CPU 以降低功耗并允许较新的处理器利用深奥睡眠状态。
红帽企业 Linux 7 还提供了动态无循环选项(默认为禁用),这对于非常敏感延迟的工作负载(如高性能计算或实时计算)非常有用。
要在特定内核中启用动态无空行为,使用 nohz_full 参数在内核命令行中指定这些内核。在 16 个内核系统中,指定 nohz_full=1-15 在内核 1 到 15 中启用动态无勾号行为,将所有时间记录到唯一未指定的内核(核心 0)。此行为可以在引导时临时启用,或者通过 /etc/default/grub 文件中的 GRUB_CMDLINE_LINUX 选项永久启用。对于永久行为,请运行 grub2-mkconfig -o /boot/grub2/grub.cfg 命令来保存您的配置。
启用动态无循环行为确实需要一些手动管理。
  • 系统引导时,您必须手动将 rcu 线程移到非延迟敏感的内核中,本例中为 core 0。
    # for i in `pgrep rcu[^c]` ; do taskset -pc 0 $i ; done
  • 使用内核命令行中的 isolcpus 参数将特定内核与用户空间任务隔离。
  • 另外,还可将内核的回写 bdi-flush 线程的 CPU 关联性设置为 housekeeping 内核:
    echo 1 > /sys/bus/workqueue/devices/writeback/cpumask
通过执行以下命令验证动态无循环配置是否正常工作,其中 stress 是在 CPU 上启动 1 秒的程序。
# perf stat -C 1 -e irq_vectors:local_timer_entry taskset -c 1 stress -t 1 -c 1
压力的一种可能的替换是运行类似 while :; do d=1; done 的脚本。
默认内核计时器配置在忙碌的 CPU 上显示 1000 号:
# perf stat -C 1 -e irq_vectors:local_timer_entry taskset -c 1 stress -t 1 -c 1
1000 irq_vectors:local_timer_entry
配置动态无循环内核后,您应该会看到 1 tick:
# perf stat -C 1 -e irq_vectors:local_timer_entry taskset -c 1 stress -t 1 -c 1
1 irq_vectors:local_timer_entry

6.3.2. 设置硬件性能策略(x86_energy_perf_policy)

x86_energy_perf_policy 工具允许管理员定义性能和能源效率相对的重要性。当处理器选择在性能和能源效率之间取舍的选择时,可以利用这些信息来影响支持此功能的处理器。
默认情况下,它在 性能 模式的所有处理器上运行。它需要处理器支持,这通过存在 CPUID.06H.ECX.bit3 来指示,且必须以 root 权限运行。
x86_energy_perf_policykernel-tools 软件包提供。有关如何使用 x86_energy_perf_policy 的详情,请查看 第 A.9 节 “x86_energy_perf_policy” 或参考手册页:
$ man x86_energy_perf_policy

6.3.3. 使用 taskset 设置进程相关性

taskset 工具由 util-linux 软件包提供。taskset 允许管理员检索和设置正在运行的进程的处理器关联,或者启动具有指定处理器关联性的进程。
重要
taskset 不保证本地内存分配。如果您需要本地内存分配的额外性能优势,红帽建议使用 numactl 而不是 taskset
有关 taskset 的详情,请参考 第 A.15 节 “taskset” 或 man page:
$ man taskset

6.3.4. 使用 numactl 管理 NUMA 关联性

管理员可以使用 numactl 来运行具有指定调度或内存放置策略的进程。numactl 也可以为共享内存段或文件设置持久策略,并设置进程的处理器关联和内存关联性。
在 NUMA 拓扑的系统中,处理器的内存访问速度随着处理器和内存数据库之间的距离增加而减慢。因此,务必要配置对性能敏感的应用,以便它们从最接近的内存库中分配内存。最好使用位于同一 NUMA 节点中的内存和 CPU。
对性能敏感的多线程应用或许能够配置为在特定 NUMA 节点上执行,而非特定的处理器。这是否适合取决于您的系统以及应用程序的要求。如果多个应用程序线程访问相同的缓存数据,则可能适合将这些线程配置为在同一处理器上执行。但是,如果访问和缓存同一处理器中执行的不同数据的多个线程可能会驱除以前的线程访问的缓存数据。这意味着每个线程"缺少"缓存会浪费执行时间从内存中获取数据并在缓存中替换数据。您可以使用 perf 工具(如 第 A.6 节 “perf” 所述)检查大量缓存未命中。
numactl 提供了多个选项,可帮助您管理处理器和内存关联性。详情请查看 第 A.11 节 “numastat” 或 man page:
$ man numactl
注意
numactl 软件包包含 libnuma 库。此库为内核支持的 NUMA 策略提供简单的编程接口,可用于比 numactl 应用更精细的调优。如需更多信息,请参阅 man page:
$ man numa

6.3.5. 使用 numad 自动 NUMA 关联性管理

numad 是一个自动 NUMA 关联性管理守护进程。它监控系统中 NUMA 拓扑和资源使用情况,以便动态改进 NUMA 资源的分配和管理。
numad 还提供了一个预放置建议服务,可由各种作业管理系统查询,为进程提供 CPU 和内存资源的初始绑定。无论 numad 是以可执行还是服务方式运行,此预置建议都可用。
有关如何使用 numad 的详情,请参考 第 A.13 节 “numad” 或参考 man page:
$ man numad

6.3.6. 调优调度策略

Linux 调度程序实施许多调度策略,这些策略决定了线程运行的位置和运行时间。调度策略主要分为两类:常规策略和实时策略。普通线程用于普通优先级的任务。实时策略用于必须在不中断的情况下完成的时间敏感任务。
实时线程不受时间分片的影响。这意味着他们将运行,直到它们阻断、退出、自愿给予,或者被更高优先级线程抢占。最低优先级实时线程排在采用正常策略的任何线程之前调度。

6.3.6.1. 调度策略

6.3.6.1.1. 使用 SCHED_FIFO 进行静态优先级调度
SCHED_FIFO (也称为静态优先级调度)是一个实时策略,为每个线程定义固定优先级。此策略允许管理员改进事件响应时间并缩短延迟,建议针对在较长时间段内不运行的对时间敏感的任务。
当使用 SCHED_FIFO 时,调度程序会按照优先级顺序扫描所有 SCHED_FIFO 线程的列表,并调度可供运行的最高优先级线程。SCHED_FIFO 线程的优先级级别可以是从 1 到 99 的任何整数,其中 99 被视为最高优先级。红帽建议从较低的数量开始,只有在您发现延迟问题时才会增加优先级。
警告
因为实时线程不受时间片的限制,因此红帽不推荐设置 99 的优先级。这会将您的进程置于与迁移和 watchdog 线程相同的优先级级别;如果您的线程进入计算循环,并且这些线程已被阻止,它们将无法运行。具有单一处理器的系统最终会挂起。
管理员可以限制 SCHED_FIFO 带宽,以防止实时应用程序程序员启动对处理器进行单调执行的实时任务。
/proc/sys/kernel/sched_rt_period_us
此参数定义被认为是处理器带宽的 10% 的时间周期(以微秒为单位)。默认值为 1000000 crius,或 1 秒。
/proc/sys/kernel/sched_rt_runtime_us
这个参数定义专用于运行实时线程的微秒的时间周期。默认值为 950000 crius,或 0.95 秒。
6.3.6.1.2. 使用 SCHED_RR 进行循环优先级调度
SCHED_RRSCHED_FIFO 的循环变体。当多个线程需要以同一优先级级别运行时,此策略很有用。
SCHED_FIFO 一样,SCHED_RR 是一个实时策略,用于为每个线程定义固定优先级。调度程序以优先级顺序扫描所有 SCHED_RR 线程的列表,并调度准备好运行的最高优先级线程。但是,与 SCHED_FIFO 不同,在特定时间片段中会调度具有相同优先级的线程。
您可以使用 sched_rr_timeslice_ms 内核参数以毫秒为单位设置这个时间片段的值(/proc/sys/kernel/sched_rr_timeslice_ms)。最小值为 1 毫秒。
6.3.6.1.3. 使用 SCHED_OTHER 进行正常调度
SCHED_OTHER 是 Red Hat Enterprise Linux 7 中的默认调度策略。此策略使用完全公平调度程序(CFS)来允许对使用此策略调度的所有线程进行公平处理器访问。当有大量线程或数据吞吐量是一个优先级时,此策略最有用,因为它允许更有效地调度线程。
使用此策略时,调度程序会根据每个进程线程的 niceness 值部分创建动态优先级列表。管理员可以更改进程的 nice 值,但不能直接更改调度程序的动态优先级列表。

6.3.6.2. 隔离 CPU

您可以使用 isolcpus 引导参数将一个或多个 CPU 与调度程序隔离。这可以防止调度程序在此 CPU 上调度任何用户空间线程。
隔离 CPU 后,您必须手动将进程分配给隔离的 CPU,或者使用 CPU 关联性系统调用或 numactl 命令。
要将系统中的第八个 CPU 隔离,请在内核命令行中添加以下内容:
isolcpus=2,5-7
您还可以使用 Tuna 工具隔离 CPU。tuna 可以随时隔离 CPU,而不仅仅是在引导时。但是,这种隔离方法与 isolcpus 参数完全不同,目前没有实现与 isolcpus 相关的性能。有关此工具的详情,请查看 第 6.3.8 节 “使用 Tuna 配置 CPU、线程和中断关联性”

6.3.7. 在 AMD64 和 Intel 64 中设置 Interrupt Affinity

中断请求具有关联的关联性属性 smp_affinity,它定义将处理中断请求的处理器。若要提高应用性能,可将中断关联和进程相关性分配到同一处理器或同一核心上的处理器。这允许指定的中断和应用程序线程共享缓存行。
重要
本节仅涵盖 AMD64 和 Intel 64 架构。在其他架构上中断关联性配置有很大不同。

过程 6.1. 自动平衡中断

  • 如果您的 BIOS 导出它的 NUMA 拓扑,则 irqbalance 服务可自动为节点上对请求服务的硬件进行中断请求。
    有关配置 irqbalance 的详情,请参考 第 A.1 节 “irqbalance”

过程 6.2. 手动平衡中断

  1. 检查哪些设备与您要配置的中断请求对应。
    从 Red Hat Enterprise Linux 7.5 开始,系统会自动配置特定设备及其驱动程序的最优中断关联性。您无法再手动配置它们的关联性。这适用于以下设备:
    • 使用 be2iscsi 驱动程序的设备
    • NVMe PCI 设备
  2. 查找您的平台的硬件规格。检查系统上的芯片组是否支持分发中断。
    • 如果存在,您可以按照以下步骤中所述配置中断交付。
      此外,检查您的芯片组用于平衡中断的算法。某些 BIOS 拥有配置中断发送的选项。
    • 如果没有,您的芯片组总是将所有中断路由到单个静态 CPU。您无法配置使用哪个 CPU。
  3. 检查您的系统上正在使用哪个高级可编程中断控制器(APIC)模式。
    只有非物理平面模式(flat)支持将中断分发到多个 CPU。这个模式只适用于最多 8 个 CPU 的系统。
    $ journalctl --dmesg | grep APIC
    在命令输出中:
    • 如果您的系统使用 flat 以外的模式,您可以看到一个类似于 Setting APIC routing to physical flat 的行。
    • 如果看不到这个信息,代表您的系统使用 flat 模式。
    如果您的系统使用 x2apic 模式,您可以通过在 bootloader 配置中的内核命令行中添加 nox2apic 选项来禁用它。
  4. 计算 smp_affinity 掩码。
    smp_affinity 值存储为代表系统中所有处理器的十六进制位掩码。每个位配置一个不同的 CPU。最不重要的位是 CPU 0。
    掩码的默认值为 f,这意味着可在系统的任何处理器上处理中断请求。将此值设置为 1 表示只有处理器 0 可以处理中断。

    过程 6.3. 计算掩码

    1. 在二进制中,对处理中断的 CPU 使用值 1
      例如,要处理 CPU 0 和 CPU 7 的中断,请使用 0000000010000001 作为二进制代码:

      表 6.1. CPU 的二进制 Bit

      CPU1514131211109876543210
      二进制0000000010000001
    2. 将二进制代码转换为十六进制代码。
      例如,使用 Python 转换二进制代码:
      >>> hex(int('0000000010000001', 2))
      
      '0x81'
      
    在有 32 个处理器的系统上,您必须限制离散的 32 位组的 smp_affinity 值。例如,如果您只想 64 位处理器系统的第一个 32 个处理器来服务中断请求,请使用 0xffffffff,00000000
  5. 设置 smp_affinity 掩码。
    特定中断请求的中断关联性值存储在关联的 /proc/irq/irq_number/smp_affinity 文件中。
    将计算的掩码写入关联的文件:
    # echo mask > /proc/irq/irq_number/smp_affinity

其它资源

  • 在支持中断中断的系统上,修改中断请求的 smp_affinity 属性可设置硬件,以便决定使用特定处理器在硬件级别提供中断,而无需在内核中干预。
    有关中断中断的详情请参考 第 9 章 网络

6.3.8. 使用 Tuna 配置 CPU、线程和中断关联性

tuna 是调整正在运行的进程的工具,并可控制 CPU、线程和中断关联性,并为它可以控制的每种实体提供很多操作。有关 Tuna 的详情,请参考 第 4 章 tuna