4. 内存与CPU参数:mem、maxcpus、isolcpus、nohz_full

内存和CPU的启动参数,说白了就是告诉内核:你该用多少硬件资源,以及怎么用。我见过不少刚入行的同事,一上来就默认参数跑,结果要么内存浪费,要么CPU被中断打爆。嗯,今天咱们把这四个参数聊透。

4.1 mem参数:给内核划个内存红线

mem 参数用来限制内核能看见和使用的物理内存总量。你可能会问:“我内存明明有64G,为什么要限制它?”

我遇到过一种场景:做内存热插拔测试时,需要模拟低内存环境。直接在物理机上拔内存条太麻烦,用 mem=4G 启动,内核就只认4G,剩下的空间留给用户态做特殊用途。另一个常见场景是给虚拟机预留大页内存——让内核少占点,用户态才能多拿点。

语法: mem=nn[KMG]
# 只让内核使用 8GB 内存
mem=8G

# 限制为 4096MB
mem=4096M
注意: mem 参数会覆盖BIOS报告的内存大小。设小了,内核直接看不见多余内存;设大了(超过物理内存),内核启动时会崩溃。我曾经在测试机上手滑写成 mem=128G,而机器只有64G,结果内核panic,只能进grub改回来。

4.2 maxcpus参数:控制CPU的“可见度”

maxcpus 控制的是内核在启动初期能使用的CPU核心数。注意,它和 nr_cpus 不一样——nr_cpus 是编译时决定的CPU上限,而 maxcpus 是运行时限制。

我习惯在调试SMP(对称多处理)问题时用这个参数。比如怀疑某个CPU核心有硬件缺陷,可以用 maxcpus=1 强制单核启动,先排除多核交互的问题。

参数 作用 典型值
maxcpus=1 只启动1个CPU核心 调试、单核测试
maxcpus=4 限制最多使用4核 低功耗、资源隔离
maxcpus=0 不启动任何辅助核心 仅用于特殊调试
小技巧: 如果你用 maxcpus=2 启动,系统启动后可以通过 echo 1 > /sys/devices/system/cpu/cpu2/online 动态上线更多核心。这个参数只管“启动时”,不管“运行时”。

4.3 isolcpus参数:把CPU“隔离”出来

isolcpus 是我个人最常用的参数之一。它的作用是把指定的CPU核心从内核的通用调度器中剥离出来。说白了,就是告诉内核:“这几个CPU你别乱用,留给我的专用进程。”

为什么需要隔离?你想想看,默认情况下,内核会把中断、定时器、进程调度均匀地分配到所有CPU上。但对于实时计算、DPDK(数据平面开发套件)这类场景,任何一次上下文切换或中断都可能造成性能抖动。隔离出来的CPU,只运行你指定的任务,干净利落。

# 隔离 CPU 2 和 CPU 3
isolcpus=2,3

# 隔离 CPU 0-3 和 CPU 7
isolcpus=0-3,7
避坑指南: 我曾经在项目中只配了 isolcpus,却没配 irqaffinity,结果中断还是往隔离核上跑。记住:isolcpus 只隔离进程调度,不隔离中断。要配合 irqaffinity 把中断绑定到非隔离核上,才算真正“干净”。

4.4 nohz_full参数:关掉“嘀嗒”时钟

内核有一个周期性时钟(tick),每隔几毫秒就“嘀嗒”一次,用来做进程调度、时间统计等。但在隔离核上,这个嘀嗒声就是噪音。nohz_full 参数可以完全关闭指定CPU上的周期性tick,只在有任务变化时才触发。

我做过一个NFV(网络功能虚拟化)项目,数据面跑在隔离核上,延迟要求微秒级。没开 nohz_full 时,每4ms一次的tick就会造成10-20微秒的抖动。开了之后,抖动直接降到1微秒以下。

# 对 CPU 2-3 关闭周期性 tick
nohz_full=2-3

# 通常和 isolcpus 配合使用
isolcpus=2-3 nohz_full=2-3
黄金组合: isolcpus + nohz_full + rcu_nocbs 是高性能计算的三件套。隔离CPU、关掉tick、再把RCU回调也挪走,隔离核上几乎零干扰。

4.5 参数关系与配置流程

这四个参数不是孤立的。我画了一张图,帮你理清它们之间的关系:

内存与CPU参数关系图 启动参数配置 mem maxcpus isolcpus nohz_full 配置建议: • 先配 mem 确定内存上限,再配 maxcpus 控制CPU数量 • isolcpus 和 nohz_full 必须指向相同的CPU集合 • 别忘了配合 rcu_nocbs 和 irqaffinity 才能达到最佳隔离效果 确定资源需求 配置mem/maxcpus 配置isolcpus 配置nohz_full

4.6 实战配置示例

假设你有一台16核、64G内存的服务器,要跑一个实时数据采集程序。我的建议配置如下:

# /etc/default/grub 中的 GRUB_CMDLINE_LINUX
GRUB_CMDLINE_LINUX="mem=32G maxcpus=8 isolcpus=4-7 nohz_full=4-7 rcu_nocbs=4-7"

解释一下:

  • mem=32G:内核只认32G,剩下32G留给大页或特殊设备
  • maxcpus=8:启动时最多用8个核心
  • isolcpus=4-7:CPU 4-7 被隔离,不跑普通进程
  • nohz_full=4-7:隔离核上关掉周期性tick
  • rcu_nocbs=4-7:隔离核上的RCU回调也挪走
验证方法: 启动后用 cat /proc/cmdline 查看实际生效的参数。再用 cat /sys/devices/system/cpu/isolated 确认隔离核列表。我每次改完参数都会跑一遍这个检查,避免“配了但没生效”的尴尬。

嗯,这四个参数讲完了。记住一个原则:隔离要彻底,配置要配套。只配 isolcpus 不配 nohz_full,就像关了门却开着窗——干扰还是会进来。