すべてのプロダクト
Search
ドキュメントセンター

Container Service for Kubernetes:NUMAトポロジ対応スケジューリングの有効化

最終更新日:Oct 28, 2024

CPUとGPUが頻繁に相互に通信するシナリオでは、非均一メモリアクセス (NUMA) ノード間のメモリアクセスは、レイテンシの増加や帯域幅の制限などの問題を引き起こす可能性があります。 これらの問題は、アプリケーションの全体的なパフォーマンスに影響します。 このような問題を解決するために、Container Service for Kubernetes (ACK) は、Kubernetesのスケジューリングフレームワークに基づくNUMAトポロジ対応スケジューリングをサポートし、最適なNUMAノードにポッドをスケジュールします。 これにより、NUMAノード間のメモリアクセスが削減され、アプリケーションのパフォーマンスが最適化されます。

仕組み

NUMAノードは、NUMAシステムの基本ユニットである。 単一のクラスタノード上の複数のNUMAノードがNUMAセットを構成し、これを使用してコンピューティングリソースを効率的に割り当て、プロセッサ間のメモリアクセスの競合を軽減します。 たとえば、8つのGPUを持つ高性能サーバーには、通常、複数のNUMAノードが含まれます。 CPUコアがアプリケーションにバインドされていない場合、またはCPUとGPUが同じNUMAノードに割り当てられていない場合、CPU競合またはCPUとGPU間のNUMAノード間通信により、アプリケーションのパフォーマンスが低下する可能性があります。 アプリケーションのパフォーマンスを最大化するために、CPUとGPUを同じNUMAノードに割り当てることができます。

kubelet CPUポリシーとNUMAトポロジポリシーに基づくネイティブソリューションは、単一のサーバー上の同じNUMAノードにCPUとGPUを割り当てるのに役立ちます。 ただし、このソリューションでは、クラスターで次の問題が発生する可能性があります。

  • スケジューラは、NUMAノードに割り当てられた特定のCPUおよびGPUを認識しない。 この場合、スケジューラは、残りのCPUおよびGPUリソースがポッドのサービス品質 (QoS) 要件を満たすことができるかどうかを判断できません。 その結果、スケジューリング後に多数のポッドがAdmissionError状態になります。 深刻なケースでは、クラスターが機能しなくなることがあります。

  • CPUとGPUの割り当ては、上位層では制御できません。 ネイティブKubernetesでは、kubeletトポロジポリシーはノードのプロセス起動パラメーターでのみ表示できますが、ノードラベルなどのメソッドを使用してクラスターレベルで取得することはできません。 したがって、ジョブを送信するときに、CPUとGPUの両方が割り当てられているNUMAノードでワークロードを実行するように指定することはできません。 その結果、アプリケーションのパフォーマンスは非常に変動します。

  • トポロジーポリシーは使いやすいものではありません。 NUMAトポロジポリシーはノードで宣言されるため、1つのノードで1つのNUMAトポロジポリシーしか実行できません。 ジョブを送信してトポロジポリシーを使用する前に、クラスターリソース管理者は、特別なラベルをノードに追加してクラスターのノードを手動で分割し、一致するラベルを持つノードにポッドをスケジュールするようにnodeAffinity設定を構成する必要があります。 さらに、異なるポリシーを持つポッドは、互いに干渉しない場合でも、同じノードにスケジュールすることはできません。 これにより、クラスターのリソース使用率が低下します。

ネイティブkubeletソリューションの前述の問題を解決するために、ACKはKubernetesのスケジューリングフレームワークに基づくNUMAトポロジ対応スケジューリングをサポートしています。 ACKは、gputopo-device-pluginコンポーネントとack-koordinatorコンポーネントのack-koordletを使用して、ノード上のCPUとGPUのトポロジを報告します。 どちらのコンポーネントもAlibaba Cloudによって開発されています。 ACKは、ワークロードでNUMAトポロジポリシーを宣言する機能もサポートしています。 次の図は、NUMAトポロジ対応スケジューリングのアーキテクチャを示しています。

image

前提条件

クラスター

  • Kubernetes 1.24以降を実行するACK Proクラスターが作成されます。 詳細については、「ACK管理クラスターの作成」をご参照ください。 ACKクラスターを更新する方法の詳細については、「Upgrade clusters」をご参照ください。

ノード数

  • ack.node.gpu.schedule=topologyラベルは、NUMAトポロジ対応スケジューリングを有効にするノードに追加されます。 詳細については、「Labels for enabling GPU scheduling policies」をご参照ください。

コンポーネント

  • kube-schedulerコンポーネントのバージョンがV6.4.4以降です。 詳細については、「kube-scheduler」をご参照ください。 kube-schedulerコンポーネントを更新するには、次の操作を実行します。ACKコンソールにログインします。 [クラスター] ページで、管理するクラスターの名前をクリックします。 左側のナビゲーションウィンドウで、[操作] > [アドオン] を選択します。 コンポーネントを見つけて更新します。

  • ack-koordinatorコンポーネントがインストールされています。 このコンポーネントは、以前はack-slo-managerと呼ばれていました。 詳細については、「ack-koordinator (FKA ack-slo-manager) 」をご参照ください。

    • ACK Lingjun cluster: ack-koordinatorコンポーネントをインストールします。

    • ACK Proクラスター: ack-koordinatorコンポーネントのパラメーターを設定する場合、agentFeaturesパラメーターにNodeTopologyReport=trueと入力します。

      image

  • トポロジ対応のGPUスケジューリングコンポーネントがインストールされています。 詳細については、「トポロジ対応GPUスケジューリングコンポーネントのインストール」をご参照ください。

    重要

    ack-koordinatorコンポーネントをインストールする前にトポロジ対応GPUスケジューリングコンポーネントをインストールする場合は、ack-koordinatorコンポーネントのインストール後にトポロジ対応GPUスケジューリングコンポーネントを再起動する必要があります。

制限事項

  • NUMAトポロジ対応スケジューリングとTopology-aware CPU schedulingまたはトポロジ対応GPUスケジューリングを併用することはできません。

  • NUMAトポロジ認識スケジューリングは、CPUとGPUの両方がNUMAノードに割り当てられているシナリオにのみ適用されます。

  • ポッド内のすべてのコンテナーの要求されたCPUコアの数は整数で、CPUコアの数の制限と同じである必要があります。

  • ポッド内のすべてのコンテナーのGPUリソースは、aliyun.com/gpuを使用して要求する必要があります。 要求されるGPUの数は整数でなければなりません。

課金

この機能を使用するには、クラウドネイティブのAIスイートをインストールする必要があります。 詳細については、「Billing of the cloud-native AI suite」をご参照ください。

ack-koordinatorコンポーネントをインストールして使用する場合、料金はかかりません。 ただし、次のシナリオでは料金が請求される場合があります。

  • ack-koordinatorは、インストール後にワーカーノードリソースを占有する管理対象外のコンポーネントです。 コンポーネントのインストール時に、各モジュールが要求するリソースの量を指定できます。

  • 既定では、ack-koordinatorは、リソースプロファイリングやきめ細かいスケジューリングなどの機能のモニタリングメトリックをPrometheusメトリックとして公開します。 ack-koordinatorのPrometheusメトリクスを有効にし、PrometheusのManaged Serviceを使用する場合、これらのメトリクスはカスタムメトリクスと見なされ、料金が課金されます。 料金は、クラスターのサイズやアプリケーションの数などの要因によって異なります。 Prometheusメトリクスを有効にする前に、Prometheusのマネージドサービスの課金概要トピックを読んで、カスタムメトリクスの無料クォータと課金ルールを確認することをお勧めします。 リソース使用量を監視および管理する方法の詳細については、「リソース使用量と請求書」をご参照ください。

NUMAトポロジ対応スケジューリングの設定

次のアノテーションをポッドのYAMLファイルに追加して、NUMAトポロジ対応スケジューリングの要件を宣言できます。

apiVersion: v1
kind: Pod
metadata:
  annotations:
    cpuset-scheduler: required                           # Specifies whether to allocate both CPUs and GPUs to a NUMA node.
    scheduling.alibabacloud.com/numa-topology-spec: |    # The requirements of the pod for the NUMA topology policy.
      {
        "numaTopologyPolicy": "SingleNUMANode",
        "singleNUMANodeExclusive": "Preferred",
      }
spec:
  containers:
  - name: example
    resources:
      limits:
        aliyun.com/gpu: '4'
        cpu: '24'
      requests:
        aliyun.com/gpu: '4'
        cpu: '24'

次の表に、NUMAトポロジ対応スケジューリングのパラメーターを示します。

パラメーター

説明

cpuset-scheduler

CPUとGPUの両方をNUMAノードに割り当てるかどうかを指定します。

値をrequiredに設定します。

numaTopologyPolicy

ポッドスケジューリング中に使用されるNUMAトポロジポリシー。 有効な値:

  • SingleNUMANode: CPUとGPUを同じNUMAノードに割り当てます。 この要件を満たすノードがない場合、ポッドはスケジュールできません。

  • 制限付き: CPUとGPUを同じNUMAセットに割り当てます。 この要件を満たすノードがない場合、ポッドはスケジュールできません。

  • BestEffort: CPUとGPUを同じNUMAノードに割り当てます。 この要件を満たすノードがない場合、ポッドは最適なノードにスケジュールされます。

singleNUMANodeExclusive

ポッドスケジューリング中に特定のNUMAノードにポッドをスケジュールするかどうかを指定します。 有効な値:

説明

NUMAノードタイプ:

  • single: 単一のNUMAノードでのみ実行できるポッドを実行します。

  • shared: NUMAノード間で実行できるポッドを実行します。

  • idle: ポッドは実行されず、すべてのポッドで使用できます。

  • 必須 (デフォルト): ポッドを1つのNUMAノードでのみ実行できる場合は、ポッドをidleまたはsingleタイプの1つのNUMAノードにスケジュールします。ポッドをNUMAノード間で実行できる場合は、ポッドをidleまたはsharedタイプの複数のNUMAノードにスケジュールします。

  • Preferred: ポッドスケジューリング中のNUMAノードのタイプを制限しません。

パフォーマンスを比較する

この例では、モデルロードプロセスを使用して、NUMAトポロジ認識スケジューリングが有効になる前後のパフォーマンス改善をテストします。 テキスト生成推論ツールは、2つのGPUにモデルをロードするために使用されます。 NSightツールは、NUMAトポロジ認識スケジューリングが有効になる前と後のGPUの読み込み速度を比較するために使用されます。

この例では、Lingjunノードが使用されます。 テキスト生成推論ツールのダウンロード方法の詳細については、「テキスト生成推論」をご参照ください。 NSightツールのダウンロード方法の詳細については、「インストールガイド」をご参照ください。

重要

テスト結果は、使用されるテストツールに基づいて異なる場合があります。 この例のパフォーマンス比較データは、NSightツールを使用して得られたテスト結果のみです。 実際のデータは、運用環境によって異なります。

NUMAトポロジ対応スケジューリングを有効にする前に

次のサンプルコードは、NUMAトポロジ対応スケジューリングが有効になる前のテストシナリオでのアプリケーションのYAMLファイルを示しています。

YAMLファイルの表示

apiVersion: apps/v1
kind: Deployment
metadata:
  labels:
    app: tgi
  name: tgi-deployment-basic
  namespace: test
spec:
  replicas: 1
  selector:
    matchLabels:
      app: tgi
  template:
    metadata:
      labels:
        app: tgi
    spec:
      containers:
        - command:
            - sleep
            - 3600d
          image: >-
            ghcr.io/huggingface/text-generation-inference:1.4
          imagePullPolicy: IfNotPresent
          name: tgi
          ports:
            - containerPort: 80
              protocol: TCP
          resources:
            limits:
              cpu: '24'
              nvidia.com/gpu: '4'
            requests:
              cpu: '24'
              nvidia.com/gpu: '4'
          terminationMessagePath: /dev/termination-log
          terminationMessagePolicy: File
          volumeMounts:
            - mountPath: /llm
              name: volume-1710932083254
      restartPolicy: Always
      schedulerName: default-scheduler
      volumes:
        - name: volume-1710932083254
          persistentVolumeClaim:
            claimName: model

モデルの読み込みプロセスの期間を確認します。 テスト結果は、プロセスが約15.9秒かかることを示しています。

image.png

NUMAトポロジ対応スケジューリングが有効になった後

次のサンプルコードは、NUMAトポロジ認識スケジューリングを有効にした後のテストシナリオでのアプリケーションのYAMLファイルを示しています。

YAMLファイルの表示

apiVersion: apps/v1
kind: Deployment
metadata:
  labels:
    app: tgi-numa
  name: tgi-numa-deployment-basic
  namespace: yueming-test
spec:
  replicas: 1
  selector:
    matchLabels:
      app: tgi-numa
  template:
    metadata:
      annotations:
        cpuset-scheduler: required
        scheduling.alibabacloud.com/resource-spec: |
          {
            "numaTopologyPolicy": "SingleNUMANode"
          }
      labels:
        app: tgi-numa
    spec:
      containers:
        - command:
            - sleep
            - 3600d
          image: >-
            ghcr.io/huggingface/text-generation-inference:1.4
          imagePullPolicy: IfNotPresent
          name: numa
          resources:
            limits:
              aliyun.com/gpu: '4'
              cpu: '24'
            requests:
              aliyun.com/gpu: '4'
              cpu: '24'
          volumeMounts:
            - mountPath: /llm
              name: volume-1710932083254
      restartPolicy: Always
      schedulerName: default-scheduler
      volumes:
        - name: volume-1710932083254
          persistentVolumeClaim:
            claimName: model

モデルの読み込みプロセスの期間を確認します。 テスト結果は、プロセスが約5.4秒かかることを示しています。 期間は66% 短縮されます。

image

関連ドキュメント