首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> Java 程式設計 >> Java 綜合教學

Spark 調度策略深度解析:FIFO vs Fair Scheduler 核心算法、資源分配與生產調優

     編輯:Java 綜合教學

Spark 調度器核心:FIFO 與 Fair 兩大調度策略算法原理、代碼實現與生產調優指南

Spark 採用兩層調度架構:DAGScheduler 切分 Stage、TaskScheduler 分發 Task。TaskScheduler 內部通過 SchedulingAlgorithm 接口實現 TaskSet/Pool 的優先級排序。本文深度解析 FIFO 与 Fair 兩種算法的比較器邏輯、資源分配模型與調優參數。

1. 調度算法接口定義

private[spark] trait SchedulingAlgorithm {
  def comparator(s1: Schedulable, s2: Schedulable): Boolean
}

兩個實現類:FIFOSchedulingAlgorithm、FairSchedulingAlgorithm。

2. FIFO 調度器:簡單優先級隊列

class FIFOSchedulingAlgorithm extends SchedulingAlgorithm {
  override def comparator(s1: Schedulable, s2: Schedulable): Boolean = {
    val p1 = s1.priority
    val p2 = s2.priority
    var res = math.signum(p1 - p2) // 優先級數值越小優先級越高
    if (res == 0) {
      val st1 = s1.stageId
      val st2 = s2.stageId
      res = math.signum(st1 - st2) // 同優先級按 StageId 先來先服務
    }
    res < 0
  }
}
  • 特點:全局單隊列,優先級高(數值小)的 Job 獨佔資源,低優先級可能長期飢餓。
  • 適用場景:單租戶、批處理為主、Job 之間無公平性要求。
  • 配置:spark.scheduler.mode=FIFO(默認)。

3. Fair 調度器:多隊列加權公平分享

3.1 核心比較邏輯

class FairSchedulingAlgorithm extends SchedulingAlgorithm {
  override def comparator(s1: Schedulable, s2: Schedulable): Boolean = {
    val minShare1 = s1.minShare
    val minShare2 = s2.minShare
    val running1 = s1.runningTasks
    val running2 = s2.runningTasks

    val needy1 = running1 < minShare1  // 是否處於「飢餓」狀態
    val needy2 = running2 < minShare2

    // 1. 飢餓者優先
    if (needy1 && !needy2) return true
    if (!needy1 && needy2) return false

    // 2. 同為飢餓/同為飽滿:比較資源占用比 或 權重比
    if (needy1 && needy2) {
      // 都飢餓:minShareRatio = runningTasks / minShare,比例小的優先(貪心策略)
      val ratio1 = running1.toDouble / math.max(minShare1, 1.0)
      val ratio2 = running2.toDouble / math.max(minShare2, 1.0)
      return ratio1.compareTo(ratio2) < 0
    } else {
      // 都飽滿:taskToWeightRatio = runningTasks / weight,比例低的優先(權重大的優先)
      val ratio1 = running1.toDouble / s1.weight
      val ratio2 = running2.toDouble / s2.weight
      val cmp = ratio1.compareTo(ratio2)
      if (cmp != 0) return cmp < 0
    }

    // 3. 完全相同:按名字字典序
    s1.name < s2.name
  }
}

3.2 關鍵概念

3.3 層級調度樹

  • Root Pool(默認名 root)
  • 子 Pool:每個用戶/組/應用一個 Pool,配置 minShare、weight、schedulingMode。
  • 葉子節點:TaskSetManager(代表一個 Stage 的 Task 集合)。
  • 調度器遞歸比較:先比較 Pool 之間優先級,再進入 Pool 內部比較 TaskSet。

4. fairscheduler.xml 範例

<?xml version="1.0"?>
<allocations>
  <pool name="production">
    <minShare>10</minShare>
    <weight>3</weight>
    <schedulingMode>FAIR</schedulingMode>
  </pool>
  <pool name="analytics">
    <minShare>5</minShare>
    <weight>1</weight>
    <schedulingMode>FIFO</schedulingMode>
  </pool>
  <pool name="default">
    <minShare>2</minShare>
    <weight>1</weight>
  </pool>
</allocations>

啟動:spark.scheduler.mode=FAIR、spark.scheduler.allocation.file=fairscheduler.xml。

5. 生產調優實戰

屬性含義配置途徑
minShare最小資源保障(CPU 核數),低於此值視為飢餓fairscheduler.xml → pool.minShare
weight權重,決定飽滿狀態下的資源分配比例fairscheduler.xml → pool.weight
schedulingModePool 內部 TaskSet 排序模式:FIFO/FAIRfairscheduler.xml → pool.schedulingMode

6. 進階:動態分配與調度器協同

  • spark.dynamicAllocation.enabled=true:Executor 根據 pending tasks 自動增減。
  • Fair Scheduler 感知 Executor 變化,重新計算 runningTasks、minShare 滿足度。
  • 結合 spark.scheduler.revive.interval(默認 1s)控制調度器重新評估頻率。

7. 總結

  • FIFO:簡單、吞吐優先、適合單租戶批處理。
  • Fair:多租戶隔離、最小保障 + 加權公平、適合混合負載(ETL + Ad-hoc + Streaming)。
  • 核心調優桿子:minShare(保底)、weight(分成)、schedulingMode(Pool 內公平)、dynamicAllocation(彈性)。
  • 監控指標:SchedulerDelay、TaskQueueLength、PoolStarvationTime,接入 Grafana 告警。

理解調度器比較器邏輯與資源模型,是從「會用 Spark」進階到「駕馭 Spark 集群」的關鍵一步。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved
問題原因調優動作
重要 Job 長期等待低優先級 Job 佔用資源(FIFO)或權重過低(Fair)提高 priority / weight,設置 minShare 保障底線資源
小 Job 被大 Job 卡死Fair 模式下大 Job 佔滿核心,小 Job 進入飢餓增加小 Job Pool minShare,或啟用動態分配 spark.dynamicAllocation.enabled=true
資源利用率低minShare 總和 > 集群總核心,導致部分 Pool 永遠飢餓審計 minShare 總和 ≤ 總核心 × 0.8,預留 20% 彈性
同 Pool 內 TaskSet 爭搶schedulingMode=FIFO 導致後提交 Stage 餓死改為 FAIR,或拆分為子 Pool