DPDK场景下GRUB与cpuset的分工
结论
DPDK 低时延 / 零丢包场景下,GRUB 启动参数和 cpuset 都要配置,但不是配两遍同样的隔离,而是分工不同、缺一不可:
- GRUB(内核启动参数)负责"把内核噪声搬走":让调度器、tick、RCU、中断别落在 DPDK 专用核上;
- cpuset / EAL(运行期)负责"把 DPDK 线程钉上去":保证 PMD 线程真的落在这批核上,且别的进程不来抢。
只配 GRUB 不配绑核:DPDK 线程不一定落在预期核上;只绑核不配 GRUB:核上依然有 tick / RCU / 中断抖动,低时延指标出不来。两边核号集合必须一致。
分析基于的版本
- Linux 内核:cgroup v2(5.x 起
cpuset.cpus.partition支持隔离分区;isolcpus=domain走HK_TYPE_DOMAIN_BOOT); - DPDK:20.x ~ 25.x(EAL
-l/--lcores/--lcores=<lcore>@<cpu>绑核方式一致); - 参考文档:Linux 内核官方
admin-guide/cpu-isolation.rst、core-api/housekeeping.rst、Intel DPDK 官方性能报告。
一、GRUB 和 cpuset 本身会冲突吗
不会在系统层冲突(不会启动失败、内核崩溃),但两者都是 CPU 隔离机制,叠加使用确实存在机制不一致。

关键机制:isolcpus=domain 由内核的 HK_TYPE_DOMAIN_BOOT 管理,它"忽略由 cpuset 执行的隔离";而 cpuset 隔离分区修改的是 HK_TYPE_DOMAIN。两套 housekeeping cpumask 各自维护、互不同步,叠加时就可能配置打架。
三个具体冲突点:
- 隔离可被绕过:
isolcpus只是把核移出调度器默认池,这些核仍留在 root cpuset 的cpuset.cpus中,cpuset /taskset仍可显式把任务放上去;硬件中断也照样会落在"隔离"核上。 - 两套掩码互不同步:
HK_TYPE_DOMAIN_BOOT(isolcpus)与HK_TYPE_DOMAIN(cpuset 分区)各管各的,housekeeping 任务可能被排到"已隔离"的核上。 - 已记录的真实故障:Red Hat 已知问题(RHEL 6/7)——内核更新后 cpuset 不再在
isolcpus的 CPU 上做负载均衡,任务分配行为异常。
另外有个硬约束:系统必须至少保留 1 个在线 housekeeping CPU(通常 CPU0),不能把全部核隔离。
二、DPDK 场景:两边各干什么

2.1 GRUB 侧(必配,且不止 isolcpus)
Intel DPDK 官方性能报告的标准内核行就是 isolcpus + nohz_full + rcu_nocbs 一组同时给,并注明 nohz_full / rcu_nocbs 对零丢包很关键。
| 参数 | 作用 |
|---|---|
isolcpus=<DPDK核> |
把核移出调度器默认负载均衡 |
nohz_full=<DPDK核> |
关闭周期 tick(要求核上只有一个任务) |
rcu_nocbs=<DPDK核> |
RCU 回调外移到 housekeeping 核 |
irqaffinity=<管理核> |
中断默认绑到 housekeeping 核 |
| 可选 | nosmt、iommu=pt、intel_pstate=disable、processor.max_cstate=、numa_balancing=disable、巨页 |
示例(DPDK 专用核 2-7,管理核 0-1):
GRUB_CMDLINE_LINUX="isolcpus=nohz,domain,managed_irq,2-7 nohz_full=2-7 rcu_nocbs=2-7 irqaffinity=0-1 intel_iommu=on iommu=pt default_hugepagesz=1G hugepagesz=1G hugepages=16"
新式写法(内核官方推荐):调度器域隔离交给 cgroup v2 cpuset partition(运行时可调),GRUB 只写 nohz_full、irqaffinity、isolcpus=managed_irq,<核>,避免与 cpuset partition 在同一批核上叠用。
2.2 cpuset 侧(需要,但角色是"把 DPDK 送上去")
isolcpus 只是让调度器"默认不往这些核放任务",但还要保证 DPDK 线程确实落在这些核上。三种等价绑核方式,选一种即可,不要全叠:
- DPDK EAL
-l <核列表>/--lcores:启动时用pthread_setaffinity_np把 lcore 钉到指定核——裸机最简,这种情况甚至不需要单独 cpuset; - systemd
AllowedCPUs=/ K8s CPU pinning / cgroupcpuset.cpus:服务化、容器化管理时推荐,整个进程树都被约束; taskset -cp:一次性临时绑核,调试用。
三、避坑点
- 核号必须一致:GRUB 里
isolcpus/nohz_full/rcu_nocbs的核 = cpuset / EAL 给 DPDK 的核,错配是最常见的"配了没效果"。 - 不要对同一批核同时用
isolcpus=domain和 cgroup v2cpuset.cpus.partition=isolated——这就是HK_TYPE_DOMAIN_BOOT忽略 cpuset 隔离的坑。 - 一核一个 PMD 线程:
nohz_full只在核上跑单个任务时生效;核上多个活任务会自动恢复 tick,nohz 白配。main / 管理线程放 housekeeping 核。 - 至少保留一个 housekeeping 核(通常 CPU0):中断、RCU 回调、未绑定 workqueue / kthread、内务统计都跑在这里。
- 确认 irqbalance 不再把中断迁回 DPDK 核;
irqaffinity=只是默认值,网卡中断仍需检查。
四、验证方法
# 查看内核隔离的核
cat /sys/devices/system/cpu/isolated
# 查看某 cgroup 的实际可用核
cat /sys/fs/cgroup/<path>/cpuset.cpus.effective
# 查看中断亲和性
cat /proc/irq/*/smp_affinity
# 查看 DPDK 进程绑核情况
taskset -cp <dpdk-pid>
# 抖动 / 噪声实测
rtla osnoise
一句话总结
GRUB 写 isolcpus=<核> nohz_full=<核> rcu_nocbs=<核> irqaffinity=<管理核>,应用侧用 EAL -l 或 systemd AllowedCPUs= 钉住同一批核——前者搬走内核噪声,后者钉住数据面线程,这就是 DPDK 官方性能报告里"零丢包"配置的完整形态。
浙公网安备 33010602011771号