任务调度性能指标:吞吐量、延迟、公平性、CPU利用率、上下文切换开销
聊任务调度,绕不开这五个指标。我见过不少团队,上来就调参数,结果越调越糟。为什么?因为他们没搞清楚到底要优化哪个指标。
这五个指标,说白了就是调度器的「五维评价体系」。你想想看,一个调度器好不好,总得有个衡量标准吧?吞吐量、延迟、公平性、CPU利用率、上下文切换开销,就是最核心的五个维度。
核心观点:这五个指标相互制约,不可能同时最优。调度的本质,就是在它们之间做权衡。
吞吐量:单位时间能干多少活
吞吐量,就是单位时间内系统完成的任务数量。比如一个Web服务器,每秒能处理多少个请求。这就是吞吐量。
我个人习惯,先看吞吐量。因为它最直观,也最容易测量。你调完参数,跑个压测,吞吐量上去了,说明方向对了。
但要注意,吞吐量高不代表一切。我曾经优化过一个批处理系统,把吞吐量提升了30%,结果延迟飙升了5倍。业务方直接炸了——他们需要的是实时响应,不是批量处理。
实战技巧:测量吞吐量时,建议用滑动窗口法。取最近1分钟、5分钟、15分钟的平均值,避免被瞬时峰值干扰。
延迟:从提交到完成要多久
延迟,就是任务从提交到完成的时间。分两种:平均延迟和尾延迟(P99、P999)。
平均延迟好理解,但真正要命的是尾延迟。我遇到过最坑的一次,系统平均延迟只有50ms,但P99延迟到了2秒。用户反馈说「偶尔卡一下」,其实就是那1%的请求拖了后腿。
为什么会这样?因为调度器在处理大量短任务时,偶尔会遇到一个长任务卡住队列。后面的短任务全得等。这就是所谓的「队头阻塞」。
避坑指南:我曾经天真地以为平均延迟低就万事大吉,结果被P99打脸。现在我做性能评估,必看P99和P999。如果这两个指标比平均值高一个数量级,说明调度策略有问题。
公平性:别让某个任务饿死
公平性,就是每个任务或每个用户,能不能得到合理的CPU时间。注意,是「合理」,不是「平均」。
举个例子:你有两个任务,一个需要10ms,一个需要10s。如果完全公平,每个任务各占50%的CPU时间,那短任务就惨了——它明明很快就能跑完,却要等长任务释放CPU。
所以公平性要结合任务特性来看。我常用的公平性指标有两个:
- 最大-最小公平性:先满足最小需求,再按比例分配剩余资源
- 加权公平性:给不同优先级的任务分配不同的权重
我记得有一次,一个Hadoop集群跑得好好的,突然某个租户的任务全卡住了。查了半天,发现是公平调度器的权重配错了,导致那个租户的任务一直被饿死。
一句话总结:公平性不是平均主义,而是「按需分配,兼顾优先级」。
CPU利用率:别让CPU闲着
CPU利用率,就是CPU忙活的时间占比。理想情况下,我们希望CPU一直满负荷运转。但现实是,CPU经常在等I/O、等锁、等内存。
这里有个误区:很多人觉得CPU利用率越高越好。其实不然。如果CPU利用率长期在95%以上,说明系统已经过载了。这时候调度器会频繁切换任务,上下文切换开销暴增,吞吐量反而下降。
我个人经验,CPU利用率保持在70%-80%是比较健康的区间。低于60%,说明资源浪费;高于90%,就要警惕了。
测量方法:用top命令看%us(用户态)和%sy(内核态)。如果%sy超过30%,说明系统调用和上下文切换太多了,需要优化。
上下文切换开销:切换是有代价的
上下文切换,就是CPU从一个任务切换到另一个任务时,保存和恢复状态的过程。每次切换,都要保存寄存器、程序计数器、栈指针等。这些操作虽然快,但积少成多。
我做过一个实验:在一个8核机器上,跑1000个线程,每个线程只做简单的加法运算。结果CPU利用率只有20%,但上下文切换每秒超过10万次。大部分CPU时间都花在切换上了,真正干活的时间很少。
上下文切换开销主要来自三个方面:
- 直接开销:保存/恢复寄存器、切换内存映射、刷新TLB
- 间接开销:缓存失效、分支预测器重置
- 系统开销:内核态与用户态切换、调度器决策
避坑指南:我曾经为了「充分利用CPU」,把线程数设成了CPU核心数的4倍。结果上下文切换开销直接让系统吞吐量腰斩。后来我学乖了,线程数一般控制在CPU核心数的1.5倍到2倍之间。
五个指标的关系:一个跷跷板
这五个指标,就像跷跷板的两端。你压下去一个,另一个就翘起来。我画了张图,帮你理清它们的关系。
从图上你能看到,调度策略是中心,五个指标围绕它展开。每个指标都不是孤立的,调整一个,其他四个都会跟着变。
实际场景中的指标取舍
不同场景,侧重点完全不同。我整理了一个表格,方便你对照:
| 场景 | 首要指标 | 次要指标 | 可牺牲指标 |
|---|---|---|---|
| Web服务器 | 低延迟 | 高吞吐量 | 公平性 |
| 批处理系统 | 高吞吐量 | CPU利用率 | 延迟 |
| 实时系统 | 低延迟 | 公平性 | 吞吐量 |
| 云平台多租户 | 公平性 | CPU利用率 | 延迟 |
| 嵌入式系统 | 低上下文切换 | CPU利用率 | 吞吐量 |
你看,没有银弹。每个场景都有自己的「命门」。我见过最离谱的一次,有人把实时系统的调度器调成了吞吐量优先,结果任务频繁超时,整个系统崩了。
我的建议:接手一个系统,先问业务方三个问题:
- 任务最长能等多久?(延迟上限)
- 每秒最少要处理多少任务?(吞吐量下限)
- 不同用户之间要不要隔离?(公平性要求)
问清楚这三个问题,指标取舍就一目了然了。
如何测量这些指标
光说不练假把式。我常用的测量工具和方法:
- 吞吐量:用
perf stat或sar -n DEV 1看每秒完成的任务数 - 延迟:用
wrk或ab做压测,关注P99和P999 - 公平性:用
pidstat -u 1看每个进程的CPU分配比例 - CPU利用率:用
top或htop看%us和%sy - 上下文切换:用
vmstat 1看cs列,或者perf stat -e context-switches
举个例子,用vmstat 1看上下文切换:
$ vmstat 1
procs -----------memory---------- ---swap-- -----io---- -system-- ------cpu-----
r b swpd free buff cache si so bi bo in cs us sy id wa st
2 0 0 123456 1234 56789 0 0 10 20 500 12000 30 10 60 0 0
3 0 0 123456 1234 56789 0 0 12 18 520 13500 32 11 57 0 0
看到cs列了吗?12000和13500,这就是每秒的上下文切换次数。如果这个值超过5万,就要警惕了。
避坑指南:我曾经在生产环境直接跑perf stat,结果性能开销太大,把线上服务拖慢了。后来我学乖了,先用vmstat做初步诊断,确认有问题再用perf做精细分析。
小结
这五个指标,是调度优化的基石。你不需要记住所有细节,但一定要理解它们之间的关系。吞吐量和延迟是一对冤家,公平性和CPU利用率也经常打架。上下文切换开销,则是那个容易被忽略的「隐形杀手」。
嗯,这一章就到这里。记住,调度的本质是权衡,没有完美的调度器,只有适合场景的调度器。