理解CPU亲和性及使用nice和renice设置进程优先级

使用Linux的`taskset`、`nice`和`renice`来调整CPU亲和性和进程优先级,而不会使关键任务资源匮乏。

理解CPU亲和性及使用nice和renice设置进程优先级

当Linux主机感觉繁忙时,您可能需要比“让调度器决定”更多的控制。CPU亲和性控制进程可以在哪里运行,而nicerenice则影响进程竞争CPU时间的强度。

本指南展示了如何使用tasksetnicerenice,并提供实际示例以及在更改生产工作负载之前需要注意的权衡。

CPU亲和性:将进程绑定到特定核心

CPU亲和性是一种机制,允许操作系统将进程或线程绑定到特定的CPU或一组CPU。当进程绑定到某个CPU核心时,它只会在该核心上执行。这有几个性能影响:

  • 减少缓存失效: 现代CPU有多级缓存(L1、L2、L3),用于存储频繁访问的数据。当进程在不同CPU核心之间迁移时,其在先前核心缓存中的数据会失效,并且必须为新核心获取新数据。将进程绑定到单个核心可确保其数据保留在该核心的缓存中,从而加快访问速度。
  • 最小化上下文切换: 当调度器决定在某个核心上运行不同进程时,当前进程的状态会被保存(上下文切换),并加载新进程的状态。如果进程频繁在核心之间移动,这些上下文切换的开销会累积。CPU亲和性可以通过将进程保持在同一个核心上来减少这种开销。
  • NUMA架构: 在非统一内存访问(NUMA)系统中,内存访问时间因CPU核心及其与内存控制器的距离而异。将进程绑定到特定核心还可以确保其访问本地内存,从而减少延迟。

如何设置CPU亲和性

虽然Linux内核通常自动管理CPU亲和性,但管理员可以手动影响它。主要工具是taskset

使用taskset

taskset命令允许您检索或设置正在运行的进程的CPU亲和性掩码,或者使用指定的亲和性启动新命令。

语法:

  • 查看正在运行的进程的CPU亲和性:

    taskset -p <PID>
    
  • 设置正在运行的进程的CPU亲和性:

    taskset -p <mask> <PID>
    

    <mask>是一个十六进制数,表示允许的CPU的位掩码。例如,0x1(二进制0001)表示CPU 0,0x2(二进制0010)表示CPU 1,0x3(二进制0011)表示CPU 0和1,依此类推。

  • 使用特定的CPU亲和性启动新命令:

    taskset -c <cpu_list> <command>
    

    <cpu_list>是CPU ID或范围的逗号分隔列表(例如,00-31,3)。

示例:

假设您想运行计算任务my_program并将其绑定到CPU核心3:

taskset -c 3 ./my_program

如果my_program已经在运行,PID为12345,并且您想用亲和性掩码限制它:

taskset -p 1 12345

该命令使用十六进制掩码,因此1表示CPU 0。要将进程移动到CPU 1,请使用-c和CPU编号:

taskset -cp 1 12345

提示: 您可以使用nproc或检查/proc/cpuinfo来确定可用的CPU数量。

警告: 错误设置CPU亲和性可能导致性能下降。最好在有无亲和性设置的情况下对应用程序进行基准测试,以确认收益。

使用nicerenice管理进程优先级

CPU亲和性决定了进程在哪里运行,而进程优先级决定了它相对于其他进程获得多少CPU时间。Linux使用“nice值”的概念来控制调度优先级。nice值的范围从-20(最高优先级,最多CPU时间)到+19(最低优先级,最少CPU时间)。进程的默认nice值为0。

较高的nice值意味着进程对其他进程更“友好”,让出更多CPU时间。相反,较低的nice值意味着进程不那么“友好”,会尝试获取更多CPU时间。

nice命令

nice命令用于以修改后的nice级别运行程序。它通常用于启动新进程。

语法:

nice -n <niceness_level> <command>
  • -n <niceness_level>:指定nice值(如果未指定,默认为10)。

示例:

要以低优先级(高nice值15)运行my_background_task

nice -n 15 my_background_task

要以高优先级(低nice值-10)运行my_critical_app

nice -n -10 my_critical_app

重要说明: 只有root用户才能分配负的nice值(提高优先级)。普通用户只能增加自己进程的nice值(降低优先级)。

renice命令

renice命令用于更改一个或多个已在运行的进程的nice级别。

语法:

renice -n <niceness_level> -p <PID>
  • -n <niceness_level>:新的nice值。
  • -p <PID>:要修改的进程的进程ID。

示例:

要将进程12345的优先级降低(增加nice值)到10

renice -n 10 -p 12345

要将进程54321的优先级提高(减少nice值)到-5(需要root权限):

sudo renice -n -5 -p 54321

renice还可以按用户(-u)或进程组(-g)定位进程。

示例:

要将用户www-data拥有的所有进程的nice值设置为5

sudo renice -n 5 -u www-data

提示: 使用tophtop查看正在运行的进程的nice值(NI列),并识别需要调整优先级的候选进程。

警告: 给进程非常高的优先级(低nice值)可能会使其他进程资源匮乏,并使系统无响应。请谨慎使用,尤其是在生产系统上。

实际场景和最佳实践

CPU亲和性场景:

  • 数据库服务器: 将数据库进程绑定到特定核心可以通过确保数据保留在CPU缓存中来提高查询性能。
  • 高频交易应用程序: 这些通常需要最小延迟和可预测的性能,因此CPU绑定至关重要。
  • 虚拟化主机: 将特定核心专用于虚拟机或主机本身,以提高隔离性和性能。

进程优先级场景:

  • 批处理作业/后台任务: 这些可以以高nice值(nice -n 15)运行,这样它们就不会干扰交互式用户任务或关键服务。
  • 交互式应用程序: 通过不让后台任务消耗所有CPU资源,确保桌面应用程序或shell保持响应。
  • 紧急资源分配: 在极少数情况下,如果关键系统进程遇到困难,可以使用renice(以root身份)临时提高其优先级。

最佳实践:

  1. 先进行基准测试: 在应用CPU亲和性或优先级更改之前和之后,始终测量性能。收益并不总是有保证的,并且可能依赖于应用程序。
  2. 了解您的硬件: 在设置CPU亲和性时,了解您的CPU拓扑(核心、插槽、NUMA节点)。
  3. 使用top/htop 监控CPU使用率、nice值和进程状态,以识别性能问题并测试更改。
  4. 提高优先级需要root权限: 请记住,只有root才能降低nice值(提高优先级)。请明智地使用此权限。
  5. 从保守开始: 对于优先级调整,从适中的nice值(例如5、10)开始,然后再走向极端(-20或+19)。
  6. 考虑NUMA感知: 对于NUMA系统,像numactl这样的工具提供了对CPU和内存绑定的更高级控制。

要点

当放置很重要时(例如NUMA敏感的服务或隔离的批处理作业),请使用CPU亲和性。当问题是调度优先级时,请使用nicerenice。从小更改开始,优先使用taskset -c以获得可读的CPU列表,并在将调优规则设为永久之前进行基准测试。