分散型 AI トレーニングおよびビッグデータワークロードでは、Pod 間の通信が頻繁に行われます。Kubernetes のデフォルトスケジューラは Pod をノード間で均等に分散配置するため、複数のスイッチホップを挟んだ異なるノードに Pod が配置される可能性があります。ホップ数が増えるほどレイテンシが増加し、スループットが低下します。ネットワークトポロジー対応スケジューリングは、ジョブ内のすべての Pod を同一のレイヤー 1 またはレイヤー 2 転送ドメイン内のノードに割り当てることで、スイッチホップを最小限に抑え、ジョブ完了を高速化します。
仕組み
ネットワークトポロジー対応スケジューリングは、貪欲アルゴリズムを使用して、トポロジースパンが最小となる Lingjun ノードにジョブを割り当てます。
ACK Lingjun クラスターには、2 階層のネットワークトポロジー構造があります。
アクセススイッチ (ASW):Lingjun ノードへの直接インターフェイスです。同一 ASW 配下のノード間の通信には、少なくとも 1 ホップ必要です。
Point of Delivery (PoD):複数の ASW をまとめる上位トポロジー階層です。同一 PoD 内で異なる ASW 配下にあるノード間の通信には、少なくとも 2 ホップ必要です。
ノード間のスイッチ階層が少ないほど、レイテンシは低くなります。スケジューラは、可能な限り低いトポロジーレベル内にすべての Pod を収めるよう試みます。
2 ノードジョブ:同一 ASW 内のノードに割り当てられます(例:ノードペア A-B または E-F)。
4 ノードジョブ:同一 PoD 内のノードに割り当てられます(例:ノードペア A-D または E-H)。
ノードラベルにより、各ノードがどの ASW および PoD に属しているかを識別できます。
alibabacloud.com/asw-id:ASW を識別します。alibabacloud.com/point-of-delivery:PoD を識別します。
ACK Lingjun クラスターでは、lingjun-networktopology-collector コンポーネントが自動的にこの情報を収集し、Lingjun ノードにこれらのラベルを適用します。その他のノードタイプまたはクラスタータイプでは、手動でラベルを追加し、ラベルキーが labelKey 値と ClusterNetworkTopology 構成で一致していることを確認してください。
スケジューリング戦略
次の 2 つの戦略により、トポロジーレベル内で Pod をどの程度厳密にグループ化するかを制御します。
| 戦略 | 動作 |
|---|---|
PreferGather | 可能な場合はレイヤー内で Pod をグループ化しますが、リソースが不足している場合はクロスレイヤースケジューリングを許可します。 |
MustGather | すべての Pod を同一レイヤー内に配置することを必須とし、単一レイヤーでジョブを収容できない場合はスケジューリングが失敗します。 |
前提条件
作業を開始する前に、以下の要件を満たしていることを確認してください。
ACK Lingjun クラスター
クラスターへの接続用に kubectl が設定済みであること
トポロジーラベルが適用された十分なノードがあること
ネットワークトポロジー対応スケジューリングの構成とデプロイ
ネットワークトポロジー対応スケジューリングを構成するには、次の 3 つの YAML ファイルが必要です。クラスター全体のトポロジー構造を定義するファイル、特定のジョブに対するスケジューリング制約を宣言するファイル、およびジョブ自体の定義ファイルです。
ステップ 1:クラスタートポロジーの定義
クラスターの 2 階層トポロジー構造を宣言するための cluster-network-topology.yaml を作成します。
apiVersion: scheduling.koordinator.sh/v1alpha1
kind: ClusterNetworkTopology
metadata:
# 変更しないでください。
name: default
spec:
networkTopologySpec:
# parentTopologyLayer は上位トポロジー構造を宣言します。
- parentTopologyLayer: ASWTopologyLayer
# Lingjun ノードの最下位レベルは必ず NodeTopologyLayer にしてください。
topologyLayer: NodeTopologyLayer
# 以下はクロスレイヤートポロジーマッピングを定義します。通常、変更は不要です。
- labelKey:
- alibabacloud.com/point-of-delivery
topologyLayer: PoDTopologyLayer
- labelKey:
- alibabacloud.com/asw-id
parentTopologyLayer: PoDTopologyLayer
topologyLayer: ASWTopologyLayerステップ 2:ジョブのトポロジー制約の宣言
各トポロジーレベルにおけるスケジューリング戦略を指定するための sample-network-topology.yaml を作成します。
apiVersion: scheduling.koordinator.sh/v1alpha1
kind: JobNetworkTopology
metadata:
labels:
network-topology-permit-wait-time: "999999"
# ジョブ名。
name: sample-network-topology
# ジョブが属する名前空間。
namespace: sample-network-topology
spec:
topologyStrategy:
# PreferGather:リソースが不足している場合、ASW をまたいだスケジューリングを許可します。
- layer: ASWTopologyLayer
strategy: PreferGather
- layer: NodeTopologyLayer
strategy: PreferGather
# MustGather:PoD をまたいだスケジューリングは許可されません。
- layer: PoDTopologyLayer
strategy: MustGather
# Job マニフェストの spec.parallelism および pod-group.scheduling.sigs.k8s.io/min-available と一致させる必要があります。
workerNum: 2ステップ 3:ジョブの作成
ジョブを定義し、トポロジー制約を参照するための pi.yaml を作成します。
apiVersion: batch/v1
kind: Job
metadata:
name: pi
spec:
# JobNetworkTopology の workerNum と一致させる必要があります。
parallelism: 2
template:
metadata:
labels:
# JobNetworkTopology の workerNum と一致させる必要があります。
pod-group.scheduling.sigs.k8s.io/min-available: "2"
pod-group.scheduling.sigs.k8s.io/name: sample-gang
# ステップ 2 で作成した JobNetworkTopology を参照します。
network-topology-job-name: sample-network-topology
network-topology-job-namespace: sample-network-topology
spec:
schedulerName: default-scheduler
containers:
- name: pi
image: perl:5.34.0
command: ["perl", "-Mbignum=bpi", "-wle", "print bpi(2000)"]
resources:
limits:
# この例では GPU を 1 枚使用します。必要に応じて調整してください。
nvidia.com/gpu: 1
restartPolicy: Never
backoffLimit: 4ステップ 4:構成のデプロイ
次のコマンドで、3 つのファイルをクラスターに適用します。
kubectl apply -f cluster-network-topology.yaml
kubectl apply -f sample-network-topology.yaml
kubectl apply -f pi.yamlスケジューリング結果の確認
クラスタートポロジーの確認
トポロジー構造を確認するため、ノードのトポロジーラベルを取得します。
# ネットワークトポロジー:
# test-pod-1 test-pod-2
# / | \ |
# test-1 test-2 test-3 test-4
# / \ | | |
# 0.12 0.14 0.15 0.16 0.17
kubectl get no -l alibabacloud.com/asw-id,alibabacloud.com/point-of-delivery -ojson | jq '.items[] | {"Name":.metadata.name, "ASW":.metadata.labels."alibabacloud.com/asw-id", "POD":.metadata.labels."alibabacloud.com/point-of-delivery"}'期待される出力:
{
"Name": "cn-hongkong.10.1.0.12",
"ASW": "test-1",
"POD": "test-pod-1"
}
{
"Name": "cn-hongkong.10.1.0.14",
"ASW": "test-1",
"POD": "test-pod-1"
}
{
"Name": "cn-hongkong.10.1.0.15",
"ASW": "test-2",
"POD": "test-pod-1"
}
{
"Name": "cn-hongkong.10.1.0.16",
"ASW": "test-3",
"POD": "test-pod-1"
}
{
"Name": "cn-hongkong.10.1.0.17",
"ASW": "test-4",
"POD": "test-pod-2"
}シナリオ 1:2 Pod ジョブ
workerNum: 2 の設定により、両方の Pod が同一 ASW(test-1)内のノードにスケジュールされます。
kubectl get pod -owideNAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
pi-8p89l 1/1 Running 0 4s 172.30.240.197 cn-hongkong.10.1.0.14 <none> <none>
pi-p8swv 0/1 ContainerCreating 0 4s <none> cn-hongkong.10.1.0.12 <none> <none>両方の Pod は test-1(ASW)に配置され、最低ホップ数のネットワークパスを共有します。
シナリオ 2:4 Pod ジョブ
pi.yaml の parallelism および pod-group.scheduling.sigs.k8s.io/min-available、ならびに sample-network-topology.yaml の workerNum を 4 に更新し、両ファイルを再適用します。
PoDTopologyLayer に設定された MustGather により、PoD をまたいだスケジューリングが禁止されるため、スケジューラはすべての 4 つの Pod を test-pod-1 内に割り当てます。test-pod-2 配下のノードはスケジュールされません。
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
pi-2kwq9 1/1 Running 0 4s 172.30.241.123 cn-hongkong.10.1.0.12 <none> <none>
pi-87hm5 0/1 ContainerCreating 0 4s <none> cn-hongkong.10.1.0.16 <none> <none>
pi-bsvx8 1/1 Running 0 4s 172.30.240.198 cn-hongkong.10.1.0.14 <none> <none>
pi-dvwhl 0/1 ContainerCreating 0 4s <none> cn-hongkong.10.1.0.15 <none> <none>シナリオ 3:5 Pod ジョブ(スケジューリング失敗)
同様のパラメーターを 5 に更新します。ジョブは失敗します。理由は、test-pod-1 には空きスロットが 4 つしかなく、PoDTopologyLayer の MustGather により、test-pod-2 の単一ノードを使用することが禁止されているためです。
すべての Pod は Pending 状態のままになります。
NAME READY STATUS RESTARTS AGE
pi-75qf5 0/1 Pending 0 2s
pi-8k4nd 0/1 Pending 0 2s
pi-b2pmc 0/1 Pending 0 2s
pi-n7c2b 0/1 Pending 0 2s
pi-wf4zn 0/1 Pending 0 2sスケジューリング失敗メッセージを確認します。
kubectl get pod -ojson | jq '.items[].status'スケジューリング失敗メッセージには次のような内容が含まれます。
0/6 nodes are available: 1 Insufficient nvidia.com/gpu, 1 [NetworkTopology begin] cluster total nodes:6, 5 node provide 5 freeSlot, 1 node unavailable cause Insufficient nvidia.com/gpu, job desireNum:5, all fail topology paths by MustGather reason: [path:RootNode->test-pod-1, freeSlotNum:4], [path:RootNode->DefaultTopologyName, freeSlotNum:0], [path:RootNode->test-pod-2, freeSlotNum:1] [NetworkTopology end], 4 NetworkTopology bestPlan empty. network topology job sample-network-topology/sample-network-topology gets rejected due to pod is unschedulable...メッセージ内の主なフィールド:
| フィールド | 値 | 意味 |
|---|---|---|
job desireNum | 5 | スケジューラは、単一の PoD レベルドメイン内に 5 つのスロットを必要としています。 |
path:RootNode->test-pod-1, freeSlotNum | 4 | test-pod-1 には空きスロットが 4 つしかなく、5 つの Pod を収容できません。 |
path:RootNode->test-pod-2, freeSlotNum | 1 | test-pod-2 には 1 つのスロットがありますが、MustGather により、ジョブを複数の PoD に分割することが禁止されています。 |
NetworkTopology bestPlan empty | — | 有効なトポロジープランが存在せず、スケジューリングがブロックされています。 |
この問題を解決するには、workerNum を単一の PoD に収まるように減らすか、PoDTopologyLayer の戦略を MustGather から PreferGather に変更して、PoD をまたいだスケジューリングを許可してください。