12.3 两层调度 (Mesos)
一句话
Mesos 把调度拆成两层:分配器(allocator) 决定 “把哪些资源给谁”,框架调度器(framework scheduler) 决定 “用这些资源跑哪些任务”;它用 offer(资源报价) 代替共享状态,避免了全局锁,但 offer 会 过期——资源给你了,你犹豫,就浪费了。
两层分工
| 层 | 角色 | 职责 | 不做什么 |
|---|---|---|---|
| 资源层 | Master + Allocator | 汇总 Agent 资源,按策略(DRF/公平)生成 offer | 不决定具体任务放哪 |
| 框架层 | Framework Scheduler(如 Spark/Marathon) | 收到 offer,决定接受/拒绝、跑哪些任务 | 不直接访问 Agent 资源 |
| Agent 层 | 每台机器上的 agent | 上报资源、启动 executor | 不参与全局分配 |
offer 生命周期:生成 → 发给框架 → 接受(资源锁定)→ 启动任务 → 拒绝/超时(资源回收再分配)。
实测:offer 过期导致的拒绝
模拟 300 节点 × 8 核、2000 个 1 核任务,15% 的决策基于过期 offer:
| 架构 | 成功 | 拒绝/冲突 |
|---|---|---|
| 单体 | 2000/2000 | 0 |
| 两层(offer) | 1860/2000 | 7.0% 拒绝 |
| 共享状态 K=4 | 1878/2000 | 23.1% 冲突 |
7% 的拒绝不是 “bug”,而是 offer 模型的固有成本:框架拿到 offer 时资源还在,决定用的时候可能已被别人拿走或已过期。这也是 Mesos 后来引入 “资源预留/revocable offers” 的原因。
浪费率 ≈ 拒绝率 × offer 平均持有时间 / 决策周期
优化方向:缩短 offer 超时 + 让框架 “快速决策”
代码:offer 的接受与拒绝
func (f *Framework) OnOffer(o Offer) {
need := f.pendingTasks()
if len(need) == 0 {
f.decline(o) // 没任务就别占着,立即归还
return
}
fit := filter(o.Resources, need) // 框架自己决定放哪些
if len(fit) == 0 {
f.decline(o)
return
}
f.accept(o, fit) // 接受后资源锁定,启动 executor
}
关键:框架必须 “要么用、要么立刻还”,犹豫就会让资源闲置,而分配器无法感知 “框架在思考”。
反模式
| 反模式 | 后果 |
|---|---|
| 框架收到 offer 后慢慢决策 | offer 过期,资源浪费,集群利用率下降 |
| 一个框架垄断所有 offer | 多框架公平性失效(需要 DRF/配额) |
| offer 粒度太大(整机) | 小任务用不完,资源碎片化 |
| offer 粒度太小(单核) | 通信与决策开销爆炸 |
| 分配器不做 “拒绝回填” | 被拒资源闲置到下一个周期 |
| 框架无 “资源需求声明” | 分配器只能猜,offer 命中率低 |
三条铁律
🔑 offer 是 “限时报价”:不立刻用就还回去。
🔑 两层调度的收益是 “解耦与多框架”,代价是 “信息陈旧”。
🔑 offer 粒度 = 资源利用率与开销的平衡点,不是越细越好。
自检
Q1 两层调度相比单体,最大的收益是什么?
▸ 答案:解耦与多框架共存:资源分配(全局策略)与任务放置(框架自己的语义)分开,不同框架(Spark、Marathon、Hadoop)可以共享一个集群,而不需要把各自的调度逻辑塞进一个中心调度器。代价是 offer 的信息陈旧与拒绝浪费。
Q2 为什么 offer 会 “过期”?
▸ 答案:因为资源是动态的:分配器发 offer 时资源空闲,但框架决策需要时间,期间资源可能被其他框架拿走、或节点故障、或 offer 超时。Mesos 用 “超时回收” 处理,框架则要 “快决策、早归还”。
Q3 DRF(主导资源公平)在两层调度里起什么作用?
▸ 答案:它决定 offer 给谁:按 “各框架的主导资源份额” 排序,份额小的优先。这样多框架之间的资源分配接近公平,而不是 “谁先请求谁拿”。DRF 属于分配器层,框架层不感知(见 12.5 公平调度算法 (MMF / DRF))。
Q4 offer 粒度为什么不能太细?
▸ 答案:因为每次 offer 都有通信与决策开销:生成、传输、框架评估、接受/拒绝、状态更新。粒度到 “单核” 时,一个 800 核集群每轮要发几百个 offer,框架侧的处理成本会超过调度收益。
Q5 框架 “拒绝 offer” 有什么代价?
▸ 答案:短期是资源闲置(从拒绝到下一轮分配之间),长期是分配器对该框架的需求估计变差(它不知道你是 “不需要” 还是 “暂时不需要”)。所以框架应尽量 “接受能用的部分”,而不是整单拒绝。
Q6 两层调度适合什么场景,不适合什么?
▸ 答案:适合多框架共享集群、框架有自己复杂调度语义的场景(大数据生态)。不适合 “单一业务、追求极致利用率” 的场景——此时单体或共享状态更简单高效。判断依据是 “是否需要多种调度语义共存”。
Q7 现代系统还用两层调度吗?
▸ 答案:思路还在,形态变了:K8s 用 “调度器 + 扩展点(scheduler framework)+ 多调度器”,YARN 用 “ResourceManager + ApplicationMaster”,都是 “资源分配与任务放置分离” 的变体。纯粹的 “offer 模型” 在大数据之外较少见,因为它的信息陈旧成本较高。
关联
- 前置:12.1 资源调度的目标与抽象
- 并列:12.2 单体调度 (Borg)、12.4 共享状态调度 (Omega)
- 下游:12.5 公平调度算法 (MMF / DRF)、61.1 Hadoop 生态(YARN 资源模型)