[アップデート] ECS がスナップショットから EBS を作成してアタッチする際にデータ転送速度を指定できるようになりました

[アップデート] ECS がスナップショットから EBS を作成してアタッチする際にデータ転送速度を指定できるようになりました

こんにちは。クラウド事業本部の枡川です。
ECS がスナップショットからリストアして EBS を扱う際、初期化にかかるデータ転送速度を指定可能になりました。

https://aws.amazon.com/jp/about-aws/whats-new/2025/05/amazon-ecs-ebs-provisioned-rate-volume-initialization/

一足先に EBS 側で利用できるようになった機能を ECS でも利用できるようになった形です。

https://dev.classmethod.jp/articles/ebs-provisioned-rate-volume-initialization/

スナップショットから EBS ボリュームを作成した場合、最初はデータの実体が S3 に存在するために、初回アクセス時のレイテンシが増加することがあります。

スナップショットから作成されたボリュームの場合、ボリュームのタイプを問わず、アクセスする前に、ストレージブロックが Amazon S3 からプルダウンされてボリュームに書き込こまれている必要があります。この事前処理には一定の時間がかかるため、各ブロックへの初回アクセス時には、I/O 操作のレイテンシーが著しく増加する可能性があります。ボリュームのパフォーマンスは、すべてのブロックがダウンロードされてボリュームに書き込まれると正常値に達します。
Amazon EBS ボリュームの初期化

従来から fio や dd などを活用して全ブロックを事前に初期化しておくことが可能でしたが、この場合はスクリプトを作成して適用する手間が必要です。
本機能を利用することでスクリプト作成や運用の手間が省ける上、データ転送速度を指定することで初期化完了までの時間を予測しやすくなりました。

ECS における EBS 利用の主なメリットとして、ML 推論など大量のデータを扱うワークロードにおいて、EFS より安く S3 より低レイテンシで「ちょうど良く一時ストレージを扱える」ということがあります。

https://dev.classmethod.jp/articles/amazon-ecs-supports-amazon-ebs-as-an-ephemeral-volume/

あくまで一時ストレージ領域であることから EC2 を利用するケースより EBS のライフサイクルが短くなると想定されるので、初回アクセスのレイテンシが比較的重いコストになりがちです。
EBS 側で GA した直後に ECS でも対応したのはこういった背景もあるのかなと思っています。

やってみる

先ほど紹介した弊社のブログ記事である、 [アップデート] Amazon ECS が一時領域として Amazon EBS のアタッチをサポートしました においてマネジメントコンソールで設定する方法は紹介されており、同じことをしてもつまらないので今回は Terraform でリソースを定義してみます。
とはいえ肝心の「ボリューム初期化レート」周りはまだ設定できないので、そこだけマネジメントコンソールで設定します。

まず、VPC を作成します。

module "vpc" {
  source                  = "terraform-aws-modules/vpc/aws"
  version                 = "~> 5.7.1"

  name                    = "${local.resource_prefix}-vpc"
  cidr                    = "10.0.0.0/16"
  azs                     = ["ap-northeast-1a", "ap-northeast-1c"]
  public_subnets          = ["10.0.0.0/24", "10.0.1.0/24"]
  private_subnets         = ["10.0.10.0/24", "10.0.11.0/24"]
  enable_dns_hostnames    = true
  map_public_ip_on_launch = false
  enable_nat_gateway      = true
  single_nat_gateway      = true
}

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

resource "aws_ecs_cluster" "ecs_cluster" {
  name = "${local.resource_prefix}-ecs-cluster"
  setting {
    name  = "containerInsights"
    value = "disabled"
  }
}

タスク実行ロールを作成します。

resource "aws_iam_role_policy_attachment" "task_execution_basis" {
  role       = aws_iam_role.task_execution.id
  policy_arn = "arn:aws:iam::aws:policy/service-role/AmazonECSTaskExecutionRolePolicy"
}

resource "aws_iam_role" "task_execution" {
  name = "${local.resource_prefix}-role-task-execution"

  assume_role_policy = <<EOF
{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Action": "sts:AssumeRole",
      "Principal": {
        "Service": "ecs-tasks.amazonaws.com"
      },
      "Effect": "Allow",
      "Sid": ""
    }
  ]
}
EOF
}

コンテナ周りの定義は JSON で管理する形としました。
mountPoints の指定が必要なこと以外、特殊な設定は無いです。

[
  {
    "name": "app",
    "image": "xxxxxxxxxxx.dkr.ecr.ap-northeast-1.amazonaws.com/masukawa-test-nextjs-app:v2",
    "essential": true,
    "readonlyRootFilesystem": false,
    "logConfiguration": {
      "logDriver": "awslogs",
      "options": {
        "awslogs-region": "ap-northeast-1",
        "awslogs-stream-prefix": "ecs",
        "awslogs-group": "/ecs/nextjs-app"
      }
    },
    "mountPoints": [
      {
        "containerPath": "/mount/ebs",
        "readOnly": false,
        "sourceVolume": "ebs-volume"
      }
    ],
    "taskRoleArn": "arn:aws:iam::xxxxxxxxxxx:role/masukawa-test-role-nextjs-ecs-task",
    "portMappings": [
      {
        "name": "next_app",
        "protocol": "tcp",
        "containerPort": 80,
        "appProtocol": "http"
      }
    ]
  }
]

ECS のタスク定義として、volume の指定も必要です。
細かい部分は ECS サービス側で行うので、configure_at_launchtrue にします。

resource "aws_ecs_task_definition" "nextjs" {
  family                   = "nextjs-app"
  cpu                      = "4096"
  memory                   = "8192"
  network_mode             = "awsvpc"
  requires_compatibilities = ["FARGATE"]
  container_definitions    = file("./contaner_definitions/nextjs-app.json")
  execution_role_arn       = aws_iam_role.task_execution.arn
  task_role_arn            = aws_iam_role.nextjs_task.arn
  volume {
    name                = "ebs-volume"
    configure_at_launch = true
  }
}

ECS サービスの volume_configuration で細かい設定を行います。

https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/ecs_service#managed_ebs_volume

今回は下記設定としました。

設定項目 設定値
サイズ 100GB
IOPS 3000
スループット 125MiB/s
ファイルシステムの種類 ext3

また、インフラストラクチャロールとして AmazonECSInfrastructureRolePolicyForVolumes をアタッチした IAM ロールを指定しておきます。

resource "aws_ecs_service" "nextjs" {
  name                              = "${local.resource_prefix}-service-nextjs"
  cluster                           = aws_ecs_cluster.ecs_cluster.arn
  task_definition                   = aws_ecs_task_definition.nextjs.arn
  desired_count                     = 1
  platform_version                  = "1.4.0"
  health_check_grace_period_seconds = 60
  enable_execute_command            = true

  network_configuration {
    assign_public_ip = false
    security_groups  = [aws_security_group.nextjs.id]
    subnets          = module.vpc.private_subnets
  }

  volume_configuration {
    name = "ebs-volume"
    managed_ebs_volume {
      role_arn         = aws_iam_role.nextjs_infra.arn
      size_in_gb       = 100
      iops             = 3000
      throughput       = 125
      snapshot_id      = "snap-xxxxxxxxxxxxxx"
      volume_type      = "gp3"
      encrypted        = true
      file_system_type = "ext3"
    }
  }

  capacity_provider_strategy {
    capacity_provider = "FARGATE_SPOT"
    base              = 1
    weight            = 1
  }
  capacity_provider_strategy {
    capacity_provider = "FARGATE"
    base              = 0
    weight            = 0
  }
}

resource "aws_cloudwatch_log_group" "nextjs-app" {
  name              = "/ecs/nextjs-app"
  retention_in_days = 90
}

resource "aws_iam_role" "nextjs_task" {
  name = "${local.resource_prefix}-role-nextjs-ecs-task"

  assume_role_policy = jsonencode({
    "Version": "2012-10-17",
    "Statement": [
      {
        "Sid": "",
        "Effect": "Allow",
        "Principal": {
          "Service": "ecs-tasks.amazonaws.com"
        },
        "Action": "sts:AssumeRole"
      }
    ]
  })
}

resource "aws_iam_policy" "nextjs_task" {
  name = "${local.resource_prefix}-policy-nextjs-ecs-task"
  path = "/service-role/"

  policy = jsonencode({
    "Version": "2012-10-17",
    "Statement": [
      {
        "Action": [
          "s3:*",
        ],
        "Effect": "Allow",
        "Resource": [
          "*"
        ]
      },
      {
        "Action": [
          "ssmmessages:CreateControlChannel",
          "ssmmessages:CreateDataChannel",
          "ssmmessages:OpenControlChannel",
          "ssmmessages:OpenDataChannel"
        ],
        "Effect": "Allow",
        "Resource": [
          "*"
        ]
      }
    ]
  })
}

resource "aws_iam_role_policy_attachment" "ecs_task" {
  policy_arn = aws_iam_policy.nextjs_task.arn
  role       = aws_iam_role.nextjs_task.name
}

resource "aws_iam_role" "nextjs_infra" {
  name = "${local.resource_prefix}-role-ecs-infra"

  assume_role_policy = jsonencode({
    "Version": "2012-10-17",
    "Statement": [
      {
        "Sid": "AllowAccessToECSForInfrastructureManagement",
        "Effect": "Allow",
        "Principal": {
          "Service": "ecs.amazonaws.com"
        },
        "Action": "sts:AssumeRole"
      }
    ]
  })
}

resource "aws_iam_role_policy_attachment" "nextjs_infra" {
  role       = aws_iam_role.nextjs_infra.name
  policy_arn = "arn:aws:iam::aws:policy/service-role/AmazonECSInfrastructureRolePolicyForVolumes"
}

サービスの設定としては下記のようになります。
赤枠で囲ってある「ボリューム初期化レート」が今回のアップデートで設定可能になった項目です。

ecs-ebs-6.png

タスク側から確認しても、EBS がアタッチされていることを確認できます。

ecs-ebs-5.png

この EBS ですが、下記スクリプトを利用して 1MB のファイルを 1000 個作成して配置しておきました。

#!/bin/bash

# ファイルを保存するディレクトリ
OUTPUT_DIR="/path/to/directory"

# ディレクトリが存在しない場合は作成
mkdir -p $OUTPUT_DIR

# 1000個のファイルを作成
for i in $(seq 1 1000); do
  num=$i

  # ddコマンドで1MBのファイルを作成
  dd if=/dev/zero of="${OUTPUT_DIR}/testfile-${num}" bs=1M count=1 status=none

  # 進捗表示(100ファイルごと)
  if [ $((i % 100)) -eq 0 ]; then
    echo "${i}個のファイルを作成しました"
  fi
done

echo "合計1000個のファイルを作成しました"

その上で、下記スクリプトでファイルアクセス時計を計測していきます。

#!/bin/bash

# 設定
FILE_PREFIX="./testfile-"
TOTAL_FILES=1000
ACCESS_COUNT=100
RESULTS_FILE="latency_results.csv"

# 結果ファイルの初期化
echo "access_number,file_number,latency_ms" > $RESULTS_FILE

for i in $(seq 1 $ACCESS_COUNT); do
  # 1から1000までのランダムな数字を生成
  random_file=$((RANDOM % TOTAL_FILES + 1))

  # ファイルへのアクセス時間を計測
  start_time=$(date +%s.%N)

  # ファイルの読み取り (キャッシュの影響を減らすためにddを使用)
  dd if="${FILE_PREFIX}${random_file}" of=/dev/null bs=1M count=1 iflag=direct 2>/dev/null

  end_time=$(date +%s.%N)

  # 経過時間をミリ秒で計算
  latency_ms=$(awk -v start="$start_time" -v end="$end_time" '\''BEGIN {print (end - start) * 1000}'\'')

  # 結果を記録
  echo "$i,$random_file,$latency_ms" >> $RESULTS_FILE

  echo "アクセス $i: ファイル $random_file へのアクセス - レイテンシ: ${latency_ms}ms"
done

echo "計測完了。結果は $RESULTS_FILE に保存されました。"

# 統計情報を表示
echo "統計情報:"
echo "平均レイテンシ: $(awk -F, '\''NR>1 {sum+=$3; count++} END {print sum/count}'\'' $RESULTS_FILE) ms"
echo "最小レイテンシ: $(sort -t, -k3,3n $RESULTS_FILE | awk -F, '\''NR==2 {print $3}'\'' ) ms"
echo "最大レイテンシ: $(sort -t, -k3,3nr $RESULTS_FILE | awk -F, '\''NR==2 {print $3}'\'' ) ms"

ちなみに、ファイル作成直後に計測したら平均レイテンシは 16.3813 ms でした。
こちらが初回アクセスした際のレイテンシが無い場合の値になるはずです。

# ./measure_latency.sh
アクセス 1: ファイル 469 へのアクセス - レイテンシ: 4.25339ms
アクセス 2: ファイル 571 へのアクセス - レイテンシ: 3.92199ms
アクセス 3: ファイル 180 へのアクセス - レイテンシ: 3.63874ms
アクセス 4: ファイル 83 へのアクセス - レイテンシ: 3.97897ms
アクセス 5: ファイル 960 へのアクセス - レイテンシ: 76.9579ms
アクセス 6: ファイル 52 へのアクセス - レイテンシ: 3.74269ms
アクセス 7: ファイル 695 へのアクセス - レイテンシ: 3.85809ms
アクセス 8: ファイル 118 へのアクセス - レイテンシ: 3.94249ms
アクセス 9: ファイル 497 へのアクセス - レイテンシ: 3.66902ms
アクセス 10: ファイル 941 へのアクセス - レイテンシ: 71.095ms
アクセス 11: ファイル 422 へのアクセス - レイテンシ: 3.66879ms
アクセス 12: ファイル 692 へのアクセス - レイテンシ: 3.57199ms
アクセス 13: ファイル 789 へのアクセス - レイテンシ: 3.60155ms
アクセス 14: ファイル 363 へのアクセス - レイテンシ: 3.67999ms
アクセス 15: ファイル 891 へのアクセス - レイテンシ: 64.9166ms
アクセス 16: ファイル 916 へのアクセス - レイテンシ: 89.6916ms
アクセス 17: ファイル 695 へのアクセス - レイテンシ: 3.49808ms
アクセス 18: ファイル 705 へのアクセス - レイテンシ: 3.65567ms
アクセス 19: ファイル 265 へのアクセス - レイテンシ: 3.9351ms
アクセス 20: ファイル 446 へのアクセス - レイテンシ: 4.31156ms
アクセス 21: ファイル 477 へのアクセス - レイテンシ: 4.03786ms
アクセス 22: ファイル 26 へのアクセス - レイテンシ: 3.95131ms
アクセス 23: ファイル 643 へのアクセス - レイテンシ: 3.90959ms
アクセス 24: ファイル 300 へのアクセス - レイテンシ: 3.58844ms
アクセス 25: ファイル 940 へのアクセス - レイテンシ: 60.914ms
アクセス 26: ファイル 231 へのアクセス - レイテンシ: 3.72696ms
アクセス 27: ファイル 747 へのアクセス - レイテンシ: 80.3185ms
アクセス 28: ファイル 862 へのアクセス - レイテンシ: 77.3048ms
アクセス 29: ファイル 565 へのアクセス - レイテンシ: 3.86882ms
アクセス 30: ファイル 712 へのアクセス - レイテンシ: 3.65233ms
アクセス 31: ファイル 869 へのアクセス - レイテンシ: 73.55ms
アクセス 32: ファイル 193 へのアクセス - レイテンシ: 3.62611ms
アクセス 33: ファイル 978 へのアクセス - レイテンシ: 101.162ms
アクセス 34: ファイル 704 へのアクセス - レイテンシ: 3.70455ms
アクセス 35: ファイル 935 へのアクセス - レイテンシ: 84.9452ms
アクセス 36: ファイル 579 へのアクセス - レイテンシ: 3.70073ms
アクセス 37: ファイル 264 へのアクセス - レイテンシ: 3.78156ms
アクセス 38: ファイル 955 へのアクセス - レイテンシ: 100.831ms
アクセス 39: ファイル 597 へのアクセス - レイテンシ: 3.77035ms
アクセス 40: ファイル 937 へのアクセス - レイテンシ: 94.6074ms
アクセス 41: ファイル 171 へのアクセス - レイテンシ: 3.69763ms
アクセス 42: ファイル 665 へのアクセス - レイテンシ: 3.75295ms
アクセス 43: ファイル 986 へのアクセス - レイテンシ: 72.6895ms
アクセス 44: ファイル 452 へのアクセス - レイテンシ: 3.87597ms
アクセス 45: ファイル 779 へのアクセス - レイテンシ: 3.59774ms
アクセス 46: ファイル 117 へのアクセス - レイテンシ: 3.48806ms
アクセス 47: ファイル 151 へのアクセス - レイテンシ: 3.61347ms
アクセス 48: ファイル 302 へのアクセス - レイテンシ: 3.56817ms
アクセス 49: ファイル 470 へのアクセス - レイテンシ: 3.71528ms
アクセス 50: ファイル 925 へのアクセス - レイテンシ: 104.584ms
アクセス 51: ファイル 592 へのアクセス - レイテンシ: 4.27127ms
アクセス 52: ファイル 546 へのアクセス - レイテンシ: 3.80373ms
アクセス 53: ファイル 44 へのアクセス - レイテンシ: 3.42298ms
アクセス 54: ファイル 88 へのアクセス - レイテンシ: 3.68714ms
アクセス 55: ファイル 320 へのアクセス - レイテンシ: 3.73077ms
アクセス 56: ファイル 327 へのアクセス - レイテンシ: 3.72124ms
アクセス 57: ファイル 667 へのアクセス - レイテンシ: 3.62015ms
アクセス 58: ファイル 443 へのアクセス - レイテンシ: 3.63421ms
アクセス 59: ファイル 465 へのアクセス - レイテンシ: 4.15254ms
アクセス 60: ファイル 329 へのアクセス - レイテンシ: 3.86357ms
アクセス 61: ファイル 253 へのアクセス - レイテンシ: 3.67713ms
アクセス 62: ファイル 244 へのアクセス - レイテンシ: 3.59797ms
アクセス 63: ファイル 597 へのアクセス - レイテンシ: 3.59702ms
アクセス 64: ファイル 87 へのアクセス - レイテンシ: 3.97849ms
アクセス 65: ファイル 648 へのアクセス - レイテンシ: 3.76034ms
アクセス 66: ファイル 798 へのアクセス - レイテンシ: 3.44348ms
アクセス 67: ファイル 46 へのアクセス - レイテンシ: 3.57795ms
アクセス 68: ファイル 643 へのアクセス - レイテンシ: 3.42846ms
アクセス 69: ファイル 382 へのアクセス - レイテンシ: 3.87788ms
アクセス 70: ファイル 693 へのアクセス - レイテンシ: 3.77297ms
アクセス 71: ファイル 493 へのアクセス - レイテンシ: 3.61109ms
アクセス 72: ファイル 546 へのアクセス - レイテンシ: 3.66569ms
アクセス 73: ファイル 523 へのアクセス - レイテンシ: 3.5429ms
アクセス 74: ファイル 363 へのアクセス - レイテンシ: 3.52454ms
アクセス 75: ファイル 600 へのアクセス - レイテンシ: 3.57437ms
アクセス 76: ファイル 292 へのアクセス - レイテンシ: 3.86024ms
アクセス 77: ファイル 702 へのアクセス - レイテンシ: 3.54934ms
アクセス 78: ファイル 166 へのアクセス - レイテンシ: 3.39675ms
アクセス 79: ファイル 390 へのアクセス - レイテンシ: 3.60823ms
アクセス 80: ファイル 401 へのアクセス - レイテンシ: 3.5665ms
アクセス 81: ファイル 330 へのアクセス - レイテンシ: 3.64184ms
アクセス 82: ファイル 215 へのアクセス - レイテンシ: 3.84569ms
アクセス 83: ファイル 5 へのアクセス - レイテンシ: 3.49665ms
アクセス 84: ファイル 750 へのアクセス - レイテンシ: 87.0831ms
アクセス 85: ファイル 389 へのアクセス - レイテンシ: 3.6335ms
アクセス 86: ファイル 222 へのアクセス - レイテンシ: 3.77154ms
アクセス 87: ファイル 385 へのアクセス - レイテンシ: 3.58319ms
アクセス 88: ファイル 625 へのアクセス - レイテンシ: 3.4411ms
アクセス 89: ファイル 532 へのアクセス - レイテンシ: 3.474ms
アクセス 90: ファイル 856 へのアクセス - レイテンシ: 85.197ms
アクセス 91: ファイル 713 へのアクセス - レイテンシ: 3.65114ms
アクセス 92: ファイル 666 へのアクセス - レイテンシ: 3.66497ms
アクセス 93: ファイル 214 へのアクセス - レイテンシ: 3.78966ms
アクセス 94: ファイル 108 へのアクセス - レイテンシ: 3.63994ms
アクセス 95: ファイル 856 へのアクセス - レイテンシ: 3.64566ms
アクセス 96: ファイル 379 へのアクセス - レイテンシ: 3.85857ms
アクセス 97: ファイル 108 へのアクセス - レイテンシ: 3.865ms
アクセス 98: ファイル 187 へのアクセス - レイテンシ: 3.71718ms
アクセス 99: ファイル 756 へのアクセス - レイテンシ: 3.47161ms
アクセス 100: ファイル 417 へのアクセス - レイテンシ: 4.01664ms
計測完了。結果は latency_results.csv に保存されました。
統計情報:
平均レイテンシ: 16.3813 ms
最小レイテンシ: 3.39675 ms
最大レイテンシ: 101.162 ms

「ボリューム初期化レート」を設定していない場合、ECS タスク作成直後にスクリプトを実行すると、平均レイテンシは 100.418 ms となりました。
ファイル数も少なくて精度は怪しいですが、初回アクセス時はレイテンシが乗って平均レイテンシが増加していると考えて良さそうです。

# ./measure_latency.sh
アクセス 1: ファイル 178 へのアクセス - レイテンシ: 148.983ms
アクセス 2: ファイル 168 へのアクセス - レイテンシ: 154.64ms
アクセス 3: ファイル 592 へのアクセス - レイテンシ: 142.245ms
アクセス 4: ファイル 456 へのアクセス - レイテンシ: 147.629ms
アクセス 5: ファイル 16 へのアクセス - レイテンシ: 96.0531ms
アクセス 6: ファイル 810 へのアクセス - レイテンシ: 68.6514ms
アクセス 7: ファイル 740 へのアクセス - レイテンシ: 158.726ms
アクセス 8: ファイル 525 へのアクセス - レイテンシ: 121.758ms
アクセス 9: ファイル 983 へのアクセス - レイテンシ: 91.0139ms
アクセス 10: ファイル 477 へのアクセス - レイテンシ: 125.798ms
アクセス 11: ファイル 375 へのアクセス - レイテンシ: 154.5ms
アクセス 12: ファイル 674 へのアクセス - レイテンシ: 142.769ms
アクセス 13: ファイル 87 へのアクセス - レイテンシ: 145.063ms
アクセス 14: ファイル 617 へのアクセス - レイテンシ: 169.611ms
アクセス 15: ファイル 151 へのアクセス - レイテンシ: 143.355ms
アクセス 16: ファイル 510 へのアクセス - レイテンシ: 142.328ms
アクセス 17: ファイル 962 へのアクセス - レイテンシ: 78.6412ms
アクセス 18: ファイル 893 へのアクセス - レイテンシ: 86.5443ms
アクセス 19: ファイル 756 へのアクセス - レイテンシ: 85.1219ms
アクセス 20: ファイル 932 へのアクセス - レイテンシ: 73.2789ms
アクセス 21: ファイル 281 へのアクセス - レイテンシ: 93.0593ms
アクセス 22: ファイル 567 へのアクセス - レイテンシ: 99.5636ms
アクセス 23: ファイル 624 へのアクセス - レイテンシ: 95.2957ms
アクセス 24: ファイル 416 へのアクセス - レイテンシ: 91.9499ms
アクセス 25: ファイル 287 へのアクセス - レイテンシ: 86.0386ms
アクセス 26: ファイル 653 へのアクセス - レイテンシ: 93.7693ms
アクセス 27: ファイル 52 へのアクセス - レイテンシ: 81.0363ms
アクセス 28: ファイル 3 へのアクセス - レイテンシ: 99.3664ms
アクセス 29: ファイル 449 へのアクセス - レイテンシ: 197.423ms
アクセス 30: ファイル 563 へのアクセス - レイテンシ: 99.8287ms
アクセス 31: ファイル 928 へのアクセス - レイテンシ: 79.1762ms
アクセス 32: ファイル 336 へのアクセス - レイテンシ: 163.173ms
アクセス 33: ファイル 121 へのアクセス - レイテンシ: 148.117ms
アクセス 34: ファイル 335 へのアクセス - レイテンシ: 76.8495ms
アクセス 35: ファイル 546 へのアクセス - レイテンシ: 78.1507ms
アクセス 36: ファイル 47 へのアクセス - レイテンシ: 82.0751ms
アクセス 37: ファイル 382 へのアクセス - レイテンシ: 159.592ms
アクセス 38: ファイル 212 へのアクセス - レイテンシ: 89.1237ms
アクセス 39: ファイル 410 へのアクセス - レイテンシ: 101.583ms
アクセス 40: ファイル 677 へのアクセス - レイテンシ: 82.3653ms
アクセス 41: ファイル 478 へのアクセス - レイテンシ: 74.352ms
アクセス 42: ファイル 317 へのアクセス - レイテンシ: 200.646ms
アクセス 43: ファイル 113 へのアクセス - レイテンシ: 111.207ms
アクセス 44: ファイル 279 へのアクセス - レイテンシ: 109.1ms
アクセス 45: ファイル 504 へのアクセス - レイテンシ: 139.973ms
アクセス 46: ファイル 667 へのアクセス - レイテンシ: 214.165ms
アクセス 47: ファイル 395 へのアクセス - レイテンシ: 85.5997ms
アクセス 48: ファイル 297 へのアクセス - レイテンシ: 93.3096ms
アクセス 49: ファイル 42 へのアクセス - レイテンシ: 91.3599ms
アクセス 50: ファイル 485 へのアクセス - レイテンシ: 85.5525ms
アクセス 51: ファイル 882 へのアクセス - レイテンシ: 4.39811ms
アクセス 52: ファイル 388 へのアクセス - レイテンシ: 95.6607ms
アクセス 53: ファイル 558 へのアクセス - レイテンシ: 90.6656ms
アクセス 54: ファイル 128 へのアクセス - レイテンシ: 191.483ms
アクセス 55: ファイル 699 へのアクセス - レイテンシ: 163.474ms
アクセス 56: ファイル 466 へのアクセス - レイテンシ: 89.0267ms
アクセス 57: ファイル 600 へのアクセス - レイテンシ: 85.4249ms
アクセス 58: ファイル 853 へのアクセス - レイテンシ: 87.6071ms
アクセス 59: ファイル 14 へのアクセス - レイテンシ: 100.882ms
アクセス 60: ファイル 271 へのアクセス - レイテンシ: 91.4915ms
アクセス 61: ファイル 335 へのアクセス - レイテンシ: 4.13966ms
アクセス 62: ファイル 148 へのアクセス - レイテンシ: 91.4402ms
アクセス 63: ファイル 869 へのアクセス - レイテンシ: 68.2695ms
アクセス 64: ファイル 376 へのアクセス - レイテンシ: 75.3615ms
アクセス 65: ファイル 320 へのアクセス - レイテンシ: 75.6366ms
アクセス 66: ファイル 37 へのアクセス - レイテンシ: 84.1513ms
アクセス 67: ファイル 98 へのアクセス - レイテンシ: 78.6898ms
アクセス 68: ファイル 470 へのアクセス - レイテンシ: 87.1696ms
アクセス 69: ファイル 144 へのアクセス - レイテンシ: 79.5217ms
アクセス 70: ファイル 640 へのアクセス - レイテンシ: 129.472ms
アクセス 71: ファイル 925 へのアクセス - レイテンシ: 57.8165ms
アクセス 72: ファイル 302 へのアクセス - レイテンシ: 74.2681ms
アクセス 73: ファイル 754 へのアクセス - レイテンシ: 4.74215ms
アクセス 74: ファイル 656 へのアクセス - レイテンシ: 83.7891ms
アクセス 75: ファイル 428 へのアクセス - レイテンシ: 155.936ms
アクセス 76: ファイル 168 へのアクセス - レイテンシ: 4.03762ms
アクセス 77: ファイル 919 へのアクセス - レイテンシ: 64.5759ms
アクセス 78: ファイル 545 へのアクセス - レイテンシ: 63.8487ms
アクセス 79: ファイル 456 へのアクセス - レイテンシ: 3.74055ms
アクセス 80: ファイル 698 へのアクセス - レイテンシ: 81.5885ms
アクセス 81: ファイル 194 へのアクセス - レイテンシ: 104.636ms
アクセス 82: ファイル 742 へのアクセス - レイテンシ: 102.301ms
アクセス 83: ファイル 681 へのアクセス - レイテンシ: 96.6165ms
アクセス 84: ファイル 517 へのアクセス - レイテンシ: 82.8376ms
アクセス 85: ファイル 266 へのアクセス - レイテンシ: 97.4438ms
アクセス 86: ファイル 798 へのアクセス - レイテンシ: 93.2667ms
アクセス 87: ファイル 548 へのアクセス - レイテンシ: 93.3309ms
アクセス 88: ファイル 491 へのアクセス - レイテンシ: 163.823ms
アクセス 89: ファイル 721 へのアクセス - レイテンシ: 176.047ms
アクセス 90: ファイル 913 へのアクセス - レイテンシ: 66.4966ms
アクセス 91: ファイル 323 へのアクセス - レイテンシ: 96.7705ms
アクセス 92: ファイル 155 へのアクセス - レイテンシ: 115.716ms
アクセス 93: ファイル 47 へのアクセス - レイテンシ: 5.07188ms
アクセス 94: ファイル 733 へのアクセス - レイテンシ: 101.688ms
アクセス 95: ファイル 503 へのアクセス - レイテンシ: 96.1304ms
アクセス 96: ファイル 940 へのアクセス - レイテンシ: 61.2617ms
アクセス 97: ファイル 723 へのアクセス - レイテンシ: 100.105ms
アクセス 98: ファイル 531 へのアクセス - レイテンシ: 79.3641ms
アクセス 99: ファイル 650 へのアクセス - レイテンシ: 80.8163ms
アクセス 100: ファイル 878 へのアクセス - レイテンシ: 80.2617ms
計測完了。結果は latency_results.csv に保存されました。
統計情報:
平均レイテンシ: 100.418 ms
最小レイテンシ: 3.74055 ms
最大レイテンシ: 200.646 ms

では「ボリューム初期化レート」を設定してみます。
利用したスナップショットですが、/mount/ebs に配置されているファイルの合計を確認すると 1GB 程度です。

# df
Filesystem     1K-blocks     Used Available Use% Mounted on
overlay         30787492 12741040  16457204  44% /
tmpfs              65536        0     65536   0% /dev
shm             16193732        0  16193732   0% /dev/shm
tmpfs           16193732        0  16193732   0% /sys/fs/cgroup
/dev/nvme2n1   103020228  1028184 101992044   1% /mount/ebs
/dev/nvme1n1    30787492 12741040  16457204  44% /etc/hosts
/dev/nvme0n1p1   5082764  2157544   2856428  44% /managed-agents/execute-command
tmpfs           16193732        0  16193732   0% /proc/acpi
tmpfs           16193732        0  16193732   0% /sys/firmware

つまり、300MiB に設定すれば 3~4 秒くらいで初期化し終わる計算になります。
ということは、コンテナに乗り込んで、ディレクトリを変えて、コマンド打とうとしている間に終わるってこと??

ecs-ebs-rate.png

ということで、作成直後に乗り込んでスクリプトを実行してみることにします。
サービスの更新を行い、タスクが「実行中」に変わったタイミングで、コンテナ内に ECS Exec で乗り込んでスクリプトを実行してみました。

ecs-ebs-wait.png

結果、平均レイテンシは 3.75489 ms になりました!
上手く「ボリューム初期化レート」が効いてそうです。

# ./measure_latency_no_bc.sh
アクセス 1: ファイル 727 へのアクセス - レイテンシ: 5.1477ms
アクセス 2: ファイル 463 へのアクセス - レイテンシ: 4.18639ms
アクセス 3: ファイル 173 へのアクセス - レイテンシ: 3.75462ms
アクセス 4: ファイル 275 へのアクセス - レイテンシ: 4.11797ms
アクセス 5: ファイル 8 へのアクセス - レイテンシ: 4.38547ms
アクセス 6: ファイル 179 へのアクセス - レイテンシ: 3.77464ms
アクセス 7: ファイル 305 へのアクセス - レイテンシ: 3.83592ms
アクセス 8: ファイル 376 へのアクセス - レイテンシ: 3.9835ms
アクセス 9: ファイル 832 へのアクセス - レイテンシ: 3.5131ms
アクセス 10: ファイル 494 へのアクセス - レイテンシ: 4.53568ms
アクセス 11: ファイル 36 へのアクセス - レイテンシ: 3.72648ms
アクセス 12: ファイル 210 へのアクセス - レイテンシ: 4.10628ms
アクセス 13: ファイル 76 へのアクセス - レイテンシ: 3.78227ms
アクセス 14: ファイル 139 へのアクセス - レイテンシ: 3.6521ms
アクセス 15: ファイル 790 へのアクセス - レイテンシ: 3.66998ms
アクセス 16: ファイル 497 へのアクセス - レイテンシ: 3.51167ms
アクセス 17: ファイル 596 へのアクセス - レイテンシ: 4.01497ms
アクセス 18: ファイル 522 へのアクセス - レイテンシ: 3.58605ms
アクセス 19: ファイル 438 へのアクセス - レイテンシ: 3.6869ms
アクセス 20: ファイル 47 へのアクセス - レイテンシ: 3.66378ms
アクセス 21: ファイル 453 へのアクセス - レイテンシ: 3.64351ms
アクセス 22: ファイル 747 へのアクセス - レイテンシ: 3.70002ms
アクセス 23: ファイル 263 へのアクセス - レイテンシ: 3.67403ms
アクセス 24: ファイル 658 へのアクセス - レイテンシ: 3.92485ms
アクセス 25: ファイル 645 へのアクセス - レイテンシ: 3.82447ms
アクセス 26: ファイル 847 へのアクセス - レイテンシ: 3.62968ms
アクセス 27: ファイル 943 へのアクセス - レイテンシ: 3.86906ms
アクセス 28: ファイル 639 へのアクセス - レイテンシ: 3.88789ms
アクセス 29: ファイル 459 へのアクセス - レイテンシ: 4.28987ms
アクセス 30: ファイル 181 へのアクセス - レイテンシ: 3.58367ms
アクセス 31: ファイル 174 へのアクセス - レイテンシ: 3.81517ms
アクセス 32: ファイル 837 へのアクセス - レイテンシ: 3.90863ms
アクセス 33: ファイル 846 へのアクセス - レイテンシ: 3.7837ms
アクセス 34: ファイル 78 へのアクセス - レイテンシ: 3.73673ms
アクセス 35: ファイル 501 へのアクセス - レイテンシ: 3.69287ms
アクセス 36: ファイル 835 へのアクセス - レイテンシ: 3.68643ms
アクセス 37: ファイル 35 へのアクセス - レイテンシ: 3.60584ms
アクセス 38: ファイル 960 へのアクセス - レイテンシ: 4.11558ms
アクセス 39: ファイル 315 へのアクセス - レイテンシ: 3.76368ms
アクセス 40: ファイル 869 へのアクセス - レイテンシ: 4.02927ms
アクセス 41: ファイル 370 へのアクセス - レイテンシ: 3.78394ms
アクセス 42: ファイル 135 へのアクセス - レイテンシ: 3.58367ms
アクセス 43: ファイル 557 へのアクセス - レイテンシ: 3.70312ms
アクセス 44: ファイル 619 へのアクセス - レイテンシ: 3.45182ms
アクセス 45: ファイル 338 へのアクセス - レイテンシ: 3.65949ms
アクセス 46: ファイル 838 へのアクセス - レイテンシ: 3.58415ms
アクセス 47: ファイル 690 へのアクセス - レイテンシ: 3.82137ms
アクセス 48: ファイル 569 へのアクセス - レイテンシ: 3.55315ms
アクセス 49: ファイル 723 へのアクセス - レイテンシ: 3.67999ms
アクセス 50: ファイル 589 へのアクセス - レイテンシ: 4.20427ms
アクセス 51: ファイル 441 へのアクセス - レイテンシ: 3.6478ms
アクセス 52: ファイル 740 へのアクセス - レイテンシ: 4.47011ms
アクセス 53: ファイル 411 へのアクセス - レイテンシ: 3.8197ms
アクセス 54: ファイル 373 へのアクセス - レイテンシ: 3.62015ms
アクセス 55: ファイル 6 へのアクセス - レイテンシ: 3.52192ms
アクセス 56: ファイル 189 へのアクセス - レイテンシ: 3.61967ms
アクセス 57: ファイル 911 へのアクセス - レイテンシ: 3.66735ms
アクセス 58: ファイル 17 へのアクセス - レイテンシ: 3.54314ms
アクセス 59: ファイル 701 へのアクセス - レイテンシ: 3.45993ms
アクセス 60: ファイル 918 へのアクセス - レイテンシ: 3.91483ms
アクセス 61: ファイル 605 へのアクセス - レイテンシ: 3.77417ms
アクセス 62: ファイル 754 へのアクセス - レイテンシ: 3.66688ms
アクセス 63: ファイル 115 へのアクセス - レイテンシ: 3.60847ms
アクセス 64: ファイル 227 へのアクセス - レイテンシ: 3.83115ms
アクセス 65: ファイル 446 へのアクセス - レイテンシ: 3.443ms
アクセス 66: ファイル 710 へのアクセス - レイテンシ: 3.582ms
アクセス 67: ファイル 262 へのアクセス - レイテンシ: 3.62706ms
アクセス 68: ファイル 404 へのアクセス - レイテンシ: 3.55172ms
アクセス 69: ファイル 26 へのアクセス - レイテンシ: 3.63255ms
アクセス 70: ファイル 708 へのアクセス - レイテンシ: 3.73816ms
アクセス 71: ファイル 576 へのアクセス - レイテンシ: 4.2274ms
アクセス 72: ファイル 535 へのアクセス - レイテンシ: 3.7055ms
アクセス 73: ファイル 143 へのアクセス - レイテンシ: 3.5193ms
アクセス 74: ファイル 956 へのアクセス - レイテンシ: 3.72863ms
アクセス 75: ファイル 396 へのアクセス - レイテンシ: 3.5007ms
アクセス 76: ファイル 467 へのアクセス - レイテンシ: 3.76725ms
アクセス 77: ファイル 423 へのアクセス - レイテンシ: 3.55625ms
アクセス 78: ファイル 877 へのアクセス - レイテンシ: 3.56674ms
アクセス 79: ファイル 307 へのアクセス - レイテンシ: 3.61657ms
アクセス 80: ファイル 752 へのアクセス - レイテンシ: 3.73888ms
アクセス 81: ファイル 657 へのアクセス - レイテンシ: 3.64733ms
アクセス 82: ファイル 105 へのアクセス - レイテンシ: 3.42512ms
アクセス 83: ファイル 771 へのアクセス - レイテンシ: 3.48735ms
アクセス 84: ファイル 605 へのアクセス - レイテンシ: 3.05939ms
アクセス 85: ファイル 399 へのアクセス - レイテンシ: 3.57103ms
アクセス 86: ファイル 257 へのアクセス - レイテンシ: 4.33064ms
アクセス 87: ファイル 644 へのアクセス - レイテンシ: 3.60298ms
アクセス 88: ファイル 398 へのアクセス - レイテンシ: 3.48592ms
アクセス 89: ファイル 518 へのアクセス - レイテンシ: 3.65973ms
アクセス 90: ファイル 897 へのアクセス - レイテンシ: 3.67379ms
アクセス 91: ファイル 591 へのアクセス - レイテンシ: 4.09651ms
アクセス 92: ファイル 59 へのアクセス - レイテンシ: 3.62849ms
アクセス 93: ファイル 908 へのアクセス - レイテンシ: 3.59631ms
アクセス 94: ファイル 300 へのアクセス - レイテンシ: 3.64041ms
アクセス 95: ファイル 647 へのアクセス - レイテンシ: 3.49879ms
アクセス 96: ファイル 782 へのアクセス - レイテンシ: 3.62468ms
アクセス 97: ファイル 910 へのアクセス - レイテンシ: 3.82996ms
アクセス 98: ファイル 266 へのアクセス - レイテンシ: 3.51834ms
アクセス 99: ファイル 34 へのアクセス - レイテンシ: 4.04286ms
アクセス 100: ファイル 320 へのアクセス - レイテンシ: 3.57676ms
計測完了。結果は latency_results.csv に保存されました。
統計情報:
平均レイテンシ: 3.75489 ms
最小レイテンシ: 3.05939 ms
最大レイテンシ: 4.53568 ms

最後に

精度は怪しいですが、「ボリューム初期化レート」が上手く効いていそうなことを確かめられました。
いや、本当はちゃんと EventBridge で初期化完了を拾って計測しようとしたんですよ。

{
  "source": ["aws.ec2"],
  "detail-type": ["EBS Volume Notification"],
  "detail": {
    "event": ["initializeVolume"]
  }
}

こんな感じで拾えました。

{
  "version": "0",
  "id": "7916b40b-7ddb-3b18-ee99-ae5a999a5530",
  "detail-type": "EBS Volume Notification",
  "source": "aws.ec2",
  "account": "xxxxxxxxxxxx",
  "time": "2025-05-14T14:51:16Z",
  "region": "ap-northeast-1",
  "resources": [
    "arn:aws:ec2:ap-northeast-1:xxxxxxxxxxxx:volume/vol-0b3b7467faf081a91"
  ],
  "detail": {
    "result": "succeeded",
    "cause": "",
    "event": "initializeVolume",
    "request-id": "c8df06b2-e03f-4174-ba74-3fe8194f19e4"
  }
}

ただし、イベント発行までラグがありそうで、上手く計測できなかったので諦めました。
タスク完了から、Event を拾えるまで 4 分くらいかかるような計算になってたので、今回の(雑な?)検証に至りました。
検証における細かい所は置いておいて、ECS に EBS をアタッチして、多数のファイルにアクセスする際は非常に有用な機能だと思います。
是非試してみて下さい!

Share this article

facebook logohatena logotwitter logo

© Classmethod, Inc. All rights reserved.