Amazon ECSのCloudWatchメトリクスとAutoScaling戦略
Amazon EC2 Container Service(以下ECS)では他のAWSサービスと同様に、サービス状況のモニタリング/アラーム発砲のためのCloudWatchメトリクスが複数種類用意されています。ECSではどういったCloudWatchのメトリクスが利用可能かどうかを整理しました。
ECSの基礎知識
ECSのモデルについては私が以前書いたブログを参照ください。
上記ブログで記載の通り、ECSではTaskDefinitionにどのくらいの量のCPUやメモリを確保しておくかを指定します。その前提でECSのCloudWatchメトリクスを学ぶ必要があります。
ECSのCloudWatchのDimensionには、「ClusterName」と「ServiceName」の2種類が存在します。それぞれに分けて見ていきましょう。
CPUReservation/MemoryReservation
Cluster内のECS TaskがTask Definitionで 予約(=確保)しているCPU Unitが、ECS Clusterが持っている合計のCPU Unitの何%を占めているのか を表したのがCPUReservationです。
MemoryReservationの考え方は上のCPU Reservationと全く同じです。 ECS Clusterが持っている合計のメモリのうち、何%をECS Taskが確保しているのかを表したのがMemoryReservationです。
CPUReservationおよびMemoryReservationは、Cluster Dimensionでのみ利用可能で、Service Dimensionでは利用できません。
CPUUtilization/MemoryUtilization
CPUUtilizationとMemoryUtilizationは、ClusterName DimensionとServiceName Dimensionのどちらでも利用可能です。
さて、CPUUtilizationとMemoryUtilizationが表しているものは名前から想像がつくと思います。それぞれ計算式が公式ドキュメントに記載されているので、ここではそのまま引用します。
- http://docs.aws.amazon.com/AmazonECS/latest/developerguide/cloudwatch-metrics.html#cluster_utilization
- http://docs.aws.amazon.com/AmazonECS/latest/developerguide/cloudwatch-metrics.html#service_utilization
(Total CPU units used by tasks in service) x 100 Service CPU utilization = ---------------------------------------------------------------------------- (Total CPU units reserved in task definition) x (number of tasks in service) (Total MiB of memory used by tasks in service) x 100 Service memory utilization = -------------------------------------------------------------------------------- (Total MiB of memory reserved in task definition) x (number of tasks in service) (Total MiB of memory used by tasks in cluster x 100) Cluster memory utilization = ------------------------------------------------------------------ (Total MiB of memory registered by container instances in cluster) (Total CPU units used by tasks in cluster) x 100 Cluster CPU utilization = -------------------------------------------------------------- (Total CPU units registered by container instances in cluster)
ServiceのCPU/MemoryUtilizationは、100%を越えることがある ことには注意が必要です。Dockerの仕組みとして、起動しているホストOS上に、別のコンテナによって確保されていないCPU/メモリ領域がある場合は、自分で確保しているCPU/メモリ量以上にリソースを利用することができるのです。
例えばCPUを2vCPUのEC2インスタンスをECS Cluster Instanceとして利用したとします。1vCPU = 1024CPU Unitとして計算されるのでそのEC2は2048CPU Unit持っていることになります。そのEC2上で512CPU Unitを確保したECS Taskを起動した場合、ホストOS上には 2048 - 512 = 1536(CPU Unit)
が確保されずに残っていることになります。 *1
このTaskの負荷が上がりCPUをたくさん使うようになった場合、自身で確保されている以上のCPUを使うことができます。例えばある時点で 実際に 消費されたCPU Unitが1024だった場合、CloudWatch上のService CPU Utilizationは上述の計算式に基づくと (1024 / 512 * 1) * 100 = 200(%)
となります。
以下のCloudWatchのグラフは実際のECS上のService CPUUtilizationの値です。ところどころ100%を越えているのが確認できます。
EC2のCloudWatchに慣れた方は、100%を超えたCPUUtilizationのMetricsを見てギョッとすることが多い印象です。Utilizationの値が100%を超えたからといってすぐに対応しなければならない問題、というわけではありません。しかし、恒常的に100%を超えているようであれば、CPUおよびMemoryの確保量を見直すのが無難でしょう。
これらのメトリクスをどう使うべき?
さて、これらのメトリクスをどのように活用していけばよいでしょうか。現在私が携わっているWEB API開発のプロジェクトでは以下の方針でCloudWatch Alarmを設定しています。
- CPUUtilization/MemoryUtilizationの値が、ある閾値を越えたとき : ECS Taskのスケールアウト
- CPUReservation/MemoryReservationの値が、ある閾値を越えたとき : ECS Cluster Instanceのスケールアウト
CPU/MemoryUtilizationは実際に消費されているリソースを表すものになるので、これが高まるということは負荷が向上していることを意味します。それをトリガーにECS Taskの数を増やすことで、全体の処理性能を高めることができます。
CPU/MemoryReservationが高まるということは、ホストOS(EC2)にコンテナを詰め込む量の限界が近い、ということです。この状態でTaskの負荷が高まった場合は、他のTaskに確保されていないリソースを活用することもできず、ECS Taskのスケールアウトも出来ない状態なのでこれ以上の処理性能向上が見込めない、手詰まりの状態です。それを避けるためにCPU/MemoryUtilizationをEC2 AutoScalingのScalingPolicyとして設定し、この値に応じてEC2インスタンスを増減させるのが望ましいでしょう。
まとめ
ECSのCloudWatch Metricsの考え方と、それを利用したAutoScaling戦略について私の意見をまとめてみました。
- CPU/MemoryReservationメトリクスでは、ECS Taskに確保されているリソースの状況を知ることができる。これをCluster InstanceのAutoScalingの条件として利用する。
- CPU/MemoryUtilizationメトリクスでは、ECS Taskが実際に利用したリソース量を知ることができる。Service単位のUtilizationメトリクスは100%を越えることがある。この値をECS TaskのAutoScalingの条件として利用する。
後半のAutoScaling戦略に関してはいろいろな意見があると思いますので、「私はこうしている!」という意見があればそれをコメントやSNSの投稿などで共有していただけると大変参考になります。