性能指标与度量:吞吐量、响应时间、资源利用率、调度延迟、公平性指标
做调度系统性能调优,第一件事不是动手改代码,而是先搞清楚——你到底要优化什么?
我见过不少团队,上来就盯着 CPU 使用率猛调,结果吞吐量上去了,响应时间却炸了。说白了,指标没对齐,努力全白费。这一章,咱们就把调度系统最核心的五个指标掰开揉碎讲清楚。
2.1 吞吐量(Throughput)
吞吐量,就是系统在单位时间内能处理的任务数量。比如每秒处理多少个请求,每分钟调度多少个作业。
公式很简单:
吞吐量 = 完成任务数 / 时间窗口
我个人习惯把吞吐量分成两类来看:
- 最大吞吐量:系统在极限压力下能扛住的最大值。压测时经常看这个。
- 稳定吞吐量:系统在正常负载下,长期维持的均值。这个更有实际意义。
2.2 响应时间(Response Time)
响应时间,就是用户发出请求到收到响应之间的耗时。你想想看,你点一个按钮,转圈转了 5 秒,你什么感觉?
响应时间通常看这几个分位值:
| 指标 | 含义 | 典型阈值 |
|---|---|---|
| P50(中位数) | 一半请求比这个快,一半比这个慢 | < 200ms |
| P95 | 95% 的请求比这个快 | < 500ms |
| P99 | 99% 的请求比这个快 | < 1s |
嗯,这里要注意:平均响应时间是个坑。如果 99% 的请求都是 100ms,但有 1% 的请求是 10s,平均值可能只有 200ms,看起来很美,实际上那 1% 的用户已经骂娘了。所以我建议重点盯 P99。
2.3 资源利用率(Resource Utilization)
资源利用率,就是 CPU、内存、磁盘、网络这些硬件被用了多少。说白了,你花钱买的服务器,到底用上了几成?
常见的度量方式:
- CPU 利用率:用户态 + 内核态 + 等待 I/O。注意,100% 不一定代表满载,可能是 I/O 等待虚高。
- 内存利用率:已用内存 / 总内存。要区分“已分配”和“实际使用”,Java 堆经常预分配一大块。
- 磁盘 I/O 利用率:磁盘读写时间占比。超过 80% 就要警惕了。
我个人的经验是:资源利用率不是越高越好。把 CPU 压到 95% 以上,看起来利用率很高,但一旦出现突发流量,系统直接雪崩。我一般建议留 20%-30% 的余量。
2.4 调度延迟(Scheduling Latency)
调度延迟,指的是任务从“就绪”到“真正开始执行”之间的等待时间。这是调度系统特有的指标。
举个例子:你提交了一个任务,它在队列里排了 10ms 才被调度器分配到一个核心上开始跑。这 10ms 就是调度延迟。
调度延迟的构成:
- 排队延迟:任务在就绪队列里等待的时间。
- 上下文切换开销:调度器切换任务时,保存/恢复寄存器、缓存失效等。
- 调度器自身开销:调度算法本身的执行时间。
2.5 公平性指标(Fairness)
公平性,就是调度器能不能让所有任务“雨露均沾”。别让某个任务一直饿着,也别让某个任务霸占资源不放。
衡量公平性,最经典的是 Jain 公平性指数:
J(x₁, x₂, ..., xₙ) = (∑xᵢ)² / (n × ∑xᵢ²)
其中 xᵢ 是第 i 个任务获得的资源量。结果在 0 到 1 之间:
- 1:完全公平,每个任务分到的资源一模一样。
- 接近 0:极度不公平,某个任务独占资源。
举个例子:3 个任务,资源分配分别是 [10, 10, 10],Jain 指数 = 1.0。如果是 [20, 5, 5],Jain 指数 ≈ 0.68。你看,差距一下就出来了。
2.6 五维指标的关系与权衡
这五个指标不是孤立的。你动一个,其他四个都会跟着变。我画了一张图,帮你理清它们之间的关系:
从图上你能看到,所有指标都指向调度系统这个核心。你调整任何一个,都会通过调度器传导到其他指标上。
举个例子:你为了提高资源利用率,把 CPU 跑满。结果任务排队时间变长,调度延迟上升,响应时间也跟着涨。这时候如果你强行降低调度延迟,频繁切换任务,上下文开销又会让吞吐量下降。你看,牵一发而动全身。
2.7 如何选择关键指标
不同场景,关注的重点不一样。我列了一个对照表:
| 业务场景 | 首要指标 | 次要指标 | 可牺牲指标 |
|---|---|---|---|
| 实时交易系统 | 响应时间(P99) | 吞吐量 | 资源利用率 |
| 离线批处理 | 吞吐量 | 资源利用率 | 响应时间 |
| 云原生调度 | 公平性 | 资源利用率 | 调度延迟 |
| 流式处理 | 调度延迟 | 吞吐量 | 公平性 |
你看,没有银弹。你得先搞清楚业务要什么,再决定优化哪个指标。