Slide 1

Slide 1 text

Kube-scheduler: from 101 to the frontier Kensei Nakada (@sanposhiho)

Slide 2

Slide 2 text

本日の目標 SIG-Scheduling は最近特に大きな機能追加をしていません。

Slide 3

Slide 3 text

本日の目標 SIG-Scheduling は最近特に大きな機能追加をしていません。 だからと言ってサボっているわけではなく、 内部で色々な改善を行っているわけです。

Slide 4

Slide 4 text

本日の目標 SIG-Scheduling は最近特に大きな機能追加をしていません。 だからと言ってサボっているわけではなく、 内部で色々な改善を行っているわけです。 色々大きな内部の改善をやってきているのですが、理解には Schedulerの深めの知識が 必要であり、あまり日の目に浴びることはない ...

Slide 5

Slide 5 text

本日の目標 SIG-Scheduling は最近特に大きな機能追加をしていません。 だからと言ってサボっているわけではなく、 内部で色々な改善を行っているわけです。 色々大きな内部の改善をやってきているのですが、理解には Schedulerの深めの知識が 必要であり、あまり日の目に浴びることはない ... このセッションは、最近私たちがやっていることを周辺知識を全て拾いながら 解説していくことで、 皆さんも知識が深まりハッピー、僕も自慢できてハッピーを目指すセッションです

Slide 6

Slide 6 text

Hello! こんにちは ! 👋 Kensei Nakada (@sanposhiho) • Software Engineer @ • Kubernetes maintainer (SIG-Scheduling approver, SIG-Autoscaling) • Kubernetes contributor award 2022, 2023

Slide 7

Slide 7 text

Image Locality Taint/Toleration Kubernetes Scheduler SchedulerはPodをどのNodeで実行するか決めるコンポーネント Resource Ports NodeAffinity PodAffinity/AntiAffinity etc etc… Many factors to consider…

Slide 8

Slide 8 text

Scheduler Plugins 各Scheduling制約はPluginとして実装されている Image Locality Plugin TaintToleration Plugin Resource Fit Plugin NodePorts Plugin NodeAffinity Plugin Inter-Pod Affinity Plugin etc etc… Kubernetes scheduler consists of many plugins:

Slide 9

Slide 9 text

Scheduling Framework Schedulerの基礎となるフレームワーク こいつがPluginなどを良きタイミングで実行してくれている Filter Podを実行できないNodeを除外 する (リソース不足、NodeAffinityに 反する、etc) Score Nodeに点数をつけて最もその Podを実行するに好ましいNode を最終決定 (Image locality, etc)

Slide 10

Slide 10 text

No content

Slide 11

Slide 11 text

×
 ×
 それぞれのPluginが何かしらの観点でNodeをフィ ルタリングする

Slide 12

Slide 12 text

×
 ×
 12 残ったNodeに対して、それぞれのPluginが何かし らの観点でNodeをスコアリングする

Slide 13

Slide 13 text

80
 60
 ×
 ×
 13 最終的にNode2が選ばれる

Slide 14

Slide 14 text

Scheduling Framework More extension points actually…

Slide 15

Slide 15 text

Scheduling Framework Scheduling cycle: SchedulerがPodをどのNodeで動かすか決定す るフェーズ。 Podを1つ1つ処理していく。

Slide 16

Slide 16 text

Scheduling Framework Binding cycle: API serverにScheduling結果を伝える。 goroutineで非同期に実行される。

Slide 17

Slide 17 text

The recent developments ● 最近は大きな機能の追加などを行なっていない ○ KEPもv1.28スタートのQueueingHint (後述) が最後 ● 内部ではPerformanceの改善に集中

Slide 18

Slide 18 text

Performance matters! ● Schedulerは基本的にクラスター内に1つだけ ○ Scheduling ThroughputがクラスターのPod作成速度よりも下回るとスケジュールされてない Podが溜まっていってしまう。 ○ アップストリームでは全てのシナリオで 300 Pods/s以上キープを目標にしている。 scheduler-perf(後述)で計測。 ● Scheduler のパフォーマンス改善は複数のエリアにまたがる ○ Scheduling Framework自体のパフォーマンス ○ Pluginのパフォーマンス ○ Requeueingの正確性 (scheduling cycleの無駄使いを減らす)

Slide 19

Slide 19 text

Scheduling Framework 前述のようにBinding Cycleは非同期で実行され る&ほぼAPIを呼び出すだけなため、 パフォーマンス改善的にはあまり関係ない。 Binding cycleに辿り着くまでの時間を短縮した い。

Slide 20

Slide 20 text

Scheduling Framework Scheduling cycleはPodを1つ1つ処理していくた め、パフォーマンスへの影響が大きい 。

Slide 21

Slide 21 text

パフォーマンス改善 1: Scheduling Cycle Pod1つあたりのSchedulingにかかる時間を減らす ● Plugin自体の処理効率を上げる ○ 事前に計算できる部分は PreXXXXに処理を移す ● FrameworkのInterfaceに手を加えてより効率的にPluginが動けるようにする ○ PreFilterResult: 複数のNodeをPreFilter時点で除外できるようにする ○ Skip: 不要なPluginはその後の拡張点で呼ばれないようにする ● PreemptionのAPIの呼び出しを非同期に (KEP-4832, 計画中未実装)

Slide 22

Slide 22 text

パフォーマンス改善 1-1: plugins Plugin自体の処理効率を上げるために、 PreXXXXを活用した事前処理を行う。 ● PreFilterはScheduling cycle中に一度だけ呼び出され、 Filterを実行する前に共通の事前計算を行える ● FilterはそれぞれのNodeに対して実行されるため、 できるだけ事前計算できる部分は PreFilterに移動した方が効率が良い

Slide 23

Slide 23 text

この例だと、 FilterAは4回、FilterBは3回呼び出 される。 実際にはPreFilterA/BがFilterA/Bの呼び出し 前に一度実行されるので、 そこで共通の事前計算を行う。

Slide 24

Slide 24 text

パフォーマンス改善 1-2: framework ● PreFilterResult: 複数のNodeをPreFilter時点で除外できるようにする ○ 例: metadata.nameに対するNodeAffinityがPodに指定されている時、PreFilterの段階で、その指 定Node以外を除外できる ● Skip: 不要なPluginはその後の拡張点で呼ばれないようにする ○ 例: NodeAffinityを持っていないPodのSchedule中、NodeAffinityを呼び出す必要はない → NodeAffinity#PreFilterがSkipを返すことでFilterが呼ばれなくなる

Slide 25

Slide 25 text

Scheduling Framework Scheduling cycleはScheduling QueueからPodを 1つずつ取り出してScheduleしていく

Slide 26

Slide 26 text

Scheduling Framework Filterの結果どのNodeもPodを受け入れること ができない場合もある このPodどこにも行けへんわ ...

Slide 27

Slide 27 text

Scheduling Framework とりま一旦Queueに戻ってもろて 優先度低いPodを殺したらこいつ Scheduleできるんちゃう...? (Preemption)

Slide 28

Slide 28 text

Preemption 優先度の高いPodがScheduleできなかった場合、 優先度の低い既存のPodを殺すことでScheduleできる可能性を探る。 Node1 high-priority-Pod Node1上のpod2つ殺したら、 俺入れるかもしれんな ...

Slide 29

Slide 29 text

Preemption 優先度の高いPodがScheduleできなかった場合、 優先度の低い既存のPodを殺すことでScheduleできる可能性を探る。 Node1 high-priority-Pod 殺しちゃお。 これで次のScheduling cycleで 俺はNode1行けるはずやで ❌ ❌ Pod deletion

Slide 30

Slide 30 text

パフォーマンス改善 1-3: preemption (WIP) Preemptionが発生する場合、Pod削除などのAPI呼び出しの部分で時間がかかってしま い、全体のScheduling throughputに影響が出る。 Binding cycleを非同期に実行しているように、 PreemptionのAPI呼び出し部分も非同期に行って、他の PodのSchedulingをブロックしない ようにしたい (KEP-4832として議論中)

Slide 31

Slide 31 text

Scheduling Framework Preemptionを試みたのち、 PodはScheduling Queueに戻され、リトライを待 つことになる とりま一旦Queueに戻ってもろて 優先度低いPodを殺したらこいつSchedule できるんちゃう...? (Preemption)

Slide 32

Slide 32 text

Scheduling Framework Preemptionを試みたのち、 PodはScheduling Queueに戻され、リトライを待 つことになる とりま一旦Queueに戻ってもろて 優先度低いPodを殺したらこいつSchedule できるんちゃう...? (Preemption) このPodはいつスケジューリングのリトライをすべき?? 🤔

Slide 33

Slide 33 text

パフォーマンス改善 2: 無駄なSchedulingを減らす Scheduling cycleはPodを1つ1つ処理していくため、無闇にPodのSchedulingはリトライして はいけない。 無駄打ちのScheduling cycleが増えるほど全体のThroughputが落ちる...

Slide 34

Slide 34 text

パフォーマンス改善 2: 無駄なSchedulingを減らす Scheduling cycleはPodを1つ1つ処理していくため、無闇にPodのSchedulingはリトライして はいけない。 無駄打ちのScheduling cycleが増えるほど全体のThroughputが落ちる... 次のSchedulingでScheduleされる見込みがある場合のみリトライしたい。

Slide 35

Slide 35 text

Scheduling Queue Schedule待ちのPodはScheduling Queueにて待機させられる。 内部は3つの待機場所に別れている: ● ActiveQ: Schedule待ちのPodたち ● BackoffQ: Backoff中のPodたち。Backoff終了後ActiveQへ移動される。 ● Unschedulable Pod Pool: 待機中のPodたち

Slide 36

Slide 36 text

Scheduling Queue さっきのPodは一旦Unschedulable Pod Poolに 戻されることになる。

Slide 37

Slide 37 text

Scheduling Queue 「どのPlugin(s)のせいでこのPodは Unschedulableになったのか」が記憶される

Slide 38

Slide 38 text

Scheduling Queue ResourceFitが記録されている場合、 新しいNodeの作成によってこのPodは Schedulableになるかもしれない EventHandlerを通して クラスター上のリソースの 作成/変更/削除を監視している

Slide 39

Slide 39 text

Nodeの追加を検知したタイミングでPodを移動 する。 NodeAdd Node追加されたし ResourceFitに弾かれたこのPod 今ならScheduleできるかもなぁ

Slide 40

Slide 40 text

PodはbackoffQを通って、ActiveQに移動され、 順番が来たらScheduling cycleへ... NodeAdd Node追加されたし ResourceFitに弾かれたこのPod 今ならScheduleできるかもなぁ

Slide 41

Slide 41 text

意味のないNodeAddだったらどうする..? 例: Podは8CPU欲しいのに、追加されたNodeは4CPUしか持っ てない NodeAdd

Slide 42

Slide 42 text

KEP-4247: QueueingHint どのClusterEventでPodをRequeueするか問い合わせることで正確なリトライを行う 例: NodeAdd or Updateが発生した時にisSchedulableAfterNodeChangeが呼び出される。 isSchedulableAfterNodeChangeがそのNodeAdd/UpdateでPodをQueueすべきか否かを決定する。

Slide 43

Slide 43 text

ResourceFit PluginのQueueingHintが実際に追 加されたNodeを確認する NodeAdd QueueingHint この追加されたNodeは 十分大きいリソース持ってるので PodをQueueしよう!

Slide 44

Slide 44 text

ResourceFit PluginのQueueingHintが実際に追 加されたNodeを確認する NodeAdd QueueingHint この追加されたNodeは Podに対してリソース小さすぎるので Podはunschedにキープ! ❌

Slide 45

Slide 45 text

パフォーマンス改善 2: 無駄なSchedulingを減らす QueueingHintによって、Queueのタイミングをより正確に決定できるようになった 2つのメリット ● 無駄なScheduling cycle消費が減る。

Slide 46

Slide 46 text

パフォーマンス改善 2: 無駄なSchedulingを減らす QueueingHintによって、Queueのタイミングをより正確に決定できるようになった 2つのメリット ● 無駄なScheduling cycle消費が減る。 ● Podが受けるBackoffの時間が短くなる。 ← 🤔

Slide 47

Slide 47 text

[復習] Scheduling Queue Schedule待ちのPodはScheduling Queueにて待機させられる。 内部は3つの待機場所に別れている: ● ActiveQ: Schedule待ちのPodたち ● BackoffQ: Backoff中のPodたち。Backoff終了後ActiveQへ移動される。 ● Unschedulable Pod Pool: 待機中のPodたち

Slide 48

Slide 48 text

BackoffQ…? そもそもなぜBackoffQが必要なのか? ● Schedulerにおける、BackoffとはScheduling cycleを浪費した罰である ○ Scheduling cycleを浪費すればするほどその PodのBackoffは長くなっていく ● 特定のPodがScheduling cycleを浪費しまくって、他のPodのSchedulingが遅れるのを 防ぐために必要

Slide 49

Slide 49 text

パフォーマンス改善 2: 無駄なSchedulingを減らす QueueingHintによって、Queueのタイミングをより正確に決定できるようになった 2つのメリット ● 無駄なScheduling cycle消費が減る。 ● Podが受けるBackoffの時間が短くなる。 ○ ↑ QueueingHintは無駄なScheduling cycleの浪費を減らすことは、 PodがBackoffを受ける回数を減らす(時間も短くする)ことにもなる

Slide 50

Slide 50 text

その他: scheduler-perf アップストリームで使用しているパフォーマンステスト。 perf-dash.k8s.io を見にいくとコミットごとに結果がグラフ化されている。

Slide 51

Slide 51 text

その他: scheduler-perf アップストリームで使用しているパフォーマンステスト。 perf-dash.k8s.io を見にいくとコミットごとに結果がグラフ化されている。

Slide 52

Slide 52 text

その他: scheduler-perf アップストリームで使用しているパフォーマンステスト。 perf-dash.k8s.io を見にいくとコミットごとに結果がグラフ化されている。 ● テストケースごとに閾値を決めて、 Throughputが閾値を下回ったらメンテナにメー ルを飛ばす ○ 今までデグレを見逃しまくってきた過去あり ● Queueing周りのテストケースを増やす (QueueingHint向け)

Slide 53

Slide 53 text

その他: scheduling queueのロック改善 ● Scheduling Queueは1つのロックを使用して排他制御していた ● QueueingHintの導入等でQueueがイベントの処理にかかる時間が増加 ○ イベント処理中もロックは取りっぱなし ● Scheduling cycleがQueueからPodを取り出す時にもロックが必要 → イベント処理がロックを取りまくるせいで Scheduling cycleの開始が妨害されThroughput が低下

Slide 54

Slide 54 text

その他: scheduling queueのロック改善 内部で使用するロックをいい感じに分割しまくることで、イベント処理が Scheduling cycleを 阻害しないように改善。 今までで一番難しい PRレビューだったかも。 絶対Deadlockとかやらかすわ、と思ってたけど、 意外と問題は起こらなかった (今のとこ)

Slide 55

Slide 55 text

THANK YOU!