isolcpus 单独使用无法彻底隔离 cpu,必须配合 nohz_full、rcu_nocbs、irqbalance 禁用及 cpuset 限制等措施,才能消除周期 tick、中断、rcu 回调和内核线程干扰,实现微秒级低抖动。

isolcpus 单独用,隔离不干净,抖动照来
只加 isolcpus=2,3,看似把 CPU2/3 从调度器负载均衡里踢出去了,但其实很多内核干扰还在:周期性调度 tick(比如每秒 100 次的时钟中断)、RCU 回调、softirq、kworker 线程,都可能偷偷跑上去。你绑了进程,top 看 CPU 占用也低,但一测延迟,P99 抖动还是跳变——因为中断或内核线程随时可能抢占你的实时线程。
常见错误现象:perf stat -e irq:softirq_entry,irq:irq_handler_entry -C 2 能抓到大量软硬中断;/proc/interrupts 显示 CPU2 上仍有网卡、定时器等中断;cat /proc/sys/kernel/timer_migration 是 1(默认),意味着高精度定时器会跨核迁移,进一步破坏确定性。
-
isolcpus只影响 CFS 调度器的 load balance,不关 tick,不挪 RCU,不拦中断 - 必须配合
nohz_full才能停掉周期 tick;配合rcu_nocbs才能把 RCU 回调甩出去 - 若系统没开
CONFIG_NO_HZ_FULL=y(老内核如 3.10 默认关),nohz_full直接无效
nohz_full 是抖动杀手,但有硬性前提
nohz_full=2,3 的核心作用是让指定 CPU 进入「全动态滴答」状态:只要上面只跑一个不可抢占任务(如 SCHED_FIFO 线程),就彻底停掉周期性调度时钟中断。这不是“减少”,而是“归零”——除了残留的 1Hz 统计 tick(已卸载到非隔离核),CPU2/3 上再无定时器唤醒。
但它很娇气,踩错一个条件就退化回普通模式:
- 必须只有一个可运行任务:两个
SCHED_FIFO线程在同一个隔离核上?tick 立刻回来 - 不能用
posix-cpu-timers(比如timer_create(CLOCK_PROCESS_CPUTIME_ID)) - 不能用
perf事件(perf record -C 2会强制 tick 复活) - x86 平台需 TSC 稳定(
rdmsr 0x10查 MSR_IA32_TSC_DEADLINE 可用性)
实操建议:启动后立刻用 cat /sys/devices/system/clocksource/clocksource0/current_clocksource 确认是 tsc;再用 grep "NO_HZ" /proc/timer_list | grep "cpu: 2" 看是否显示 “dyntick idle” —— 不是这个,说明没生效。
irqbalance 和 cpuset 必须同步封口,否则前功尽弃
内核参数管不到用户空间中断分发和内核线程调度范围。nohz_full 再干净,如果网卡中断还往 CPU2 上砸,或者 ksoftirqd/2 自己跑上去,抖动一样爆表。
关键配置点:
-
IRQBALANCE_BANNED_CPULIST=2,3(写进/etc/sysconfig/irqbalance或/etc/irqbalance/irqbalance.env),让 irqbalance 主动绕开隔离核 -
echo 0-1 > /sys/fs/cgroup/cpuset/cpuset.cpus(root cpuset 剔除 2,3),否则 kworker/2:x、migration/2 等默认内核线程仍可能落上去 -
echo 2-3 > /sys/fs/cgroup/cpuset/rt_app/cpuset.cpus+echo $PID > /sys/fs/cgroup/cpuset/rt_app/tasks,把业务线程锁死在隔离核,且只在此 cpuset 下运行
漏掉任意一项,ps -eLo pid,lwp,cls,pcpu,psr,args | grep -E "(kworker|ksoftirqd|migration)" 都可能看到它们出现在 CPU2 上。
验证抖动是否真降下来:别只看 top,要看 timer_list 和 perf
很多人改完参数,top 显示 CPU2 空闲就以为成功了。但抖动藏在微秒级行为里,得用更底层工具交叉验证。
三步快速验效:
- 查 tick 是否真停:
grep "jiffies:" /proc/timer_list | grep "cpu: 2"—— 如果输出里还有 “jiffies: N”,说明 tick 没关;应为 “dyntick idle” 或完全无输出 - 查中断分布:
watch -n1 'cat /proc/interrupts | grep -E "(eth|timer|resched)"',确认 CPU2 列数字长期为 0(除可能的 IPI) - 测真实抖动:
sudo perf record -e 'sched:sched_switch' -C 2 -g -- sleep 10,然后perf script | awk '{print $9}' | sort -n | tail -20看上下文切换间隔分布,稳定在毫秒级以下才算过关
最容易被忽略的是:nohz_full 依赖用户线程主动声明不可抢占。哪怕你绑了核、设了 SCHED_FIFO,如果线程里调了 read() 或 malloc() 导致睡眠,它就不再是“唯一可运行任务”,tick 会瞬间复活。所以真正低抖动场景,往往要搭配 busy-wait、mlockall、hugepage 等一整套手法——单靠内核参数,只是打地基而已。










