ターゲット追跡スケーリングポリシーを使ってAmazon SQSキューのメッセージ数でAmazon ECSタスクをオートスケーリングしてみた

ターゲット追跡スケーリングポリシーを使ってAmazon SQSキューのメッセージ数でAmazon ECSタスクをオートスケーリングしてみた

Clock Icon2025.07.10

SQSメッセージ数に応じてECSタスクのオートスケーリング

スケーリングポリシー

ECSのスケーリングポリシーの内ターゲット追跡とステップスケーリングでは、任意のCloudWatchメトリクスをターゲットメトリクスとすることができます。

ターゲット追跡では、しきい値を維持するようにスケールイン・スケールアウトを自動的に行ってくれます。

一方ステップスケーリングでは、スケールイン・スケールアウトのタスク数をユーザー側で指定する必要があります。

設定の手間はかかりますが、柔軟な設定ができるため急激な負荷増大にも対応しやすいです。

今回のケースでは、ターゲット追跡では、「1タスクで何件処理したいかを設定する」だけで良いです。

一方ステップスケーリングでは、メッセージ数ごとに設定が必要です。

例:

  • 0-5件/タスク: 何もしない
  • 5-15件/タスク: +1タスク
  • 15-25件/タスク: +3タスク
  • 25件/タスク超: +5タスク

設定がシンプルかつ直感的にできるため、ターゲット追跡を選択します。

ターゲットメトリクス

ターゲットメトリクスにSQSメッセージ数を指定することで、メッセージ数に応じてECSのタスク数を増やすことができます。

CloudWatch Amazon SQSメトリクスのApproximateNumberOfMessagesVisibleでメッセージ数を取得できます。

しかし、直接SQSメッセージ数を使用すると、現在のタスク数を考慮しない判断となります。

例: 閾値50件、現在60件の場合

  • 2タスク稼働中 → 30件/タスク(スケールアウト必要)
  • 10タスク稼働中 → 6件/タスク(スケールアウト不要)

同じメッセージ数でも、適切な判断ができません。

1タスクあたりのメッセージ数(メッセージ数 / タスク数)をしきい値とすることで、比率ベースでのスケーリングが可能です。

目標値10件/タスクの場合:

  • 60件、2タスク → 30件/タスク → スケールアウト
  • 60件、10タスク → 6件/タスク → スケールイン

EC2ベースの記事になりますが、もっと詳しく知りたい場合は以下が参考になると思います。

Scaling policy based on Amazon SQS - Amazon EC2 Auto Scaling

構成

SQS ECSオートスケーリング.png

以下のブログとほぼ同じ構成です。

カスタムメトリクスを用いた Amazon Elastic Container Service (ECS) のオートスケーリング | Amazon Web Services ブログ

異なる部分はタスクあたりのバックログの計算をLambdaではなく、CloudWatch Metric Mathを使っている点です。

やってみた

リソースのデプロイ

リソースはTerraformで作成しました。

1タスクあたり10件のメッセージ処理を目標に、ターゲット追跡のしきい値を10としました。

10メッセージ/1タスクを超えたら、スケールアウトします。最大タスク数は5タスクとしました。

autoscaling.tf
resource "aws_appautoscaling_target" "ecs_target" {
  max_capacity       = 5
  min_capacity       = 1
  resource_id        = "service/${aws_ecs_cluster.main.name}/${aws_ecs_service.main.name}"
  scalable_dimension = "ecs:service:DesiredCount"
  service_namespace  = "ecs"

  depends_on = [aws_ecs_service.main]
}

# ECS Target Tracking Policy
resource "aws_appautoscaling_policy" "ecs" {
  name               = "${local.prefix}-target-tracking"
  policy_type        = "TargetTrackingScaling"
  resource_id        = aws_appautoscaling_target.ecs_target.resource_id
  scalable_dimension = aws_appautoscaling_target.ecs_target.scalable_dimension
  service_namespace  = aws_appautoscaling_target.ecs_target.service_namespace
  target_tracking_scaling_policy_configuration {
    target_value       = 5.0
    scale_out_cooldown = 60
    scale_in_cooldown  = 120

    customized_metric_specification {
      metrics {
        label = "Get the queue size (the number of messages waiting to be processed)"
        id    = "m1"

        metric_stat {
          metric {
            metric_name = "ApproximateNumberOfMessagesVisible"
            namespace   = "AWS/SQS"

            dimensions {
              name  = "QueueName"
              value = aws_sqs_queue.task_queue.name
            }
          }

          stat = "Sum"
        }

        return_data = false
      }

      metrics {
        label = "Get the ECS running task count (the number of currently running tasks)"
        id    = "m2"

        metric_stat {
          metric {
            metric_name = "RunningTaskCount"
            namespace   = "ECS/ContainerInsights"

            dimensions {
              name  = "ClusterName"
              value = aws_ecs_cluster.main.name
            }

            dimensions {
              name  = "ServiceName"
              value = aws_ecs_service.main.name
            }
          }

          stat = "Average"
        }

        return_data = false
      }

      metrics {
        label       = "Calculate the backlog per instance"
        id          = "e1"
        expression  = "m1 / m2"
        return_data = true
      }
    }
  }
}

コードの全量は以下から確認できます。

terraform-sample/sqs-ecs-autoscaling at main · msato0731/terraform-sample · GitHub

Terraformを実行してリソースを作成します。

terraform init
terraform plan
terraform apply

設定確認

ECSのAuto Scaling設定は以下です。

Cursor_と_サービスの自動スケーリングを表示___Elastic_Container_Service___ap-northeast-1.png

スケールイン・スケールアウト 2つのCloudWatch アラームが自動的に作成されました。

メトリクスにはCloudWatch Metric Mathで、SQSメッセージ数/ECSタスク数をした値が設定されています。

アラーム___CloudWatch___ap-northeast-1.png

動作確認

実際にスケールアウトを確認してみます。

SQSにてメッセージ送信します。テスト用に50件程度送信します。

メッセージを送受信___Simple_Queue_Service___ap-northeast-1.png

スケールアウトアラームをみるとステータスがAlarmに変わり、AutoScalingアクションが実行されました。

TargetTracking-service_sqs-ecs-autoscaling-cluster_sqs-ecs-autoscaling-service-AlarmHigh-f1bf0930-5a84-4949-9ef3-1de34b6a2307___アラーム___CloudWatch___ap-northeast-1.png

ECSサービスのイベントからもAuto Scalingが開始されたことを確認できました。

サービスイベント___Elastic_Container_Service___ap-northeast-1.png

タスク数も5個になっていました。

サービスタスク___Elastic_Container_Service___ap-northeast-1.png

最後にスケールインを確認します。

SQSのメッセージを削除します。メッセージ数を0にします。

メッセージを送受信___Simple_Queue_Service___ap-northeast-1.png

15分程度待つと、スケールイン用のCloudWatchアラームがAlarm状態になり、Auto Scalingアクションが行われました。

TargetTracking-service_sqs-ecs-autoscaling-cluster_sqs-ecs-autoscaling-service-AlarmLow-2d1640f8-b9d3-47f9-9da1-4052920b3ab0___アラーム___CloudWatch___ap-northeast-1.png

1タスクずつスケールインが行われ、9分程度で1タスクになりました。

サービスイベント___Elastic_Container_Service___ap-northeast-1.png

おわりに

SQSメッセージ数に応じて、ECS Fargateをターゲット追跡スケーリングポリシーでオートスケーリングしてみました。

マネジメントコンソール上では、ターゲット追跡スケーリングのメトリクスタイプが以下から選ぶ形になり任意のメトリクスを渡すことができません。

  • ECSServiceAverageCPUUtilization
  • ECSServiceAverageMemoryUtilization
  • ALBRequestCountPerTarget

サービスの自動スケーリングを管理___Elastic_Container_Service___ap-northeast-1.png

Application Auto ScalingのAPIは任意のメトリクスに対応しています。

PutScalingPolicy - Application Auto Scaling

そのためAWS CLIやTerraform上からは、任意のメトリクスをターゲットメトリクスにすることができます。

参考

Share this article

facebook logohatena logotwitter logo

© Classmethod, Inc. All rights reserved.