Red Hat Training

A Red Hat training course is available for RHEL 8

第 29 章 调整调度策略

在 Red Hat Enterprise Linux 中,最小的进程执行单元称为线程。系统调度程序决定哪个处理器运行线程,以及线程运行的时间。但是,由于调度程序的主要顾虑是保持系统处于忙碌状态,因此可能无法最佳地为应用程序性能调度线程。

例如,当 Node B 上的处理器可用时,NUMA 系统上的应用程序在节点 A 上运行。为了让节点 B 处于忙碌状态,调度程序将一个应用程序的线程移到 Node B。但是,应用程序线程仍然需要访问节点 A 上的内存。但是,此内存需要更长的时间来访问,因为线程现在在 Node B 上运行,并且 Node A 内存不再对线程而言是本地的。因此,线程在节点 B 上运行可能需要更长的时间,需要等待节点 A 上的处理器变得可用,然后在具有本地内存访问权限的原始节点上执行线程。

29.1. 调度策略的类别

对性能敏感的应用通常得益于设计人员或管理员确定线程的运行位置。Linux 调度程序实施许多调度策略,这些策略决定线程运行的位置和运行时间。

以下是两个主要类别的调度策略:

Normal policies
普通线程用于普通优先级的任务。
Realtime policies

实时策略用于必须在不中断的情况下完成的时间敏感任务。实时线程不受时间分片的影响。这意味着线程会一直运行,直到它们阻断、退出、自愿生成,或者被更高优先级的线程抢占。

最低优先级实时线程排在采用正常策略的任何线程之前调度。如需更多信息,请参阅使用 SCHED_FIFO 的静态优先级调度,并使用 SCHED_RR 进行循环优先级调度

其它资源

  • sched(7)sched_setaffinity(2)sched_getaffinity(2)sched_setscheduler(2)sched_getscheduler(2) man page

29.2. 使用 SCHED_FIFO 进行静态优先级调度

SCHED_FIFO 也称为静态优先级调度,是一个实时策略,为每个线程定义固定优先级。此策略允许管理员缩短事件响应时间并缩短延迟。对于时间敏感任务,建议不要在较长时间内执行此策略。

SCHED_FIFO 处于使用状态时,调度程序会按照优先级顺序扫描所有 SCHED_FIFO 线程列表,并调度就绪运行的最高优先级线程列表。SCHED_FIFO 线程的优先级级别可以是从 199 的任何整数,其中 99 被视为最高优先级。红帽建议从较低数量开始,只有在您发现延迟问题时才会增加优先级。

警告

因为实时线程不受时间片的限制,因此红帽不推荐将优先级设置为 99。这会使您的进程处于与迁移和 watchdog 线程相同的优先级级别;如果您的线程进入计算循环,并且这些线程已被阻止,它们将无法运行。具有单一处理器的系统最终会挂起。

管理员可以限制 SCHED_FIFO 带宽,以防止实时应用程序程序员启动将处理器推崇的实时任务。

以下是此策略中使用的一些参数:

/proc/sys/kernel/sched_rt_period_us
此参数定义时间周期,以微秒为单位,被视为处理器带宽的 10%。默认值为 1000000 μs1 second
/proc/sys/kernel/sched_rt_runtime_us
此参数定义专用于运行实时线程的时间周期,以微秒为单位。默认值为 950000 μs0.95 seconds

29.3. 使用 SCHED_RR 进行循环优先级调度

SCHED_RRSCHED_FIFO 的循环变体。当多个线程需要以同一优先级级别运行时,此策略很有用。

SCHED_FIFO 类似,SCHED_RR 是一个实时策略,为每个线程定义固定的优先级。调度程序按照优先级顺序扫描所有 SCHED_RR 线程的列表,并调度就绪运行的最高优先级线程。但是,与 SCHED_FIFO 不同,具有相同优先级的线程在特定时间片段中以轮循方式调度。

您可以使用 /proc/sys/kernel/sched_rr_timeslice_ms 文件中的 sched_rr_timeslice_ms 内核参数以毫秒为单位设置这个时间片段的值。最低的值是 1 millisecond

29.4. 使用 SCHED_OTHER 进行常规调度

SCHED_OTHER 是 Red Hat Enterprise Linux 8 中的默认调度策略。此策略使用完全公平调度程序(CFS)来允许对使用此策略调度的所有线程进行公平处理器访问。当有大量线程或者数据吞吐量具有优先权时,此策略最有用,因为它允许更有效地调度线程。

使用此策略时,调度程序会根据每个进程线程的 niceness 值部分创建动态优先级列表。管理员可以更改进程的 nice 值,但不能直接更改调度程序的动态优先级列表。

29.5. 设置调度程序策略

使用 chrt 命令行工具检查并调整调度程序策略和优先级。它可以启动具有所需属性的新进程,或者更改正在运行的进程的属性。它还可用于在运行时设置策略。

流程

  1. 查看活跃进程的进程 ID(PID):

    # ps

    ps 命令中使用 --pid-p 选项来查看特定 PID 的详情。

  2. 检查特定进程的调度策略、PID 和优先级:

    # chrt -p 468
    pid 468's current scheduling policy: SCHED_FIFO
    pid 468's current scheduling priority: 85
    
    # chrt -p 476
    pid 476's current scheduling policy: SCHED_OTHER
    pid 476's current scheduling priority: 0

    在这里,468476 是进程的 PID。

  3. 设置进程的调度策略:

    1. 例如,将 PID 为 1000 的进程设置为 SCHED_FIFO,优先级为 50

      # chrt -f -p 50 1000
    2. 例如,将 PID 为 1000 的进程设置为 SCHED_OTHER,优先级为 0

      # chrt -o -p 0 1000
    3. 例如,将 PID 为 1000 的进程设置为 SCHED_RR,其优先级为 10

      # chrt -r -p 10 1000
    4. 要使用特定的策略和优先级启动新应用程序,请指定应用程序的名称:

      # chrt -f 36 /bin/my-app

29.6. chrt 命令的策略选项

使用 chrt 命令,您可以查看和设置进程的调度策略。

下表描述了适当的策略选项,可用于设置进程的调度策略。

表 29.1. chrt 命令的策略选项

短选项长选项描述

-f

--fifo

将调度设置为 SCHED_FIFO

-o

--other

将调度设置为 SCHED_OTHER

-r

--rr

将调度设置为 SCHED_RR

29.7. 在引导过程中更改服务的优先级

使用 systemd 服务,可以为引导过程中启动的服务设置实时优先级。单元配置指令用于在启动过程中更改服务的优先级

引导过程优先级更改通过使用 service 部分中的以下指令来完成:

CPUSchedulingPolicy=
为已执行的进程设置 CPU 调度策略。它用于设置 otherfiforr 策略。
CPUSchedulingPriority=
为已执行的进程设置 CPU 调度优先级。可用的优先级范围取决于所选 CPU 调度策略。对于实时调度策略,可以使用 1 (最低优先级)和 99 (最高优先级)之间的整数。

以下流程描述了如何在引导过程中使用 mcelog 服务更改服务的优先级。

先决条件

  1. 安装 tuned 软件包:

    # yum install tuned
  2. 启用并启动 tuned 服务:

    # systemctl enable --now tuned

流程

  1. 查看正在运行的线程的调度优先级:

    # tuna --show_threads
                          thread       ctxt_switches
        pid SCHED_ rtpri affinity voluntary nonvoluntary             cmd
      1      OTHER     0     0xff      3181          292         systemd
      2      OTHER     0     0xff       254            0        kthreadd
      3      OTHER     0     0xff         2            0          rcu_gp
      4      OTHER     0     0xff         2            0      rcu_par_gp
      6      OTHER     0        0         9            0 kworker/0:0H-kblockd
      7      OTHER     0     0xff      1301            1 kworker/u16:0-events_unbound
      8      OTHER     0     0xff         2            0    mm_percpu_wq
      9      OTHER     0        0       266            0     ksoftirqd/0
    [...]
  2. 创建补充的 mcelog 服务配置文件,并在该文件中插入策略名称和优先级:

    # cat <<-EOF > /etc/systemd/system/mcelog.system.d/priority.conf
    
    >
    [SERVICE]
    CPUSchedulingPolicy=_fifo_
    CPUSchedulingPriority=_20_
    EOF
  3. 重新载入 systemd 脚本配置:

    # systemctl daemon-reload
  4. 重启 mcelog 服务:

    # systemctl restart mcelog

验证步骤

  • 显示由 systemd 问题设置的 mcelog 优先级:

    # tuna -t mcelog -P
    thread       ctxt_switches
      pid SCHED_ rtpri affinity voluntary nonvoluntary             cmd
    826     FIFO    20  0,1,2,3        13            0          mcelog

其它资源

29.8. 优先级映射

优先级按组定义,某些组专用于某些内核功能。对于实时调度策略,可以使用 1 (最低优先级)和 99 (最高优先级)之间的整数。

下表描述了优先级范围,可用于设置进程的调度策略。

表 29.2. 优先级范围的描述

优先级线程描述

1

低优先级内核线程

这个优先级通常为只需要 SCHED_OTHER 以上的任务保留。

2 - 49

可供使用

用于典型应用优先级的范围。

50

默认 hard-IRQ 值

 

51 - 98

高优先级线程

将此范围用于定期执行的线程,且必须具有快速响应时间。不要将此范围用于 CPU 绑定线程,因为您将造成中断。

99

watchdogs 和迁移

必须以最高优先级运行的系统线程。

29.9. CPU-partitioning 配置文件

cpu-partitioning 配置集用于将 CPU 与系统级别中断隔离。隔离这些 CPU 后,您可以为特定的应用程序分配它们。这在低延迟环境或您想要从硬件中提取最高性能的环境中非常有用。

此配置集还允许您指定内务处理 CPU。内务操作 CPU 用于运行所有服务、守护进程、shell 进程和内核线程。

您可以使用以下配置选项在 /etc/tuned/cpu-partitioning-variables.conf 文件中配置 cpu-partitioning 配置集:

isolated_cores=cpu-list
列出要隔离的 CPU。隔离 CPU 列表用逗号分开,您可以使用短划线来指定范围,如 3-5。此选项是必需的。此列表中缺少的任何 CPU 都会自动被视为内务 CPU。
no_balance_cores=cpu-list
列出内核在系统范围范围的进程负载均衡期间没有考虑的 CPU。此选项是可选的。这通常与 isolated_cores 列表相同。

其它资源

  • tuned-profiles-cpu-partitioning(7) man page