🐈‍⬛

AWS Batchの最大vCPU設定を試してみる

2023/08/04に公開

概要

過日、会社制度を利用してAWS DevDayに参加しました。
その際に拝見した技術的負債になりかけていた機能をリアーキテクティングしたらめちゃくちゃ改善した話の中で、AWS Batchが取り上げられていました。
が、筆者は随分前にやや苦い思いをした記憶がある(※1)のを除けば、ちゃんと使ってみたことがなかったので、これを機会にとりあえず最大vCPU周りでも試してみようか、と検証した記録になります。

※1: やはり同日のAWS DevDayの中で拝見した第一回似てるサービス使い分け大会でも言及されていましたが、俗に本邦で「バッチ処理」といった場合、その意味するところは「定期業務におけるバッチ処理」と「大規模計算におけるバッチ処理」の2つがあります。AWS Batchが適しているのはどちらかと言うと後者なのですが、筆者は同サービスが登場して間もないころに、前者の目的でAWS Batchを利用しようとして痛い目を見た記憶があり、AWS Batchそれ自体にちょっと苦手意識を持っていました......。

構成

基本的に、環境構築はTerraformで実施しました。
実際にはPublicなサブネットにBatchの実行環境を用意することはそうそうないと思いますが、そこは検証目的ということで目を瞑っていただければ幸いです。
一応、関連リソースのtf定義だけ貼っておきます。

resource "aws_batch_compute_environment" "this" {
  compute_environment_name = "test"
  service_role             = aws_iam_role.aws_batch_service_role.arn
  compute_resources {
    max_vcpus          = var.max_vcpus // 今回は1を指定
    security_group_ids = [aws_security_group.aws_batch.id]
    subnets            = [aws_subnet.public["a"].id, aws_subnet.public["c"].id]
    type               = "FARGATE"
  }
  type       = "MANAGED"
  depends_on = [aws_iam_role_policy_attachment.aws_batch_service_role]

  lifecycle {
    create_before_destroy = true
  }
}
resource "aws_batch_job_definition" "job_definition" {
  name = "job-definition"
  type = "container"

  platform_capabilities = [
    "FARGATE",
  ]
  container_properties = templatefile("./job_definition.json", {
    execution_role_arn = aws_iam_role.aws_batch_execution_role.arn
    job_role_arn       = aws_iam_role.job_role.arn
  })
}
{
  "image": "busybox",
  "command": [
    "sleep",
    "100"
  ],
  "fargatePlatformConfiguration": {
    "platformVersion": "LATEST"
  },
  "networkConfiguration": {
    "assignPublicIp": "ENABLED"
  },
  "resourceRequirements": [
    {
      "type": "VCPU",
      "value": "0.25"
    },
    {
      "type": "MEMORY",
      "value": "512"
    }
  ],
  "jobRoleArn": "${job_role_arn}",
  "executionRoleArn": "${execution_role_arn}"
}

検証その1(単一種類のジョブを複数個)

今回の検証ポイントは最大vCPU、つまり上述のTerraform定義のうちaws_batch_compute_environment.thisにおいて定義しているmax_vcpusになります。
こちらは、当該コンピューティング環境において一度に消費できる最大のVCPU数を指定するパラメータで、今回の場合は1に設定しています。従ってVCPUを0.25要求するジョブであれば最大4並列、0.5要求するジョブであれば、最大2並列での実行が可能なはずです。

では、実際に確かめてみましょう。
AWSマネジメントコンソールから、配列サイズを8に設定してジョブを送信します。

aws_batch_job_definition.job_definitionにおいて定義したジョブを、8回実行するように指定しています。しかし同ジョブはVCPU数を0.25必要とするため、8並列での実行とはならず、4並列での実行が2回に分けて実施されるはずです。

想定通り、ジョブが4並列ずつ2回立ち上がって、合わせて8回の実行が達成されました。

検証その2(複数種類のジョブを複数個)

念の為、VCPUの要求数が異なるジョブを複数種類立ち上げた場合でも実験してみます。

{
  "image": "busybox",
  "command": [
    "sleep",
    "100"
  ],
  "fargatePlatformConfiguration": {
    "platformVersion": "LATEST"
  },
  "networkConfiguration": {
    "assignPublicIp": "ENABLED"
  },
  "resourceRequirements": [
    {
      "type": "VCPU",
      "value": "${vcpu}"
    },
    {
      "type": "MEMORY",
      "value": "${memory}"
    }
  ],
  "jobRoleArn": "${job_role_arn}",
  "executionRoleArn": "${execution_role_arn}"
}
resource "aws_batch_job_definition" "job_definition_025" {
  name = "job-definition-025"
  type = "container"

  platform_capabilities = [
    "FARGATE",
  ]
  container_properties = templatefile("./job_definition.json", {
    execution_role_arn = aws_iam_role.aws_batch_execution_role.arn
    job_role_arn       = aws_iam_role.job_role.arn
    vcpu               = "0.25"
    memory             = "512"
  })
}

resource "aws_batch_job_definition" "job_definition_050" {
  name = "job-definition-050"
  type = "container"

  platform_capabilities = [
    "FARGATE",
  ]
  container_properties = templatefile("./job_definition.json", {
    execution_role_arn = aws_iam_role.aws_batch_execution_role.arn
    job_role_arn       = aws_iam_role.job_role.arn
    vcpu               = "0.5"
    memory             = "1024"
  })
}

terraformをちょっと修正して、1つのテンプレートファイルから2種類のジョブ定義が作成されるようにしています。
0.5VCPUを要求するjob-definition-050と、先ほど同様に0.25VCPUを要求するjob-definition-025です。max_vcpusの設定がうまく働いてくれれば、前者(job-definition-050)を1つ実行している状態で、同一のコンピューティング環境を用いて、新たに後者(job-definition-025)3つの実行を命じた時、はじめに2つのジョブが立ち上がるものの、そこでmax_vcpusの制約に引っかかり、1つのジョブがRUNNABLE状態で待機になるはずです。

はじめに、job-defintion-0501ジョブの実行を命じます。

次いで、job-definition-0253ジョブの実行を命じます。

3つのジョブのうち、2つまではすぐに実行されるものの、1つはRUNNABLEで待機になるはずです。

こちらも想定通り。先行した2ジョブに遅れることしばらく、コンピューティング環境のVCPUに空きがでた時点で、残り1ジョブが処理されました。

まとめ

max_vcpusの設定を用いることで、1つのコンピューティング環境内で同時に実行されるバッチジョブの数を制限できることが検証できました。
実際にこの機能が奏功するケースとなると、たとえば一定の金額に収まる範囲で可能な限りジョブをぶん回したいというような経済的制約への対応や、おそらくはこちらの方が多いと思いますが、ジョブの実行数が多くなりすぎるとデータベースの負荷や外部API呼び出しのRate Limitなどが懸念されるため、一定数以下にとどめたいというような状況となるでしょう。
今回の記事の検証対象からは外しましたが、AWS Batchには失敗したバッチジョブ単体でのリトライ機能など、
他にも便利そうな機能が揃っていますので、必要に応じて活用してみるのもいいかと思います。

Fivot Tech Blog

Discussion