Slurmフェデレーションとは?構築手順・ジョブID体系と1日5万ジョブの適用限界

Slurmのフェデレーションは、別々のslurmctldが管理する複数クラスタを1つのジョブID空間で束ね、投入されたジョブの複製を各クラスタへ配って、最初に資源を確保できたクラスタで走らせる機能です。初出は2017年11月にタグ付けされたSlurm 17.11で、現行の26.05でも修正が入り続けています。ただし公式ドキュメントの立場は、高スループット環境向けの機能ではない、というものです。この記事ではsacctmgrでの構築手順、32ビットジョブIDの分割方式と最大63クラスタという上限、そして採用を見送るべき条件までを、Slurm 26.05の一次情報にあたって整理します。

まとめ

  • フェデレーションは、投入されたジョブの複製(siblingジョブ)を参加クラスタへ配り、先に資源を確保できたクラスタで起動させる仕組みです。
  • 構築コマンドはsacctmgrだけで完結します。前提としてslurm.confのAccountingStorageType=accounting_storage/slurmdbdとクラスタ間のMUNGE鍵共有が要りますが、フェデレーション固有のslurm.conf設定に必須項目はありません。
  • ジョブIDは32ビットのうち下位26ビットをローカルID、上位6ビットをクラスタOrigin IDに割り当てて一意性を確保します。参加クラスタ数の上限は63です。
  • 公式は1日5万ジョブを超える規模なら、sibling先のクラスタを減らすかローカル投入へ寄せるよう求めています。ジョブ数を稼ぐための機能ではありません。
  • ジョブ配列はoriginクラスタでしか走らず、ローカルで資源不足と判定されたジョブは他クラスタへ回りません。この2点は26.05時点でも制限として残っています。

以降は構築手順から順に、公式ドキュメントの記述と突き合わせた整理です。

フェデレーションが担う範囲と公式が示す適用外の条件

マルチクラスタ運用におけるフェデレーションの位置づけ

Slurmには、フェデレーションを組まなくても複数クラスタへコマンドを飛ばせるマルチクラスタ機能があります。sbatch -M dawn,duskのようにクラスタを列挙すると、Slurmは最も早く開始できると判断したクラスタへジョブを即時投入します。ここで重要なのは、公式ドキュメントが「その後、リストの別クラスタで先に資源が空いてもジョブを移す努力は行わない」と明言している点です。投入時点の一発判断で決まり、待ち行列に並んでいる間に状況が変わっても追随しません。

フェデレーションはこの弱点を、複製で解きます。投入を受けたクラスタが各クラスタへsiblingジョブを配り、それぞれのクラスタが自分のスケジューリングポリシーで独立にスケジュールを試みる構造です。どこか1つが資源を確保した時点で、残りのsiblingジョブは取り下げられます。結果として、どのクラスタが最初に空くかを投入時点で当てる必要がなくなります。

前提条件はマルチクラスタと共通です。全クラスタがSlurmDBDを共有し(AccountingStorageType=accounting_storage/slurmdbd)、クラスタ間で通信できるMUNGE鍵が配布されている必要があります。sacctmgrはSlurmDBD上のデータベースを操作するコマンドなので、この土台が無ければフェデレーションの作成そのものができません。

1日5万ジョブという適用限界

公式のFederated Scheduling Guideは冒頭で次の注意を置いています。高スループット環境として意図した機能ではなく、1日あたり5万ジョブを超えてスケジュールするなら、siblingジョブの投入先クラスタを減らすか、--cluster-constraint=-Mでローカルクラスタへ負荷を寄せることを検討せよ、という内容です。

この注意の意味は、緩和策の中身に表れています。公式が減らすよう促しているのは「投入先クラスタ数」です。1本のジョブ投入に対してviableなクラスタの数だけsiblingジョブが作られ、起動のたびにoriginクラスタとの調停が走る構造なので、負荷がクラスタ数に応じて増えることがここから読み取れます。「クラスタを足せばスループットが上がる」という直感とは逆向きに働くわけです。したがって、大量の短時間ジョブを流し込むハイスループット計算(HTC)の受け皿としては選ぶべきではありません。

sacctmgrによるフェデレーション構築手順

フェデレーションの作成とクラスタ割り当て

フェデレーションはSlurmDBD上に作成し、そこへクラスタを紐づけます。作成と同時にクラスタを指定することも、後から追加することもできます。

# フェデレーションを作成し、同時にクラスタを登録する
sacctmgr add federation fed_east clusters=cluster1,cluster2

# 既存フェデレーションへクラスタを追加・削除する
sacctmgr modify federation fed_east set clusters+=cluster3
sacctmgr modify federation fed_east set clusters-=cluster2

# クラスタ側から所属を指定する書き方
sacctmgr modify cluster cluster3 set federation=fed_east

# 構成の確認
sacctmgr show federation tree
sacctmgr show cluster withfed

1つのクラスタが同時に所属できるフェデレーションは1つだけです。別のフェデレーションへ移すときは、set federation=と値を空にして所属を外すか、移動先を指定して上書きします。フェデレーション自体の削除はsacctmgr delete federation fed_eastです。

クラスタを登録して各クラスタのslurmctldを起動すると、コントローラ側からも状態を確認できるようになります。

scontrol show federation

出力にはフェデレーション名と参加クラスタが並び、各クラスタのコントロールホストとポートを確認できます。26.05では、このホスト表示がIPv6リテラルの場合に角括弧で囲まれるよう修正が入りました。アドレスとポートの区切りが曖昧だった問題への対応です。

fedstateによる投入制御の4状態

クラスタをフェデレーションに残したまま、ジョブの受け入れ方だけを変えられます。設定はsacctmgr modify cluster <name> set fedstate=<state>で、取れる状態は次の4つです。

fedstate 新規ジョブ スケジューリング フェデレーション所属
ACTIVE 受け入れる 行う 維持
INACTIVE 受け入れない 行わない 維持
DRAIN 受け入れない 既存ジョブは完了まで継続 維持
DRAIN+REMOVE 受け入れない 既存ジョブは完了まで継続 完了後に離脱

計画メンテナンスで使うのはDRAINです。走っているフェデレーションジョブを最後まで面倒みたうえで、新規投入だけを止められます。DRAIN+REMOVEはさらに一歩進み、既存ジョブが終わり次第そのクラスタをフェデレーションから外します。外れた後は非フェデレーションのクラスタとして通常どおりジョブを受け付けるので、クラスタを恒久的に切り離す運用の終端はこれです。なお公式がINACTIVEについて書いているのは「新規ジョブを受け付けずスケジュールもしない」までで、その時点で実行中のジョブをどう扱うかは明記されていません。既存ジョブの完走を保証したいならDRAINを選ぶのが安全です。

クラスタフィーチャーによる投入先の絞り込み

クラスタには任意のフィーチャー文字列を付けられます。GPU搭載機だけを集めたクラスタ、大容量メモリのクラスタといった区別を、ジョブ側から指定できるようにするための仕組みです。

# クラスタにフィーチャーを付与・除去する
sacctmgr modify cluster cluster1 set features+=gpu,highmem
sacctmgr modify cluster cluster2 set features-=highmem

# 投入側でフィーチャーを要求する
sbatch --cluster-constraint=gpu script.sh

# 否定形はシェルの履歴展開を避けるため引用符で囲む
sbatch --cluster-constraint='!highmem' script.sh

否定形の!は引用符で囲むよう公式が明記しています。囲まないと、対話シェルのbashやzshが履歴展開として解釈し、意図しない文字列がSlurmへ渡ります。スクリプト内から呼ぶ場合は履歴展開が無効なので実害はありませんが、書き方は統一しておくのが無難です。

クラスタ除外時に走る挙動

ドレインせずにクラスタをフェデレーションから外すと、そのクラスタに関係するジョブは状態ごとに違う扱いを受けます。ここは事故になりやすい箇所なので、外す前に把握しておく必要があります。

  • 外したクラスタで実行中のジョブ、およびそのクラスタ発のジョブは、非フェデレーションジョブとしてそのまま走り続ける。
  • originクラスタで保留中だったジョブは、originに非フェデレーションジョブとして留まり、残りのsiblingジョブは削除される。
  • 外すのがoriginクラスタで、保留ジョブが実行可能なクラスタを1つしか持たない場合、そのクラスタに非フェデレーションジョブとして残る。
  • 外すのがoriginクラスタで、保留ジョブが複数クラスタで実行可能な場合は、フェデレーションジョブのまま残り、残ったsibling同士で起動を調停する。

要するに、無停止で外したいならDRAIN+REMOVEを使い、それ以外の除外は「非フェデレーションジョブへの降格が混ざる」前提で計画する、という切り分けです。

フェデレーションジョブIDのビット割り当てと63クラスタの上限

32ビットジョブIDの分割方式

フェデレーションでは、どのクラスタで採番されたジョブIDも全体で一意でなければなりません。Slurmはこれを、32ビット符号なし整数を2つの領域に割ることで実現しています。ローカル採番の連番とクラスタの識別子を1つの整数に詰め込む設計です。

項目 出典
ローカルジョブID bits 0-25 federation.html
クラスタOrigin ID bits 26-31 federation.html
ローカルジョブIDの最大値 67,108,863 (0x3FFFFFF) slurm.conf MaxJobId
MaxJobIdの既定値 67,043,328 (0x03ff0000) slurm.conf MaxJobId
フェデレーションジョブIDの下限 67,108,865 slurm.conf MaxJobId
参加クラスタ数の上限 63 slurm.h MAX_FED_CLUSTERS

上位6ビットがOrigin IDに使われるため、コントローラはジョブIDを見るだけで、そのジョブがどのクラスタへ投入されたものかを判定できます。ローカルの連番のほうは26ビットに制限され、上限は67,108,863です。MaxJobIdの既定値67,043,328はこの上限より少し低く設定されており、到達すると次のジョブはFirstJobId(既定1)へ戻ります。

運用上おさえておきたいのは、フェデレーションジョブのIDが必ず67,108,865以上になる点です。上位6ビットのOrigin IDが1以上になることの帰結です。判別に使うのは桁数ではなくこの閾値だと覚えてください。ローカルジョブIDも既定のMaxJobIdまで伸びれば8桁に到達するので、桁数では区別が付きません。ジョブIDを固定長で切り出しているスクリプトや、外部の課金・レポート基盤にIDを渡している運用では、フェデレーション化のタイミングで見直しが要ります。

63クラスタという構造的上限

クラスタ数の上限が書かれているのは、ドキュメントではなくソース側の定数です。Slurm 26.05.2のslurm/slurm.h#define MAX_FED_CLUSTERS 63があり、6ビットのOrigin IDから非フェデレーションを示す0を除いた値と一致します。数十クラスタ規模を1フェデレーションで束ねる計画があるなら、この天井を先に見ておくべきです。もっとも、公式が1日5万ジョブ超では投入先クラスタを減らすよう求めている以上、上限に近い構成は現実的な選択肢になりません。

ジョブ投入からsiblingジョブ起動までの調停

originクラスタが持つ起動ロックの役割

ジョブが投入されたクラスタがoriginクラスタになり、そこから各viableクラスタへsiblingジョブが複製されます。以降、各クラスタは自分のスケジューラで独立にこのジョブを検討しますが、実際に資源を割り当てる直前だけはoriginに問い合わせます。他のクラスタが同時に割り当てを試みていないかを確認するためです。

確認が通ったクラスタが資源確保に成功すると、originへ起動を通知し、originが残りのクラスタへsiblingジョブの取り下げを指示します。取り下げられたジョブはRevoked(RV)状態になります。sacctの既定表示ではRevokedジョブが出てこないため、同じジョブが二重に並ぶことはありません。

割り当てに失敗した場合もoriginへ通知が返り、他のクラスタが試行できるようになります。このとき、失敗したのがメインスケジューラなら、そのパーティションではそれ以上先のジョブを見ません。バックフィルスケジューラだった場合は、そのジョブのために資源が予約されます。

originクラスタが落ちている間は、残ったsibling同士で調停してジョブを起動します。originが復帰すると他のsiblingと同期を取る流れです。origin単一障害点で全ジョブが止まる設計ではありません。

投入先を絞る2つの提出オプション

siblingジョブを配る先は、投入時に2つのオプションで制御できます。

# cluster2 と cluster3 のどちらかへ投入し、siblingもこの2つに限定する
sbatch -M cluster2,cluster3 script.sh

# クラスタ指定とフィーチャー指定を併用すると、双方を満たすクラスタだけが対象になる
sbatch -M cluster2,cluster3 --cluster-constraint=gpu script.sh

-Mを指定すると、Slurmはリストの中から投入先を1つ選び、同時にそのリストをジョブに引き継ぎます。フェデレーションに他のクラスタがあっても、siblingジョブはリスト内のクラスタにしか作られません。前節で触れた1日5万ジョブへの対処として公式が挙げているのが、まさにこの絞り込みです。

なお、投入先の判定ロジックはSlurm 25.05で変更されました。フェデレーション単位で1クラスタだけを試す方式から、指定された各クラスタを個別に試す方式になっています。最終的に1クラスタへ投入する点は26.05でも変わりません。

保留ジョブとorigin停止時の挙動

すべてのジョブが即座に複製されるわけではありません。ホールドされたジョブと依存関係の解決待ちジョブは、解放されるまで、あるいは依存が解消されるまでoriginクラスタに留まります。解消された時点で他のviableクラスタへsiblingが配られます。

投入後にホールドや依存が付いた場合は逆向きに動き、origin以外のクラスタからそのジョブが取り除かれる仕様です。「投入時に複製、条件付きで回収」ではなく「実行可能になった時点で複製」と理解しておくと、squeue --federationで保留ジョブが1クラスタにしか見えない理由を説明できます。

フェデレーション横断のステータス確認とslurm.conf設定

fed_displayによる既定ビューの切り替え

squeuesinfoなどのステータス系コマンドは、既定ではローカルクラスタの情報しか表示しません。フェデレーション全体を1つのビューにまとめるには--federationを付けます。このオプションが指定されると、コマンドはまずローカルクラスタがフェデレーションに属しているかを確認し、属していれば各クラスタへ並列に問い合わせて結果を統合する動きです。

毎回付けるのが煩雑なら、slurm.confで既定を反転できます。

# /etc/slurm/slurm.conf
FederationParameters=fed_display

これで全ステータスコマンドがフェデレーションビューを既定にします。個別にローカル表示へ戻したいときは--local、特定クラスタだけ見たいときは-Mを使ってください。-Mを付けた場合の出力は、クラスタごとに情報を分けて並べる従来形式です。

26.05のslurm.confマニュアルでFederationParametersに名前付きで記載されている値はfed_displayだけです。マニュアルにはもう1つ、オプション名の欠落した記述(slurmdbd停止中も--clusterを使えるようにする、という内容)が続いていますが、26.05のソースが参照しているのはfed_displayのみでした。しかもFederationParametersは検証なしの文字列として読まれ、消費側はfed_displayが含まれるかの部分一致テストしか行いません。つまり他の値を書いても起動が止まることはなく、黙って無視されます。設定が効いたと誤認しやすいので、値を足すときは実際の表示で確認してください。

squeue・sinfo・sprio・sacctで増える表示項目

フェデレーションビューでは、どのクラスタの情報なのかを出力に含める必要があるため、各コマンドに専用のフォーマット項目が追加されています。

コマンド 追加項目・オプション 用途
squeue --sibling siblingを統合せず個別表示
squeue clustersiblingsactivesiblingsviable 実行クラスタとsibling配置
squeue -S cluster クラスタ名でソート
sinfo %Vcluster パーティションのクラスタ名
sprio %c--sibling クラスタ別の優先度
sacct -D--duplicate Revokedジョブの表示

実務で使う頻度が高いのはsqueue --siblingsprio --siblingです。フェデレーションビューの既定では同一ジョブのsiblingが1行にまとまりますが、優先度はクラスタごとに異なる計算結果になるため、なぜそのクラスタで動かないのかを追うには個別表示が要ります。siblingsviableで実行可能なクラスタを確認し、siblingsactiveで実際にsiblingが存在するクラスタと突き合わせると、フィーチャー指定やfedstateで除外されているクラスタを特定できます。

originへルーティングされるscontrol操作

scontrolはサブコマンドによって扱いが別です。フェデレーションビューで表示できるのはshow jobs--federationまたは--sibling付き)、show stepscompletingの3つです。

状態を変える操作のうち、holduholdreleaserequeuerequeueholdsuspendupdate jobはフェデレーション内で処理されます。origin以外のクラスタで実行しても、コマンドがoriginへ転送される仕組みです。これら以外のサブコマンドは転送されないため、対象クラスタで直接実行するか-Mでクラスタを指定してください。

再キューイング・キャンセル・対話ジョブの制約

再キューイングとキャンセルの経路

フェデレーションジョブが再キューイングされると、まずoriginクラスタへ通知が入り、originが改めてviableクラスタへsiblingジョブを投入し直します。このため、再キューイング後のジョブは前回とは別のクラスタで起動する可能性があります。特定ノードの障害で落ちたジョブが、次は別クラスタで走るという動きです。slurm.confのRequeueExitRequeueExitHoldはoriginクラスタの設定が使われるので、クラスタごとに値が違う環境では意図した終了コードで再投入されないことがあります。

キャンセルの対象は、実行中のsiblingジョブ、または保留中の全siblingジョブです。特定クラスタのsiblingだけを候補から外したいときはscancel --sibling=<cluster_name>を使い、そのクラスタをアクティブなsiblingリストから取り除きます。ジョブそのものを消さずに投入先を狭める操作です。ジョブ内容の変更はoriginクラスタへルーティングされ、originで成功したときだけ各siblingへ反映されます。

対話ジョブとMPIで必要になる前提条件

srunsallocによる対話ジョブも、ローカルクラスタに投入して別クラスタから資源を得ることが可能です。ローカル以外のクラスタが割り当てを行った場合、環境変数SLURM_WORKING_CLUSTERにsiblingクラスタのIPアドレス、ポート、RPCバージョンが設定され、後続のsrunがどのクラスタと通信すべきかを判断できるようになります。

この動作の前提は2つです。1つは、すべての計算ノードがすべての投入ホストからアクセス可能であること。もう1つはMPIジョブに関するもので、srunを実行するホストと割り当てられた計算ノードでSlurmdSpoolDirが同じパスである必要があります。異なる場合の回避策として公式が挙げているのは、slurm.confにLaunchParameters=use_interactive_stepを設定し、salloc時にユーザーを実際の計算ノード上へ配置する方法です。計算ノード上のslurm.confが使われるため、パスの不一致が問題になりません。

公式が挙げる5つの制限事項

Federated Scheduling GuideのLimitationsには、26.05時点でも次の5項目が残っています。

  • ローカルクラスタの資源条件(パーティション、ノード数など)で失敗したジョブは拒否され、他クラスタで実行可能でもsiblingが作られない。
  • ジョブ配列は投入されたクラスタでのみ実行される。
  • ジョブの変更はoriginクラスタで成功しなければ、リモートのsiblingへ反映されない。
  • sviewではジョブ以外への変更が無効化される。
  • sviewのグリッド表示はフェデレーションビューでは無効。

1点目は特に注意が要ります。「クラスタAでは資源が足りないがクラスタBなら通る」というジョブを自動で振り分けてくれる機能ではありません。パーティション定義やノード構成がクラスタ間で大きく異なる場合、投入されたクラスタの制約でそのまま弾かれます。フェデレーションを組むなら、パーティション名とノード仕様をある程度そろえておくのが現実的な運用条件です。

導入を見送るべき条件と17.11環境からの移行コスト

フェデレーションを採用すべきでない条件

ここまでの制限を踏まえると、フェデレーションを選ばないほうがよい状況は具体的に絞れます。実務でまず効くのは1つ目です。

第一に、1日のジョブ数が5万を超える環境。公式の緩和策が「siblingを配る先を減らす」=機能を実質無効化する方向である以上、クラスタごとにキューを分けて投入側で振り分けるほうが素直です。この条件に当たるかどうかで、検討そのものの可否が決まります。

第二に、ワークロードの中心がジョブ配列である環境。配列ジョブはoriginでしか走らないため、組んでも負荷は平準化されず、運用の複雑さだけが増えます。第三に、クラスタ間でパーティション構成やノード仕様が大きく異なる環境。期待した振り分けが起きないので、投入側のラッパーで条件に応じてクラスタを選ぶ設計のほうが確実です。第四に、クラスタ間でMUNGE鍵の共有やネットワーク到達性を確保できない環境。前提条件を満たせないため、そもそも構築できません。

逆に向いているのは、似た構成のクラスタが2つから数個あり、時間帯や部署によって混雑が偏り、ジョブが比較的長時間で本数はそれほど多くない環境です。この条件に当てはまらないなら、コンテナ基盤側のスケジューラを検討する選択肢もあります。HashiCorp Nomadはマルチリージョンのフェデレーションを標準機能として持ち、バッチとサービスを同じスケジューラで扱えます。クラウド側に寄せるなら、キュー管理そのものを引き受けるAWS Batchのようなマネージドのジョブキューが候補です。

26.05へ直接上げられる版の範囲

Slurm 17.11を前提とした日本語情報は、今も多く残っています。17.11は2017年11月にタグ付けされた版、つまりフェデレーションの初出版です。ただし、当時の手順をそのまま現行環境へ持ち込むのは現実的ではありません。

26.05のリリースノートは、直接アップグレードできる元の版を25.11、25.05、24.11の3つに限定しています。17.11から26.05へ上げるには、この対応表に沿って中間の版を何度も経由する必要があり、slurmdbdのデータベース変換もその都度発生します。バージョン差を「設定ファイルの微修正で済む」と見積もるのは危険です。

一方で、フェデレーション機能自体には現行版でも手が入り続けています。25.11ではフェデレーションジョブにSLUIDが設定されない不具合や、siblingジョブ投入時のメモリ破壊が修正されました。放置された機能ではないため、17.11時代の既知の問題を前提に判断するのも同じくらい危険です。導入判断は、必ず自分が動かす版のドキュメントとCHANGELOGにあたってください。

よくある質問

フェデレーションの検討時に判断が分かれやすい論点を5つまとめました。

フェデレーションとマルチクラスタ(-M)は何が違いますか?

ジョブを配る範囲と、配った後の追随性が違います。非フェデレーションの-Mは、指定したクラスタの中で最も早く開始できると判断された1つへ即時投入し、その後に別クラスタが空いてもジョブを移しません。フェデレーションは全viableクラスタへsiblingジョブを複製し、最初に資源を確保できたクラスタで起動させます。待ち行列に並んでいる間の状況変化に追随したいかどうかが、選択の分かれ目です。

動かしているSlurmの版はどうやって確認しますか?

クライアントコマンドに-Vまたは--versionを付けます。scontrol --versionsinfo -Vsqueue --versionのいずれでもバージョン情報が出力されます。フェデレーションを組む前に、全クラスタでこの出力をそろえておくのが前提です。26.05のリリースノートが直接アップグレード元を25.11、25.05、24.11に限定している以上、クラスタ間の版差が大きいと移行計画そのものが分岐します。

フェデレーションのトラブルはどのログで追えますか?

slurm.confにDebugFlags=Federationを設定すると、フェデレーションのスケジューリングに関する詳細がslurmctldのログへ出力されます。出力先は同じくslurm.confのSlurmctldLogFileで指定したパスです。あわせてsqueue --siblingでsiblingジョブが実際にどのクラスタへ配られているか、siblingsviableで実行可能と判定されているクラスタはどれかを確認すると、フィーチャー指定やfedstateで除外されているクラスタを切り分けられます。Revoked状態のジョブはsacct -Dで表示できます。

ジョブIDが67,108,865以上になるのはなぜですか?

フェデレーションジョブでは上位6ビットのクラスタOrigin IDが必ず1以上になるためです。下位26ビットのローカルジョブIDは最大67,108,863(0x3FFFFFF)で、その上にOrigin IDが乗ります。MaxJobIdの既定値67,043,328はローカルジョブIDにのみ適用され、フェデレーションジョブIDには適用されません。

Slurm 17.11時代の設定手順はそのまま使えますか?

sacctmgrによるフェデレーション作成やfedstateの考え方といった基本構造は、26.05でも変わっていません。ただし版そのものを17.11のまま運用するのは別問題で、26.05への移行には中間の版を何度も経由する必要があります。挙動の差分もあります。25.05では複数クラスタ指定時に各クラスタを個別評価するよう変わりました。細かい違いは自分が使う版のCHANGELOGで確認してください。

関連記事

資料請求

RELATED POSTS 関連記事