分析 Linux 服务器性能,首先想到的命令肯定是 top, 通过它,我们可以看到当前服务器资源使用情况和进程运行资源占用情况。

linux top上的res_linux top上的res

在查看进程资源占用情况时,有两列大家是最难区分,PR(priority)进程优先级和 NI(nice)优先级切换等级,都是优先级,有什么区别呢?

如果,仔细观察,还会发现 PR 列的值是:rt 或大于等于 0 的数字;NI 列的值是:[-20, 19]之间的数字,这些又代表什么意思呢?

因为这些问题搞不清,所以这两列很难理解,下面,我就来给大家说说:

️首先,还是老规矩,在不知道 Linux 命令的结果信息是什么意思的时候,可以查看命令的帮助信息,info top 查看帮助

linux top上的res_用户态_02

NI  --  Nice Value
           The  nice  value  of  the  task.   A negative nice value means
           higher priority, whereas a positive  nice  value  means  lower
           priority.   Zero  in this field simply means priority will not
           be adjusted in determining a task's dispatch-ability.
           这项任务的优先价值。负的nice值意味着更高的优先级,而正的nice值意味着更低的优先级。
           该字段中的0表示在确定任务的调度能力时不会调整优先级。

linux top上的res_用户态_03

PR  --  Priority 优先事项
           The scheduling priority of the task.  If you see `rt' in  this
           field, it means the task is running under real time scheduling
           priority.


           Under linux, real time priority is somewhat  misleading  since
           traditionally  the  operating itself was not preemptible.  And
           while the 2.6 kernel can be made mostly preemptible, it is not
           always so.
           任务的调度优先级。如果在该字段中看到“rt”,则表示任务正在实时调度优先级下运行。


           在linux下,实时优先级有些误导,因为传统上操作本身是不可抢占的。
     虽然2.6内核基本上是可抢占的,但并不总是如此。

️估计看了帮助,还是有些愣,接下来,我们就来讲解一下:

⚫ 首先,我们看到,任务列表数量很多,一般都超过了 CPU 的数量,超过了 CPU 的数量的进程,都要使用 CPU,就要排队,排队,有 3 种队列:Deadline 最后期限队列 dl_rq,实时任务队列 rt_rq,cfs 公平队列 cfs_rq. 每种队列中排队的任务比较多,事情就会比较复杂,所以需要有默认的、大家都遵循的‘优先级’,和出现紧急情况,能灵活调整的‘调度策略’。

● 如:在机场、火车站,排队上机(车),大多数人,都在排队,但是,如果有人快要误点了,这个人一般就是可以进入优先队列,被优先调度进入上机区域,这就是最后期限队列 dl_rq;而老、弱、病、残或 VIP 人,他们又会单独一个队列,一般都可以随进随走,快速通过的,这就是实时队列 rt_rq;其他人,没有特殊身份,就只能在一起排队,先后通过,这就是公平队列 cfs_rq,但,cfs_rq 队列实在太长了,总会有个别特殊情况的吧,对于突发情况,总得有个应对策略吧,所以,就有调度策略。

⚫ NI 是代表 nice 的意思,是一个进程用户态的一个概念;PR 代表 priority 优先级,是进程的实际优先级,是进程内核态的一个概念。

● 一个进程,就好比一个人。人,总是说 琐事缠身,但是,也会有些自己想做主动做的事情。琐事,可能不需要大脑想很多,就是机械的做,这是 NI;而有些事,需要通过自己大脑思考,主动去做,这是 PR。

⚫ 对于一个普通任务进程来说,PR 的值等于 NI 的值加 20,即:PR=NI+20, 所以,你就会发现,当进程的 NI 为 0,PR 就是 20;NI 为-20,PR 就是 0. 我们平时启动的一个进程,如果没有特意去指定任务优先级的话,默认情况下,都是普通任务进程,NI 的值为 0。
 

● cfs 公平队列 cfs_rq,它的进程都是普通任务进程。

⚫ -20 是 NI 的最小值,也就是说,此进程的用户态拥有最高优先级,进程运行,当需要进行用户态和内核态的转换时,这种,就有着最高的优先级,优先被执行调度。

● NI 相当于我们日常琐事,-20,说明你有很多事情没有完成,身体非常累,你现在最要紧的是把事情做完,所以,此时是拥有最高优先级的;0,说明你没事可做,做事的优先级就最低。

⚫ 进程列表中 NI 值越低,代表:这个进程在系统所有的进程中拥有最高优先级,会优先被调度,但是,并不代表这个进程将会有大量的进程上下文切换。

linux top上的res_开发语言_04

● 在 top 命令中,CPU 使用情况的数据中,也有一个 ni,这个 ni 是:用户进程空间内改变过优先级的进程占用 CPU 百分比。它是系统所有进程发生了用户态到系统态的调度,一个进程的用户态到另一个进程用户态间的调度,他们总的占用 CPU 时间比。

单个进程 NI 值低,拥有高的优先级,但是,如果这个进程被使用的少,它占用 CPU 的调度时间也会少,对 CPU 的 ni 值影响也会就少。所以,请不要把这两个 ni 强行关联。

⚫ 对于一个实时任务进程来说,PR 内核态优先级为 rt(Realtime),这种任务,在 CPU 中实时执行。

● Deadline 最后期限队列 dl_rq,实时任务队列 rt_rq,这两中队列的进程,都是 实时任务进程

⚫ 普通任务进程(cfs 公平队列 cfs_rq),它的调度策略有两种:SCHED_NORMAL, SCHED_BATCH

⚪ SCHED_NORMAL:没什么特殊,就是普通任务使用的调度策略,就是进程使用 CPU 的时间,每次都相等

⚪ SCHED_BATCH:后台任务调度策略,不与终端交互

⚫ 实时任务进程(Deadline 最后期限队列 dl_rq,实时任务队列 rt_rq),它的调度策略有三种:

SCHED_DEADLINE,SCHED_FIFO,SCHED_RR

⚪ SCHED_DEADLINE:距离当前时间最近的 deadline 任务优先被调度

⚪ SCHED_FIFO:相同优先级的任务,先来先执行;优先级更高的任务,可以插队

⚪ SCHED_RR:循环执行,每个任务分配相同时间,相同优先级任务,轮流执行,如果没有执行完,就到队列末尾,再分配时间执行,而优先级高的任务,可以插队抢先执行

● 三种队列,执行顺序是:Deadline 最后期限队列 dl_rq > 实时任务队列 rt_rq > cfs 公平队列 cfs_rq

实时任务进程,总是会比普通任务进程优先被执行

⚫ 启动一个进程,默认 NI 为 0,是普通任务进程,也可以通过 nice 或 renice 命令,改变进程优先级

nice --help
Usage: nice [OPTION] [COMMAND [ARG]...]
Run COMMAND with an adjusted niceness, which affects process scheduling.
With no COMMAND, print the current niceness.  Niceness values range from
-20 (most favorable to the process) to 19 (least favorable to the process).


Mandatory arguments to long options are mandatory for short options too.
  -n, --adjustment=N   add integer N to the niceness (default 10)
      --help     display this help and exit
      --version  output version information and exit


NOTE: your shell may have its own version of nice, which usually supersedes
the version described here.  Please refer to your shell's documentation
for details about the options it supports.


GNU coreutils online help: <http://www.gnu.org/software/coreutils/>
For complete documentation, run: info coreutils 'nice invocation'

nice -n 优先级整数 进程命令 可以在启动进程时指定进程用户态的优先级 NI

renice --help


Usage:
 renice [-n] <priority> [-p|--pid] <pid>...
 renice [-n] <priority>  -g|--pgrp <pgid>...
 renice [-n] <priority>  -u|--user <user>...


Options:
 -g, --pgrp <id>        interpret argument as process group ID
 -n, --priority <num>   specify the nice increment value
 -p, --pid <id>         interpret argument as process ID (default)
 -u, --user <name|id>   interpret argument as username or user ID
 -h, --help             display help text and exit
 -V, --version          display version information and exit


For more information see renice(1).

renice -n 优先级整数 -p 进程id 重新更改进程的用户态优先级 NI

注意:nice 的范围是 [-20, 19], 所以在使用这些命令时,优先级整数范围别写错了。

nice 和 renice 命令,可以修改进程的优先级,但是,再怎么改,这个进程还是普通任务进程,如果,你想把一个任务指定为实时任务进程,则使用 chrt 命令

chrt --help
Show or change the real-time scheduling attributes of a process.


Set policy:
 chrt [options] <priority> <command> [<arg>...]
 chrt [options] --pid <priority> <pid>


Get policy:
 chrt [options] -p <pid>


Policy options:策略
 -b, --batch          set policy to SCHED_BATCH
 -d, --deadline       set policy to SCHED_DEADLINE
 -f, --fifo           set policy to SCHED_FIFO
 -i, --idle           set policy to SCHED_IDLE
 -o, --other          set policy to SCHED_OTHER
 -r, --rr             set policy to SCHED_RR (default)


Scheduling options:
 -R, --reset-on-fork       set SCHED_RESET_ON_FORK for FIFO or RR
 -T, --sched-runtime <ns>  runtime parameter for DEADLINE
 -P, --sched-period <ns>   period parameter for DEADLINE
 -D, --sched-deadline <ns> deadline parameter for DEADLINE


Other options:
 -a, --all-tasks      operate on all the tasks (threads) for a given pid
 -m, --max            show min and max valid priorities
 -p, --pid            operate on existing given pid
 -v, --verbose        display status information
 -h, --help     display this help and exit
 -V, --version  output version information and exit


For more details see chrt(1).

chrt -f -p 进程id 修改某个进程为实时任务进程,设置进程的调度策略为 SCHED_FIFO,进程用户态优先级 NI 为某个整数