调度策略基础:FIFO、公平调度、容量调度的原理与对比

调度策略这东西,说白了就是「谁先拿资源」的规则。我刚开始做集群管理时,觉得调度嘛,不就是排队?后来被现实狠狠教育了一顿。你想想看,一个 Hadoop 集群几百台机器,任务五花八门,要是调度策略选错了,轻则资源浪费,重则线上事故。

今天咱们就聊聊三种最基础的调度策略:FIFO、公平调度和容量调度。嗯,别看它们老,但理解透了,后面学 YARN、Kubernetes 调度会轻松很多。

一、FIFO 调度:先来先服务

FIFO,全称 First In First Out,先进先出。这应该是人类最直观的调度方式了——谁先提交任务,谁就先拿资源。

核心思想:一个全局队列,任务按提交时间排序。前面的任务不跑完,后面的只能等着。

我在项目中遇到过一个小团队,他们用 Hadoop 跑离线报表,数据量不大,FIFO 用得好好的。后来业务扩张,报表任务和临时查询混在一起,问题就来了——一个跑 2 小时的报表堵住队列,后面 5 分钟的临时查询硬生生等了 1 小时 50 分钟。

FIFO 的优缺点:

  • 优点:实现简单,逻辑清晰,适合小规模、任务类型单一的集群。
  • 缺点:容易产生「队头阻塞」——一个大任务卡住,后面所有小任务都得等。

避坑指南:我曾经在一个 20 节点的集群上用过纯 FIFO,结果一个 Spark 任务把内存吃光了,后面 MapReduce 任务全部 OOM。后来我学乖了——FIFO 只适合「任务大小差不多」的场景,否则一定要加资源限制。

二、公平调度(Fair Scheduling):雨露均沾

公平调度,顾名思义,就是让每个任务都能分到资源。它不像 FIFO 那样死板,而是动态调整——任务多就每人分一点,任务少就让某个任务多吃点。

为什么会这样?因为公平调度引入了「最小保证」的概念。每个任务池(Pool)都有一个最低资源保障,比如 20% 的 CPU。即使其他任务再多,这个池也能拿到至少 20%。

核心机制:公平调度器会定期计算每个任务的「资源缺口」——当前资源与应得资源的差距。缺口越大的任务,优先级越高。

我记得有一次帮客户调优,他们 100 个节点跑着 3 个部门的任务。用 FIFO 时,A 部门的大任务经常把 B、C 部门的小任务饿死。换成公平调度后,每个部门至少能拿到 30% 的资源,虽然大任务跑得慢了,但整体满意度反而高了。

公平调度的关键参数:

  • minimum:每个池的最小资源保障
  • maximum:每个池的最大资源上限
  • weight:权重,权重高的池在资源竞争时能分到更多

个人经验:公平调度适合多租户场景。但要注意——如果所有池都设了很高的 minimum,集群资源不够分时,调度器会陷入「死锁」,谁也跑不动。我建议 minimum 总和不要超过集群总资源的 80%。

三、容量调度(Capacity Scheduling):分田到户

容量调度和公平调度有点像,但思路更「硬」。它把集群切成多个「队列」,每个队列有固定的容量上限。比如队列 A 占 50%,队列 B 占 30%,队列 C 占 20%。

你想想看,这就像分田到户——每家分一块地,你家地里的活再多,也不能占邻居的地。除非邻居的地闲着,你才能临时借用一下。

核心区别:公平调度是「动态平衡」,容量调度是「静态划分」。容量调度更强调隔离性——一个队列的任务再疯狂,也不会影响其他队列。

我在金融行业见过一个典型场景:生产队列和测试队列共用集群。用容量调度,生产队列占 70%,测试队列占 30%。测试任务再浪,也最多吃掉 30% 的资源,生产任务稳如泰山。

容量调度的核心概念:

  • 容量(Capacity):队列保证能拿到的资源百分比
  • 最大容量(Maximum Capacity):队列最多能拿到的资源百分比(防止借太多)
  • 弹性(Elasticity):队列空闲时,资源可以借给其他队列

注意:我曾经遇到一个坑——容量调度下,如果队列 A 的容量是 50%,但它的任务很少,队列 B 借走了 30%。突然队列 A 来了个大任务,需要立刻收回资源。这时队列 B 的任务会被强制杀死!所以「弹性」一定要配合「抢占(Preemption)」机制使用,否则会出事故。

四、三种策略的对比

说了这么多,咱们用一张表来总结:

特性 FIFO 公平调度 容量调度
资源分配方式 顺序分配 动态平衡 静态划分
任务隔离性 无 弱(可借用) 强(有上限)
适用场景 小集群、单用户 多租户、负载波动大 多租户、需要强隔离
实现复杂度 低 中 高
典型代表 Hadoop 1.x 默认 YARN Fair Scheduler YARN Capacity Scheduler

五、核心逻辑流程图

下面这张 SVG 图展示了三种调度策略的核心逻辑。我画的时候特意把「队列」和「资源池」的关系标出来了,你一看就明白。

三种调度策略核心逻辑对比 FIFO 调度 任务队列(按时间排序) 队头任务 → 获取全部资源 队尾任务 → 等待 公平调度 多个任务池(Pool) 动态计算资源缺口 缺口大 → 优先分配 容量调度 固定队列(Queue) 队列 A: 50% | B: 30% | C: 20% 超容量 → 等待或抢占 一句话总结 • FIFO:谁先来谁先吃,吃完了下一个 • 公平调度:大家轮流吃,饿了的先吃 • 容量调度:分桌吃饭,不能抢别人碗里的 选择建议:小集群用 FIFO,多租户用公平调度,强隔离用容量调度

六、如何选择?

说实话,没有「最好」的调度策略,只有「最合适」的。我个人的选择经验是这样的:

  • 集群小于 10 节点,任务类型单一:FIFO 就够了,别折腾。
  • 多部门共用集群,任务大小不一:公平调度,灵活且公平。
  • 生产环境,需要强隔离:容量调度,稳字当头。

一个小技巧:如果你不确定选哪个,可以先从公平调度开始。它最灵活,后期可以平滑迁移到容量调度。我在好几个项目里都是这么干的——先用公平调度跑一段时间,观察资源使用模式,再决定要不要切到容量调度。

嗯,调度策略的基础就聊到这儿。这三种策略是后续学习 YARN、Kubernetes 调度的基石。你想想看,理解了「先来后到」「公平分配」「容量隔离」这三个核心思想,后面那些花里胡哨的调度器,本质上都是它们的变体或组合。

可可精品资料库