AWS Batchでスケジュールポリシーを使ってジョブごとの重みに従ってコンピューティングリソースの割当が出来るようになりました

2021.11.11

いわさです。

AWS Batchにてスケジュールポリシーを使って、ジョブの重みに応じたリソースの割り当て調整が出来るようになりました。

説明を見るとわかるような、わからないような...
実際に動かして確認してみました。

何が出来るようになったのか

外的な変更として、まずはスケジュールポリシーが実装されました。
スケジュールポリシーでは、主に識別子を設定することで、識別子ごとに重みを設定することが出来るようになります。
例えば、Aさんは長時間のジョブを実行するので100、Bさんは短時間のジョブを実行するので1といった具合です。

そして、作成したスケジュールポリシーはキューに紐付けます。
そうすると、ジョブキューはFIFOではなくてスケジュールポリシーに従った動きを行うようになります。

もちろん従来のようにスケジュールポリシーを紐付けない形でのキュー作成も可能です。

最後に、対象キューがスケジュールポリシーに紐付けられている場合、ジョブ送信時にどの共有識別子は設定するかを指定します。

従来の挙動

Aさんは長時間のジョブを実行する、Bさんは短時間のジョブを実行するという場合でも、従来では先にキューイングされたものから処理されていました。
もしAさんが先にいくつかの長時間ジョブをキューイングしていた場合、それらが終わるまで短時間ジョブをあとからキューイングするBさんは待機しなければなりませんでした。
Bさんのジョブはすぐ終わるのにも関わらずです。

Aさんのジョブを10件送信したのちに、Bさんのジョブを10件送信してみましょう。

for x in {1..10}; do 
    aws batch submit-job --job-definition def1 \
            --job-name job-a-${x} \
            --job-queue iwasa-queue2 \
            --profile hoge
done
for x in {1..10}; do 
    aws batch submit-job --job-definition def1 \
            --job-name job-b-${x} \
            --job-queue iwasa-queue2 \
            --profile hoge
done

送信した順に処理されていますね。

従来でも、複数のキューを用意して、キューごとに優先度を変える方法は出来ていましたが、あくまでもキューによっての優先付けであり、識別子のような形で任意の優先順位付けは出来ませんでした。

ちなみに...

実は非スケジュールポリシー環境でも完全なFIFOではないので注意が必要です。

ジョブの実行順は、他のジョブへの依存関係がすべて満たされている限り、送信順とほぼ同じです。

ほぼ...

私が確認した限りだと、たまに割り込みが発生していました。

スケジュールポリシーの設定ごとの挙動

では今回実装された機能でどのようにコントロール出来るようになるのかを見てみます。
検証に使用したコンピューティングタイプはEC2で、vCPUは最小/最大ともに4です。
そして、一つのジョブあたり1vCPUを使うように設定しています。

タスクはAmazon Linuxコンテナーでsleep 60を実行する単純なものです。

識別子による割り当てと重み

挙動確認した限りだと、タイミングや他の様々な条件に関連して多少前後する場合があるのですがそれらを無視できる状態だと、概ね以下のような動きになります。

A:1, B:1

ジョブAとジョブBを10件づつ送信したあとの処理結果です。(全件SUCCEEDEDとなった後に抽出)

iwasa.takahito@hoge ~ % aws batch list-jobs --job-queue iwasa-queue7 --job-status SUCCEEDED --profile hoge | jq '.jobSummaryList | sort_by(.startedAt)[] | (.startedAt|tostring)+":"+.jobName'
↓最初の4件
"1636592304700:job-a-1"
"1636592304747:job-b-1"
"1636592304772:job-a-3"
"1636592304776:job-b-2"
↓次の4件
"1636592359815:job-a-2"
"1636592359816:job-a-4"
"1636592359875:job-b-3"
"1636592359907:job-b-4"
↓次の4件
"1636592420979:job-a-7"
"1636592421035:job-a-5"
"1636592421059:job-b-6"
"1636592421061:job-b-5"
↓次の4件
"1636592481619:job-b-8"
"1636592481664:job-a-6"
"1636592481721:job-b-7"
"1636592481735:job-a-9"
↓次の4件
"1636592542015:job-b-9"
"1636592542034:job-a-10"
"1636592542040:job-b-10"
"1636592542042:job-a-8"

AタスクとBタスクが2件づつバランスよく処理されています。

A:999, B:1

iwasa.takahito@hoge ~ % aws batch list-jobs --job-queue iwasa-queue10 --job-status SUCCEEDED --profile hoge | jq '.jobSummaryList | sort_by(.startedAt)[] | (.startedAt|tostring)+":"+.jobName'
↓最初の4件
"1636595652050:job-b-2"
"1636595652076:job-b-3"
"1636595652078:job-b-4"
"1636595652082:job-b-1"
↓次の4件
"1636595705806:job-b-7"
"1636595705833:job-a-1"
"1636595705840:job-b-5"
"1636595705878:job-a-2"
↓次の4件
"1636595766827:job-a-3"
"1636595766831:job-b-9"
"1636595766850:job-b-6"
"1636595766877:job-b-8"
↓次の4件
"1636595828058:job-a-4"
"1636595828074:job-b-10"
"1636595828083:job-a-5"
"1636595828088:job-a-6"
↓次の4件
"1636595889086:job-a-8"
"1636595889160:job-a-9"
"1636595889186:job-a-7"
"1636595889233:job-a-10"

Bがかなり優先されて処理されます。
ただし、ずっとBが処理されるわけでもなく、Bが連続実行されたあとにたまにAが割り込まれます。
最終的にはAが多めに残って最後にまとめて処理されていました。

いくつかのパターンを試してわかったのですが、設定された重みだけでなく、どの重みを何回実行したかなどでBの相対的なウェイトが大きくなったタイミングでAも動かすことでバランスを取るような動きをしています。

コンピューティング予約

先程のように重みを設定することが出来ますが、それでもキューが埋まっている場合は処理中のジョブは中断出来ないので、待つ必要があります。
このコンピューティング予約を設定しておくと、コンピューティングリソースを全て使わずに、割り込み用に残しておくことが出来ます。

設定値はパーセントになるので50%として50を設定してみます。
識別子は2つあって、重みは1づつです。

この場合はアクティブでないひとつの識別子の50%を処理出来るように残しておくという設定になるため、vCPUが4の環境だとすると1:1で識別子あたりvCPU2を使うので、vCPU1が割り込み処理用に残されます。

3件づつ処理されており、常にジョブ1件分の余力を残していますね。

まとめ

本日はAWS Batchでのスケジュールポリシーを試してみました。
うまく活用出来ると、重みに応じてコンピューティングリソースを平等に割り当て出来るになるので便利ですね。

ただし、私が触った限りだと設定が少し難しく感じました。
優先度の上書き設定などがあったり、時間による減衰設定などもあります。
おそらく最初は思ったようなジョブ順序にならないと思いますので十分検証のうえご利用頂いたほうが良いでしょう。