AWS ParallelCluster ひとつのキューに複数のインスタンスタイプを登録して AllocationStrategy を試してみた

2022.11.08

AWS ParallelCluster 3.3.0 で追加された機能の「ひとつのキューに複数のインスタンスタイプの割り当て」を試してみました。動作確認に使用したクラスターのコンフィグを紹介します。

複数のインスタンスタイプをひとつのキューに登録できるメリットは上記のリンクで紹介しております。こちらの記事にも一部再掲します。

本記事で検証する新機能

ひとつキューに複数のインスタンスタイプを登録し、計算に利用するコンピュートリソースを複数あるインスタンスタイプの中から自動選択する優先順位をユーザー側で決めることができるようになりました。具体的な利用例としてスポットインスタンスで計算する場合を前提に考えてみます。

最安価なコスト優先の戦略

複数のインスタンスタイプの中からもっともスポットインスタンスの利用単価が安いのを優先してコンピュートノードを起動します。スポットインスタンスの単価は需要と供給のバランスで変動します。スポットインスタンスのコストをユーザー側で確認して今安いインスタンスタイプのあるキューを選択してジョブをサブミットする行為が必要なくなります。

デフォルトは最安価なコストを優先するの戦略になっています。

キャパシティ最適化優先の戦略

起動するインスタンス数に対して最適なキャパシティがあるインスタンスタイプを優先してスポットインスタンスを起動します。つまり、スポットインスタンスの中断率を下げることができます。

スポットインスタンスは計算中に中断が発生するかもしれないけど大幅な割り引き(最大90%オフ)を受けられるというトレードオフの関係にあります。アプリケーションが中断に備えてチェックポイントを作成できない、再実行するのに長時間かかる、だけど利用費を下げたいときはこちらの戦略がオススメです。

諸条件・設定方法

複数のインスタンスタイプをひとつのキューに登録するための必須要件をまとめておきます。

  • 同じ vCPU 数であること
    • Hyper-Threading 無効化時は物理コア数が同数であること
    • x86_64 と arm64 の混在は不可
    • Intel なら Intel、AMD なら AMD で統一
  • EFA をサポートしているインスタンスタイプなら EFA を有効化にすること

インスタンスのスペック確認は以下の方法が便利です。

その他注意事後はドキュメントをご確認ください。

検証環境

本機能は v3.3.0 で新たにサポートされました。古いバージョンではサポートされておりませんのでご注意ください。

# pcluster version
{
  "version": "3.3.0"
}

サンプルコンフィグ

インスタンスタイプはc6i.large,m6i.large,r6i.largeを混合したキューを作成しました。AllocationStrategyの違いで2つキューを用意しました。

  • queue-1: 最安価なコスト優先の配置戦略を指定
  • queue-2: キャパシティ最適化優先の配置戦略を指定
項目
ParallelCluster 3.3.0
OS Ubuntu 20.04
CPU Intel
Head Node t3.micro
Compute Node queue-1 と queue-2
Simultaneous Multi-Threading 無効
Placement group 有効
CloudWatch Dashboard 無効

multi-instancetypes.yaml

Region: ap-northeast-1
Image:
  Os: ubuntu2004
Tags:
  - Key: Name
    Value: MultipleTypeCluster
# ----------------------------------------------------------------
# Head Node Settings
# ----------------------------------------------------------------
HeadNode:
  InstanceType: t3.micro
  Networking:
    ElasticIp: false
    SubnetId: subnet-035be95eeaa091603
  Ssh:
    KeyName: sandbox-key
  LocalStorage:
    RootVolume:
      Size: 35
      Encrypted: true
      VolumeType: gp3
      Iops: 3000
      Throughput: 125
  Iam:
    AdditionalIamPolicies:
      - Policy: arn:aws:iam::aws:policy/AmazonSSMManagedInstanceCore
    S3Access:
      - BucketName: hpc-dev-postinstall-files
        EnableWriteAccess: false
# ----------------------------------------------------------------
# Compute Node Settings
# ----------------------------------------------------------------
Scheduling:
  Scheduler: slurm
  SlurmSettings:
    ScaledownIdletime: 5
  SlurmQueues:
    # ------ Debug 1 without Postinstall ------
    - Name: debug-1
      ComputeResources:
        - Name: debug-without-postinstall
          InstanceType: t3.micro
          MinCount: 0
          MaxCount: 10
          DisableSimultaneousMultithreading: false
      ComputeSettings:
        LocalStorage:
          RootVolume:
            Size: 35
            Encrypted: true
            VolumeType: gp3
            Iops: 3000
            Throughput: 125
      CapacityType: SPOT
      Networking:
        SubnetIds:
          - subnet-035be95eeaa091603
        PlacementGroup:
          Enabled: false
      Iam:
        AdditionalIamPolicies:
          - Policy: arn:aws:iam::aws:policy/AmazonSSMManagedInstanceCore
        S3Access:
          - BucketName: hpc-dev-postinstall-files
            EnableWriteAccess: false
    # ------ Debug 2 with Postinstall ------
    - Name: debug-2
      ComputeResources:
        - Name: debug-run-postinstall
          InstanceType: t3.micro
          MinCount: 0
          MaxCount: 10
          DisableSimultaneousMultithreading: false
      ComputeSettings:
        LocalStorage:
          RootVolume:
            Size: 35
            Encrypted: true
            VolumeType: gp3
            Iops: 3000
            Throughput: 125
      CapacityType: SPOT
      Networking:
        SubnetIds:
          - subnet-035be95eeaa091603
        PlacementGroup:
          Enabled: false
      CustomActions:
        OnNodeConfigured:
          Script: s3://hpc-dev-postinstall-files/sample-ubuntu-docker/postinstall.sh
      Iam:
        AdditionalIamPolicies:
          - Policy: arn:aws:iam::aws:policy/AmazonSSMManagedInstanceCore
        S3Access:
          - BucketName: hpc-dev-postinstall-files
            EnableWriteAccess: false
    # ------ Compute 1 ------
    - Name: queue-1
      ComputeResources:
        - Name: multi6i-serices-price
          Instances:
            - InstanceType: c6i.large
            - InstanceType: m6i.large
            - InstanceType: r6i.large
          MinCount: 0
          MaxCount: 10
          DisableSimultaneousMultithreading: true
      ComputeSettings:
        LocalStorage:
          RootVolume:
            Size: 35
            Encrypted: true
            VolumeType: gp3
            Iops: 3000
            Throughput: 125
      CapacityType: SPOT
      AllocationStrategy: lowest-price
      Networking:
        SubnetIds:
          - subnet-035be95eeaa091603
        PlacementGroup:
          Enabled: true
      CustomActions:
        OnNodeConfigured:
          Script: s3://hpc-dev-postinstall-files/sample-ubuntu-docker/postinstall.sh
      Iam:
        AdditionalIamPolicies:
          - Policy: arn:aws:iam::aws:policy/AmazonSSMManagedInstanceCore
        S3Access:
          - BucketName: hpc-dev-postinstall-files
            EnableWriteAccess: false
    # ------ Compute 2 ------
    - Name: queue-2
      ComputeResources:
        - Name: multi6i-serices-capacity
          Instances:
            - InstanceType: c6i.large
            - InstanceType: m6i.large
            - InstanceType: r6i.large
          MinCount: 0
          MaxCount: 10
          DisableSimultaneousMultithreading: true
      ComputeSettings:
        LocalStorage:
          RootVolume:
            Size: 35
            Encrypted: true
            VolumeType: gp3
            Iops: 3000
            Throughput: 125
      CapacityType: SPOT
      AllocationStrategy: capacity-optimized
      Networking:
        SubnetIds:
          - subnet-035be95eeaa091603
        PlacementGroup:
          Enabled: true
      CustomActions:
        OnNodeConfigured:
          Script: s3://hpc-dev-postinstall-files/sample-ubuntu-docker/postinstall.sh
      Iam:
        AdditionalIamPolicies:
          - Policy: arn:aws:iam::aws:policy/AmazonSSMManagedInstanceCore
        S3Access:
          - BucketName: hpc-dev-postinstall-files
            EnableWriteAccess: false
# ----------------------------------------------------------------
# Shared Storage Settings
# ----------------------------------------------------------------
SharedStorage:
  - MountDir: /mnt/efs-1zone
    Name: efs-1zone
    StorageType: Efs
    EfsSettings:
      FileSystemId: fs-0f1158ade79354809
# ----------------------------------------------------------------
#  Other Settings
# ----------------------------------------------------------------
Monitoring:
  Logs:
    CloudWatch:
      Enabled: true
      RetentionInDays: 30
      DeletionPolicy: "Delete"
  Dashboards:
    CloudWatch:
      Enabled: false

Dry Run を実行

インスタンスタイプを混在しているけど Placement Group を有効にしていると、インスタンスのキャパシティ不足を引きやすなると警告メッセージが出力されました。今まで見ることのなかったタイプのメッセージです、インスタンスタイプの混在なんてできませんでしたからね。

$ pcluster create-cluster -n MultiTypeCluster -c multi-instancetypes.yaml --dryrun ture
{
  "validationMessages": [
    {
      "level": "WARNING",
      "type": "InstancesNetworkingValidator",
      "message": "Enabling placement groups for queue: queue-1 may result in Insufficient Capacity Errors due to the use of multiple instance types for Compute Resource: multi6i-serices-price (https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/placement-groups.html#placement-groups-cluster)."
    },
    {
      "level": "WARNING",
      "type": "InstancesNetworkingValidator",
      "message": "Enabling placement groups for queue: queue-2 may result in Insufficient Capacity Errors due to the use of multiple instance types for Compute Resource: multi6i-serices-capacity (https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/placement-groups.html#placement-groups-cluster)."
    }
  ],
  "message": "Request would have succeeded, but DryRun flag is set."
}

ParallelCluster のコンフィグで Placement Group を有効化するとクラスター戦略で作成されます。言い換えるとスプレッドや、パーテイション指定は作成できません。Placement Group の ID 指定ができるため、先に任意の Placement Group を作成して ID を指定する方法が取るとよいのかもしれません。ここは別の機会に検証してみたいと思います。

クラスター作成・動作確認

クラスターを作成します。

$ pcluster create-cluster -n MultiTypeCluster -c multi-instancetypes.yaml

ヘッドノードへログイン

queue-1,2が複数インスタンスタイプを登録してあるキューです。

$ sinfo
PARTITION AVAIL  TIMELIMIT  NODES  STATE NODELIST
debug-1*     up   infinite     10  idle~ debug-1-dy-debug-without-postinstall-[1-10]
debug-2      up   infinite     10  idle~ debug-2-dy-debug-run-postinstall-[1-10]
queue-1      up   infinite     10  idle~ queue-1-dy-multi6i-serices-price-[1-10]
queue-2      up   infinite     10  idle~ queue-2-dy-multi6i-serices-capacity-[1-10]

テストジョブを作成します。

test1.sh

#! /bin/bash

#SBATCH -N 1

curl http://169.254.169.254/latest/meta-data/instance-type

最安価なコスト優先と、キャパシティ優先の2つのキューを対象にジョブをサブミットしてみました。

$ sbatch -p queue-1 test1.sh
$ sbatch -p queue-2 test1.sh

$ squeue
             JOBID PARTITION     NAME     USER ST       TIME  NODES NODELIST(REASON)
                 1   queue-1 test1.sh   ubuntu CF       0:12      1 queue-1-dy-multi6i-serices-price-1
                 2   queue-2 test1.sh   ubuntu CF       0:01      1 queue-2-dy-multi6i-serices-capacity-1

何のインスタンスタイプが起動してくるか見守ります。ともにc6i.largeが起動してきました。

スポット価格を確認

c6i.largeのスポット価格が他に比べると一番安かったのでコストが優先されていますね。

スポットインスタンスの中断率を確認

3タイプともユーザーから確認できる範囲では5%より少ないという情報しかありません。その中でもc6i.largeが選ばれて起動してきたようです。

わかりやすいパターン

16xlargeにもなると顕著に中断率の違いが見られました。現時点でc6i.16xlargem6i.16xlargeを登録したキューでキャパシティ優先指定であればm6i.16xlargeが起動してきたはずです。次回はさきに中断率を確認してテストしやすいケースのキューを作成して挙動をご紹介できればと思います。

コスト優先だとc6i.16xlargeが起動してきたことでしょう。中断率は高いということは需要があるというでしょうけど、それでもコストは安かったんですね。

おわりに

今回紹介した機能は v3.3.0 の目玉アップデート機能と思われる内容でしたので、クラスターのコンフィグを参考にぜひ試してみてください。

AWS HPC Blog でも取り上げられておりますので以下の記事もご確認していただくとなおよろしいかと思います。

参考