上一篇记的是运行期能改的 sysctl。这一篇是另一类东西:写在 GRUB 里、开机时传给内核的引导参数(kernel command line)。它们和 sysctl 有个本质区别——sysctl 改错了大不了回滚,引导参数改错可能直接让机器进不去系统,而且你在 SSH 上看不到任何报错,只能去 IPMI/串口控制台救。
这串参数不是我们原创,是在网上流传的一份"调优内核引导参数",有人直接整段贴进 GRUB_CMDLINE_LINUX 就重启了。我们把它完整留在这里,但要明确:这不是推荐配置,是一份我们拿来逐条审过的参考。里面有相当一部分我们在生产机上坚决不开,原因会在下面说清楚。按用途分组看,比当成一长串咒语照抄有用得多。
先给一条铁律:改引导参数之前,确保你有带外管理(IPMI/iDRAC/串口)能进 GRUB。没有带外、机器又在远端机房的,不要碰这些。
日志、审计与启动显示
| 参数 | 作用 |
|---|---|
loglevel=3 | 内核控制台打印级别设为 3,少刷屏。 |
rd.udev.log_priority=3 | initramfs 里 udev 的日志级别设为 3。 |
rd.systemd.show_status=auto | 启动时自动显示 systemd 状态。 |
log_buf_len=2M | 内核日志环形缓冲区设为 2M,排障时能留下更多历史。 |
audit=1 | 启用内核审计子系统。 |
这组基本无害,是我们会保留的。唯一要注意 audit=1 在高并发系统调用的机器上有可感知的开销,如果没有合规需求可以关掉。
cgroup 与容器
| 参数 | 作用 |
|---|---|
systemd.unified_cgroup_hierarchy=false | 关闭 cgroup v2 统一层级,退回 v1。 |
systemd.legacy_systemd_cgroup_controller=false | 关闭旧版 systemd cgroup 控制器。 |
cgroup_enable=memory | 启用 memory cgroup。 |
cgroup_memory=nokmem | 关闭 kmem 记账(历史上的内存泄漏规避手段)。 |
swapaccount=1 | 启用 swap 记账,容器限制 swap 时需要。 |
这些决定了容器运行时拿到的 cgroup 版本。强行退回 cgroup v1 要谨慎:现在的容器运行时(containerd、podman 新版本)越来越以 v2 为主,退回 v1 可能让新版工具行为异常。我们的取舍是跟着实际跑的运行时版本走,而不是无脑退回 v1。
存储与 I/O
| 参数 | 作用 |
|---|---|
scsi_mod.use_blk_mq=1 | 启用块层多队列(blk-mq),对 NVMe/多队列 SSD 有意义。 |
我们的 NVMe/ZFS 机器上 blk-mq 是默认且想要的,这条可以留;在新内核上它基本已经是默认行为。
内存管理与大页
| 参数 | 作用与风险 |
|---|---|
transparent_hugepage=never | 关闭透明大页(THP)。数据库、ZFS ARC 这类对内存延迟敏感的负载上,关 THP 通常是对的,能避免 THP 整理带来的延迟尖刺。这是少数我们明确推荐的。 |
cma=128M | 预留 128M 连续内存给 CMA。只有特定设备(某些 DMA)需要,没有对应硬件就是白占。 |
init_on_free=0、init_on_alloc=0 | 关闭分配/释放时的内存清零。换一点性能,代价是牺牲了一层防信息泄露的加固——这是安全和性能的直接取舍。 |
vsyscall=none | 关闭老的 vsyscall 接口,收紧攻击面,现代系统上安全。 |
注意源里写的是 domain init_on_free=0, init_on_alloc=0,中间带了个 domain 和逗号,这其实是粘贴时混进来的噪声,真正的内核参数就是 init_on_free=0 和 init_on_alloc=0 两个,中间不该有逗号。照抄原样会让内核把 domain 当成一个无法识别的参数。
CPU 电源与频率(追求低延迟)
| 参数 | 作用与风险 |
|---|---|
intel_pstate=disable | 禁用 intel_pstate 调频驱动。 |
processor.max_cstate=0 / intel_idle.max_cstate=0 | 禁止 CPU 进入深度 C-state。 |
idle=halt | 空闲时用 halt 而非更省电的方式。 |
cpufreq.off=1 | 关闭频率调节。 |
pcie_aspm=off | 关闭 PCIe 省电。 |
thermal.off=1 | 关闭温控。 |
这一整组是典型的"用功耗换延迟":把 CPU 钉在高频、不让它睡,换取稳定的低延迟响应。在做实时转发、低延迟交易类负载时有意义。代价很直接:功耗和发热大幅上升,电费和机房散热都要跟上。而 thermal.off=1 要特别小心——关掉温控意味着过热时内核不再降频保护,硬件真有散热问题时可能直接烧,我们生产机上不开这一条。普通业务机完全不需要这组参数。
中断、锁与 RCU
| 参数 | 作用与风险 |
|---|---|
threadirqs | 把硬中断处理放到内核线程里,便于调度和隔离。 |
nosoftlockup | 关闭软锁定检测。 |
nmi_watchdog=0 | 关闭 NMI 看门狗,省一点每核开销。 |
rcu_nocbs=0-64 | 把 CPU 0–64 的 RCU 回调卸载到别处,配合 CPU 隔离做低延迟。 |
rcupdate.rcu_expedited=1 | 加速 RCU 宽限期,降延迟、略增 CPU 开销。 |
rcutree.kthread_prio=2 | 提高 RCU 内核线程优先级。 |
skew_tick=1 | 错开各核时钟中断,减少同时唤醒造成的抖动。 |
no_timer_check | 跳过定时器 IRQ 路由检查,省一点启动时间。 |
noreplace-smp | 关闭 SMP 相关的代码替换优化。 |
这组是给专门调过 CPU 隔离的低延迟机准备的,尤其 rcu_nocbs=0-64 只有在你真的做了 isolcpus/nohz_full 把这些核隔出来时才有意义,否则是空设。nosoftlockup+nmi_watchdog=0 则是又把上一篇里当安全网的检测关掉了——省了开销,也失去了发现卡死的手段,取舍要清楚。
虚拟化与 IOMMU
| 参数 | 作用 |
|---|---|
intel_iommu=on / amd_iommu=on | 开启 IOMMU,做 PCI 直通(passthrough)的前提。 |
iommu.strict=0 | 非严格模式,延迟 TLB 刷新换性能,代价是直通设备的隔离性略降。 |
kvm-intel.nested=1 | 启用嵌套虚拟化。 |
kvm-intel.vmentry_l1d_flush=never | 关闭进 VM 时的 L1D 刷新——这是关掉 L1TF 的一个缓解,见下面安全一节。 |
pci=realloc | 允许重新分配 PCI 资源,解决某些设备 BAR 空间不够。 |
做 GPU/网卡直通时 intel_iommu=on 是必须的。iommu.strict=0 和各种 flush=never 都是用隔离性换性能,多租户环境要想清楚。
网卡命名
| 参数 | 作用 |
|---|---|
net.ifnames=0 | 关闭 systemd 的可预测网卡命名,网卡回到 eth0 这类传统名字。 |
biosdevname=0 | 同样关闭 BIOS 风格命名。 |
这两条纯看运维习惯。好处是名字短、脚本好写;坏处是多网卡机器上传统命名顺序不稳定,插拔网卡后名字可能对调,自动化反而更容易踩坑。我们在网卡固定、靠 MAC 绑定的机器上才用。
显卡
| 参数 | 作用与风险 |
|---|---|
nomodeset | 禁用内核模式设置(KMS)。 |
vt.cur_default=50 | 设置虚拟终端光标。 |
nomodeset 要特别点名:它会禁掉内核显卡驱动的模式设置,对纯服务器可能无所谓,但在需要显卡驱动正常工作的机器(比如上一篇讲的 GPU 节点)上开 nomodeset,驱动会起不来。这类参数的"好坏"完全取决于机器角色,不能一概照抄。
安全缓解——风险最高的一组
mitigations=off noibrs nopti l1tf=off nospec_store_bypass_disable noibpb spectre_v2_user=off spectre_v2=off
| 参数 | 作用 |
|---|---|
mitigations=off | 一次性关闭所有 CPU 漏洞缓解(这一条就等于下面全部)。 |
nopti | 关闭 KPTI(Meltdown 缓解)。 |
noibrs / noibpb / spectre_v2=off / spectre_v2_user=off | 关闭 Spectre v2 相关缓解。 |
l1tf=off | 关闭 L1TF(L1 终端失效)缓解。 |
nospec_store_bypass_disable | 关闭 SSB 缓解。 |
这是整串参数里我们最要给出警告的部分。 关掉这些缓解确实能拿回被 Meltdown/Spectre 一系列补丁吃掉的性能,在某些计算密集负载上收益可观。但代价是把机器暴露在已知的侧信道漏洞下。在多租户、跑别人代码、或任何不完全可信负载的机器上,绝对不能开——这相当于主动拆掉 CPU 的安全隔离。只有在物理隔离、单租户、确认负载完全可信、并且你确实量到性能瓶颈在这里的前提下,才可以考虑,而且要作为一个明确的风险决策记录下来,而不是随手贴进 GRUB。
其它
| 参数 | 作用与风险 |
|---|---|
selinux=0 | 关闭 SELinux。省心,但也去掉了一层强制访问控制。 |
mce=off | 关闭机器检查异常(MCE)。危险:MCE 是硬件报告内存/CPU 错误的机制,关掉它等于让你对正在发生的硬件故障视而不见,我们不开。 |
noresume | 禁用从休眠恢复,服务器本来也不休眠,无害。 |
workqueue.power_efficient=0 | 关闭省电型工作队列,偏向性能。 |
cryptomgr.notests | 跳过启动时的加密算法自测,省一点启动时间。 |
nosync | 关闭相关忙等待行为。 |
nf_conntrack.acct=0 | 关闭 conntrack 流量计数,省一点每连接开销——对上一篇那种几十万连接的机器有点意义。 |
crashkernel=384M-2G:64M,2G-:128M | 按物理内存大小给 kdump 预留崩溃内核内存。想要崩溃转储就保留。 |
完整参考(原样保留)
下面是源里的完整一行。再强调:这不是让你照抄的配置,是一份评估对象。mitigations=off 那组、mce=off、thermal.off=1、nomodeset 请根据机器角色明确决定,domain ... , 那处是粘贴噪声需要清掉。
loglevel=3 selinux=0 audit=1 rd.systemd.show_status=auto rd.udev.log_priority=3 systemd.unified_cgroup_hierarchy=false systemd.legacy_systemd_cgroup_controller=false scsi_mod.use_blk_mq=1 crashkernel=384M-2G:64M,2G-:128M workqueue.power_efficient=0 domain init_on_free=0, init_on_alloc=0 cma=128M vsyscall=none nosoftlockup mce=off threadirqs noresume nmi_watchdog=0 vt.cur_default=50 transparent_hugepage=never cgroup_enable=memory cgroup_memory=nokmem swapaccount=1 nf_conntrack.acct=0 log_buf_len=2M intel_pstate=disable processor.max_cstate=0 intel_idle.max_cstate=0 thermal.off=1 pci=realloc pcie_aspm=off cpufreq.off=1 idle=halt net.ifnames=0 biosdevname=0 mitigations=off noibrs nopti l1tf=off nomodeset nospec_store_bypass_disable noibpb spectre_v2_user=off spectre_v2=off kvm-intel.vmentry_l1d_flush=never no_timer_check noreplace-smp kvm-intel.nested=1 nosync iommu.strict=0 intel_iommu=on amd_iommu=on cryptomgr.notests rcu_nocbs=0-64 rcupdate.rcu_expedited=1 rcutree.kthread_prio=2 skew_tick=1
正确的做法是:挑出和你机器角色对得上的几条,一次只加一组,改完 grub2-mkconfig 后重启、从带外控制台确认能进系统、再验证关掉的东西没造成功能缺失。引导参数没有"抄一份万能配置"这回事——每台机器的角色不同,该开的和会要命的也不同。
