第四篇:《CPU 深度调优:调度器、进程优先级与 Cgroups》
用工具发现了问题下一步是解决问题。CPU 调优的核心是理解“CPU 时间是如何分配给各个进程的”——这取决于调度器的策略、进程优先级的设置以及Cgroups的资源限制。本文深入讲解 Linux 的 CFS 调度器原理、nice 值与实时优先级、CPU 亲和性taskset以及容器时代最重要的 Cgroups v2 CPU 子系统帮你从“被动发现”走向“主动调控”。一、CFS 调度器Linux 的“公平裁判”1.1 什么是 CFSCFSCompletely Fair Scheduler完全公平调度器 是 Linux 内核从 2.6.23 版本开始使用的默认进程调度器。它的设计目标是让所有进程公平地分享 CPU 时间。1.2 CFS 的核心原理CFS 摒弃了传统调度器复杂的优先级数组和轮转算法采用了一个非常 elegant 的设计虚拟运行时间vruntime 每个进程都有一个 vruntime 值表示该进程已获得的 CPU 时间经过优先级加权。红黑树Red-Black Tree CFS 将所有可运行进程按 vruntime 排序vruntime 最小的进程被优先调度。公平性保证每次调度时CFS 选择 vruntime 最小的进程运行。运行一段时间后该进程的 vruntime 增加会被放到树后面让其他进程有机会运行。简单来说谁获得的 CPU 时间最少谁就先运行。这就是“完全公平”的含义。1.3 调度周期与时间片CFS 不是用固定的时间片而是根据目标延迟target latency 动态计算。例如目标延迟设为 20ms系统中有 2 个可运行进程每个进程获得约 10ms。系统中有 10 个可运行进程每个进程获得约 2ms。进程数量越多每个进程分到的时间片越短上下文切换越频繁。二、进程优先级如何“插队”虽然 CFS 追求公平但 Linux 允许你通过优先级影响调度结果。2.1 Nice 值静态优先级nice 值是 Linux 中最常用的优先级调整方式范围是 -20最高优先级到 19最低优先级 默认值为 0。nice 值 含义-20 到 -1 高优先级需要 root 权限或 CAP_SYS_NICE0 默认优先级1 到 19 低优先级nice 值影响的是 CFS 的 vruntime 增长速度nice 值越低 → vruntime 增长越慢 → 获得更多 CPU 时间nice 值越高 → vruntime 增长越快 → 获得更少 CPU 时间调整方式# 启动时设置 nice 值nice-n19make-j$(nproc)# 以最低优先级运行编译任务[reference:46]# 运行时调整需要 root 权限降低 nice 值renice-5-p1234# 将 PID 1234 的 nice 值调整为 -5[reference:47]sudorenice-10-p1234# 提高优先级[reference:48]⚠️ 注意普通用户只能提高 nice 值降低优先级不能降低 nice 值提高优先级。降低 nice 值需要 root 权限。2.2 实时调度策略chrt对于对响应时间有严格要求的任务如音频处理、工业控制系统可以使用实时调度策略。# 查看进程的调度策略chrt-p1234# 设置 FIFO 实时调度策略优先级 501-99sudochrt-f-p501234# 以 RR 实时调度策略启动新进程sudochrt-r99./realtime_app调度策略类型SCHED_OTHER默认的 CFS 调度策略普通进程。SCHED_FIFO先进先出实时调度高优先级进程会一直运行直到主动让出。SCHED_RR轮转实时调度同优先级进程轮转执行。⚠️ 警告实时调度策略会抢占普通进程使用不当可能导致系统卡死。仅用于经过充分测试的实时应用。三、CPU 亲和性taskset把进程“钉”在核心上CPU 亲和性CPU Affinity是将进程绑定到特定 CPU 核心上运行。它的价值在于提升缓存命中率进程始终在同一个核心上运行L1/L2 缓存数据不会失效。隔离关键业务将核心业务进程绑定到独立核心避免被其他进程干扰。3.1 查看和设置 CPU 亲和性# 查看进程的 CPU 亲和性taskset-p1234# 输出pid 1234s current affinity mask: f二进制 1111表示可用 4 个核心# 将进程绑定到 CPU 0 和 CPU 1taskset-cp0,11234# 启动新进程并绑定到 CPU 0-3taskset-c0-3 ./myappCPU 掩码taskset 使用位掩码表示 CPU 核心。掩码 1二进制 0001→ CPU 0掩码 3二进制 0011→ CPU 0 和 CPU 1掩码 f二进制 1111→ CPU 0-33.2 实战场景场景一将网络密集型进程绑定到专用核心# 将网卡中断绑定到 CPU 2需配置 /proc/irq/*/smp_affinity# 将应用进程绑定到 CPU 3taskset-c3./nginx场景二NUMA 架构下的性能优化在多路 CPU 服务器上将进程绑定到同一个 NUMA 节点的核心上可以避免跨节点内存访问的额外延迟。# 查看 NUMA 拓扑numactl--hardware# 将进程绑定到 NUMA 节点 0 的 CPU 0-7numactl--cpunodebind0--membind0./myapp四、Cgroups容器时代的资源管控CgroupsControl Groups 是 Linux 内核提供的资源限制机制是 Docker 和 Kubernetes 实现资源隔离的底层技术。在生产环境中你通常不会直接修改进程的 nice 值而是通过 Cgroups 来限制容器的 CPU 使用。4.1 Cgroups v2 CPU 子系统Cgroups v2 是当前的主流版本其 CPU 控制器通过两个核心文件控制资源文件 作用 示例cpu.max 设置 CPU 配额上限 100000 100000 1 个 CPU 核心cpu.weight 设置 CPU 权重相对优先级 范围 1-10000默认 100查看当前容器的 CPU 配额cat/sys/fs/cgroup/cpu.max# 输出100000 100000表示可以使用 1 个 CPU 核心[reference:57]cpu.max 的格式quota在一个周期内允许使用的 CPU 时间微秒period周期长度微秒默认 100000quota / period 可使用的 CPU 核心数配置 含义100000 100000 1 个 CPU 核心50000 100000 0.5 个 CPU 核心200000 100000 2 个 CPU 核心max 100000 无限制使用所有可用 CPU4.2 在容器环境中应用Docker 限制 CPUdockerrun--cpus2--cpu-shares1024myapp–cpus2限制容器最多使用 2 个 CPU 核心对应 cpu.max–cpu-shares1024设置 CPU 权重对应 cpu.weightKubernetes 限制 CPUresources: requests: cpu:500m# 保证 0.5 个 CPU 核心limits: cpu:1000m# 最多使用 1 个 CPU 核心requests调度器保证的最小资源软限制limits容器允许使用的最大资源硬限制对应 cpu.max4.3 为什么 Cgroups 比 nice 更适合生产环境五、CPU 调优的层次与选择最佳实践容器环境优先使用 Cgroups通过 K8s 的 resources.limits 和 requests 声明式管理。关键业务使用 taskset 隔离核心将高优先级业务绑定到独立核心避免被系统进程干扰。临时调试使用 nice/renice快速降低编译任务的优先级不影响在线服务。避免在生产环境随意使用实时调度chrt 可能让系统失去响应。六、小结CFS 调度器通过 vruntime 实现进程间的公平调度。nice 值-20 到 19影响进程的 CPU 时间分配renice 可运行时调整。taskset 将进程绑定到特定 CPU 核心提升缓存命中率。Cgroups v2 是容器时代资源管控的标准通过 cpu.max 限制 CPU 配额。理解这些机制你就不仅能“看到” CPU 问题还能主动“调控”CPU 资源分配。