Linux 性能调优之配置CPU调度策略和可调参数

总有些人,一见就觉得喜欢,连道理都没得讲——烽火戏诸侯《剑来》

写在前面


  • 考试整理,博文内容涉及:
  • CPU 调度简单认知
  • 不同进程优先级和不同调度策略认知
  • 内核调度可调参数介绍
  • 理解不足小伙伴帮忙指正

总有些人,一见就觉得喜欢,连道理都没得讲——烽火戏诸侯《剑来》


当前实验环境

1
2
3
4
5
6
7
8
9
10
11
12
13
14
┌──[root@vms99.liruilongs.github.io]-[~]
└─$hostnamectl
Static hostname: vms99.liruilongs.github.io
Icon name: computer-vm
Chassis: vm
Machine ID: ea70bf6266cb413c84266d4153276342
Boot ID: d1c70cbd940549bc8fbdc3821ab073ec
Virtualization: vmware
Operating System: Rocky Linux 8.9 (Green Obsidian)
CPE OS Name: cpe:/o:rocky:rocky:8:GA
Kernel: Linux 4.18.0-513.9.1.el8_9.x86_64
Architecture: x86-64
┌──[root@vms99.liruilongs.github.io]-[~]
└─$

Scheduling Processes(进程调度)

单个CPU同一时间仅可用执行一个进程!虽然Linux系统似乎通过多任务同时运行多个进程,但当多个进程在单个CPU上同时运行时,是通过交替执行这些进程实现的。

要快速确定下一个进程并确保公平性、响应性、可预测性和可扩展性,操作系统通常会采用调度算法。内核通过进程调度器决定哪个进程在特定的时间运行。

一个常用的满足这些要求的算法是基于优先级的抢占式调度算法。以下是其工作原理:

  • 优先级分配快速决定下一个进程,根据进程的特性和需求,为每个进程分配一个优先级值。较高的优先级值表示更高的执行优先级。这个分配可以是静态的或动态的,取决于系统的设计。
  • 公平分享:CPU时间公平地分配给所有进程。每个进程都会获得一定比例的CPU时间,以确保公平性,,但是允许高优先级进程抢占低优先级进程的资源.
  • 抢占机制:允许具有较高优先级的进程抢占正在执行的低优先级进程。这意味着当一个高优先级进程就绪时,它可以暂停当前正在执行的低优先级进程,将CPU资源分配给高优先级进程。
  • 响应交互式应用程序:为了满足 交互式应用程序的需求,可以采取措施来提高这类应用程序的响应性,例如将交互式应用程序的优先级设置为较高,以确保它们获得更多的CPU时间。
  • 可预测和可扩展性:调度算法应该能够在不同的工作负载条件下保持可预测性和可扩展性,即在不同的负载情况下,仍然能够提供相对一致的性能和响应时间。

进程优先级认知

Linux 系统中调度器基于调度策略调度优先级决定进程执行的顺序。

了解优先级之前先简单了解下调度策略,Linux 调度策略分为两

非实时策略(non-real-time policies)适用于大多数通用计算系统和应用程序。这些策略的主要目标是在多个进程之间提供公平的CPU时间共享,并确保系统的响应性和资源利用率。一些常见的非实时调度策略包括:

实时策略(FIFO,real-time policies)适用于对时间敏感的系统和应用程序,如航空航天、医 疗设备和工业控制系统。这些策略的主要目标是确保实时任务在其截止时间内得到满足。实时调度策略通常基于任务的截止时间优先级来进行调度,并采取措施确保任务能够按时完成

调度优先级分为三种:

在这里插入图片描述

注:静态优先级(1-139),实时优先级为(99-1)nice(动态优先级)为(19 到 -20)

Static priority(静态优先级)

用于非实时进程,也称为普通进程。静态优先级是在进程创建时分配的固定优先级,并且通常在进程的生命周期中保持不变。

Dynamic priority(动态优先级):

CPU资源不足时,进程的优先级会被重置,因为有更高优先级的其他进程需要先被调度。调度器会提高等待时间最长的进程的优先级,用户也可用通过nice 或 renice命令修改进程优先级。进程优先级在进程生命周期内可用增加或减少,称为动态优先级

Real-Time Priority(实时优先级):

进程使用实时优先级策略 real-time policies(实时策略)会固定优先级调度,优先级的值为1(lowest)-99(highest)之间的值,这个值也叫实时优先级(real-time priority)

PS命令查看调度策略和优先级: pri是静态优先级,rtprio是实时优先级,ni是nice值(动态优先级),cls是调度策略,TS代表非实时策略,FF代表实时策略

进程优先级限制

可以通用 Linux下的 security 模块下的 ulimit 来配置当前 shell 的优先级信息

  • priority(静态优先级):以给定优先级运行用户进程
  • nice(动态优先级):允许提高到的最大 nice 优先级值(范围:-20 到 19)(ulimit -e)
  • rtprio(实时优先级):最大实时优先级(ulimit -r)

/etc/security/limits.conf 下进行相关配置

1
2
3
4
5
6
7
8
# 配置 priority 参数
* hard priority <priority_value>

# 配置 nice 参数
* hard nice <nice_value>

# 配置 rtprio 参数
@realtimegroup hard rtprio <rtprio_value>

调度策略认知

实时调度策略

1
2
3
4
5
6
7
8
9
┌──[root@vms99.liruilongs.github.io]-[~]
└─$ps axo pid,pri,rtprio,ni,cls,comm | egrep "FF|PID" | head -n 5
PID PRI RTPRIO NI CLS COMMAND
15 139 99 - FF migration/0
16 139 99 - FF watchdog/0
19 139 99 - FF watchdog/1
20 139 99 - FF migration/1
┌──[root@vms99.liruilongs.github.io]-[~]
└─$

字段说明:

pri静态优先级,当前设置为 139最低,静态优先级(PRI)的取值范围通常是0到139,其中0表示最高优先级,而139表示最低优先级。较高的静态优先级值表示较低的优先级,

rtprio实时优先级,最大 99,实时优先级(RTPRIO)的取值范围应该是1到99,较高的值表示较高的实时优先级,可以对照最前面的图,较高的值表示较高的实时优先级

FF实时策略,所以 nice(动态优先级) 的值为-,前面我们有讲,使用FIFO 实时调度策略时,其优先级是由静态优先级(PRI)实时优先级(RTPRIO)确定的。

实时调度器用于处理具有实时要求的任务。实时任务通常需要快速响应和确定性的执行时间。在实时调度器中,有两种不同的调度策略可用:

  • SCHED_FIFO(先进先出 FF):根据任务的优先级进行调度,优先级高的任务先被执行,直到完成或阻塞。ps o cls的输出结果为FF(FIFO)
  • SCHED_RR(轮转 RR):类似于FIFO,但任务在执行一段时间后会被抢占,以确保其他任务有机会执行。带时间片的轮询算法,每个进程耗尽自己的时间片让出CPU重新排队. ps o cls的输出结果为RR

对于实时调度策略的任务而言,内核不会计算动态优先级。

截止时间调度器(Deadline Scheduler)也属于实时调度策略,策略名称:SCHED_DEADLINE,是一种专门用于处理具有截止时间要求的任务的调度器。截止时间调度器通过设置每个任务的截止时间和执行时间来确保任务按时完成。该调度器使用Earliest Deadline First(EDF)算法,根据任务的截止时间和剩余执行时间来决定下一个要执行的任务。

实时调度策略配置

SCHED_FIFO调度策略:
systemdunit配置文件中,可以使用以下方式为进程设置SCHED_FIFO调度策略:
[Service]块中添加CPUSchedulingPolicy=fifo,表示将调度策略设置为SCHED_FIFO先进先出(FIFO)模式

可以选择性地在[Service]块中添加CPUSchedulingPriority=<优先级>,其中<优先级>是一个整数值,表示进程的优先级。较小的值表示较高的优先级。

1
2
3
4
5
6
7
8
9
10
[Unit]
Description=My Service

[Service]
ExecStart=/path/to/my/service
CPUSchedulingPolicy=fifo
CPUSchedulingPriority=99

[Install]
WantedBy=default.target

SCHED_RR调度策略:同理

1
2
3
4
5
6
7
8
9
10
[Unit]
Description=My Service

[Service]
ExecStart=/path/to/my/service
CPUSchedulingPolicy=rr
CPUSchedulingPriority=50

[Install]
WantedBy=default.target

非实时策略

1
2
3
4
5
6
7
┌──[root@vms99.liruilongs.github.io]-[~]
└─$ps axo pid,pri,rtprio,ni,cls,comm | egrep "TS|PID" | head -n 5
PID PRI RTPRIO NI CLS COMMAND
1 19 - 0 TS systemd
2 19 - 0 TS kthreadd
3 39 - -20 TS rcu_gp
4 39 - -20 TS rcu_par_gp
  • pri静态优先级, 设置为 19 和 39,取值范围通常是0到139,较高的静态优先级值表示较低的优先级,
  • rtprio实时优先级,使用非实时策略的进程不使用实时优先级,他们的实时优先级设置为0
  • ni动态优先级,是针对非实时策略(TS)的进程而言的,可以通过 nice 值进行调整。基于用户态对进程的优先级调整。Nice值的范围是-20(最高优先级)到19(最低优先级)。较低的Nice值表示较高的优先级。

非实时调度器主要为完全公平调度器(Completely Fair Scheduler,CFS),完全公平调度器是用于常规任务的默认调度器。它旨在提供公平的CPU时间分配给所有运行的进程。CFS调度器使用红黑树数据结构来跟踪任务的虚拟运行时间(virtual runtime),并根据任务的优先级和虚拟运行时间来决定下一个要执行的任务。有以下几种调度策略可用:

  • SCHED_NORMAL(也称为SCHED_OTHER或TS):进程使用完CPU资源会加入到相同进程优先级的队列,重新排队执行,时间片轮询机制。ps o cls的输出结果是TS
  • SCHED_BATCH:面向批处理工作负载,因此可以运行的时间更长,更好地使用缓存,适合于非交互实时任务,ps o cls输出结果为B
  • SCHED_IDLE: 适合于低优先级的程序,优先级最低,在系统CPU空闲时,才执行该类程序。使用IDLE算法的进程运行优先级比nice值为19的进程还低,ps o cls输出结果为IDLE

没有特殊要求,应用程序应该使用默认调度算法,像大型矩阵求逆,就不要使用FIFO算法,多数内核线程使用FIFO来避免用户态进程和自己抢资源。

非实时调度策略配置

在systemd中,CFS调度器是默认的调度器,它会根据任务的优先级和虚拟运行时间来进行动态调度,以提供公平的CPU时间分配给所有运行的进程。其中,SCHED_NORMAL(也称为SCHED_OTHER)是默认的调度策略,用于普通进程。SCHED_BATCH用于批处理任务,而SCHED_IDLE用于空闲任务。

[Service]节中添加CPUSchedulingPolicy配置项,并设置为所需的调度策略

1
2
3
CPUSchedulingPolicy=other
CPUSchedulingPolicy=batch
CPUSchedulingPolicy=idle

内核调度策略可调参数

sysctl命令可以对CFS调度算法进行调优,调优的参数在/proc/sys/kernel目录下

sched_latency_ns

sched_latency_ns是一个用于定义目标抢占延迟时间的变量。它指定了在这个时间周期内,调度器会至少一次地调度所有运行队列中的任务。这个变量的值以纳秒(ns)为单位。

1
2
3
┌──[root@vms99.liruilongs.github.io]-[~]
└─$cat /proc/sys/kernel/sched_latency_ns
18000000

通过增加sched_latency_ns的值,可以增加CPU绑定进程的时间片。也就是说,绑定在CPU上的进程会获得更长的执行时间。

sched_min_granularity_ns

sched_min_granularity_ns是一个进程被调度后的最小执行时间,以纳秒为单位。它的值必须小于sched_latency_us

1
2
3
┌──[root@vms99.liruilongs.github.io]-[~]
└─$cat /proc/sys/kernel/sched_min_granularity_ns
10000000

sched_migration_cost_ns

sched_migration_cost_ns是一个进程在最后一次执行后决定是否迁移到其他CPU的时间。它以纳秒为单位。增加该变量的值可以降低进程跨CPU迁移的频率。

1
2
3
┌──[root@vms99.liruilongs.github.io]-[~]
└─$cat /proc/sys/kernel/sched_migration_cost_ns
500000

sched_rt_period_ussched_rt_runtime_us

sched_rt_period_ussched_rt_runtime_us是与实时进程相关的变量。

1
2
3
4
5
6
7
8
┌──[root@vms99.liruilongs.github.io]-[~]
└─$cat /proc/sys/kernel/sched_rt_period_us
1000000
┌──[root@vms99.liruilongs.github.io]-[~]
└─$cat /proc/sys/kernel/sched_rt_runtime_us
950000
┌──[root@vms99.liruilongs.github.io]-[~]
└─$

sched_rt_period_us的默认值为1秒(单位是微秒,即1000000微秒=1秒),而sched_rt_runtime_us的默认值为0.95秒(单位是微秒,即950000微秒=0.95秒)。这意味着在1秒的时间周期内,实时进程最多可以使用0.95秒的时间。

sched_rr_timeslice_ms

sched_rr_timeslice_ms是一个用于定义轮转调度算法(RR)的变量。它指定了当一个进程被执行后,再次被抢占并返回到CPU队列的时间。它以毫秒为单位。

1
2
3
┌──[root@vms99.liruilongs.github.io]-[~]
└─$cat /proc/sys/kernel/sched_rr_timeslice_ms
100

如何调整

1
2
3
4
5
6
7
8
# 永久调整
#/etc/sysctl.conf
kernel.sched_latency_ns = <value>
sudo sysctl -p
# OR
#/etc/sysctl.d/99-cpu-scheduling.conf
kernel.sched_latency_ns = <value>
sudo sysctl --system
1
2
# 临时调整
sudo sysctl -w kernel.sched_latency_ns=<value>

命令行工具设置调度策略

chrt:chrt命令允许设置进程的调度策略和优先级。例如,要将一个进程设置为SCHED_FIFO策略,优先级为99,可以使用以下命令:

1
chrt -f -p 99 <pid>

taskset:taskset命令可以设置进程运行在特定的CPU核心上。例如,要将进程绑定到CPU 0和CPU 1上,可以使用以下命令:

1
taskset -c 0,1 <pid>

博文部分内容参考

© 文中涉及参考链接内容版权归原作者所有,如有侵权请告知 :)


https://access.redhat.com/documentation/zh-cn/red_hat_enterprise_linux_for_real_time/7/html/tuning_guide/chap-realtime-specific_tuning


© 2018-2024 liruilonger@gmail.com, All rights reserved. 保持署名-非商用-相同方式共享(CC BY-NC-SA 4.0)

发布于

2024-03-08

更新于

2024-03-08

许可协议

评论
Your browser is out-of-date!

Update your browser to view this website correctly.&npsb;Update my browser now

×