AWS JAPAN APN ブログ

【APN Ambassadors ブログシリーズ第二弾】AWS Batch にてスポットインスタンスを適用してコストを最適化する

パートナーソリューションアーキテクトの大林です。
本記事は、「Japan APN Ambassador」 の方々に、AWS JAPAN APN ブログ にて技術情報をお届けいただく【APN Ambassadors ブログシリーズ】の第二弾となります。今回は、APN Ambassador であるアイレット株式会社 廣山 豊様より、寄稿いただきました。
本記事は、2020 年 8 月 14 日時点の内容となります。最新の情報につきましては、AWS 公式ドキュメントを参照ください。

======================================================================================

アイレットは、クラウドの導入設計から構築・運用・監視保守までを行う「cloudpack」というマネージドサービスを提供しています。 MSP 開発セクションでは、この「cloudpack」の根幹でもある MSP 業務のクオリティを高めていくためにさまざまな業務の改善や自動化に向けた開発やサービス提供をおこなっており、そのひとつに Resource Visualizer というサービスがあります。

現在、社内各プロジェクトへの導入が順調に増加しており、それにともない Resource Visualizer の稼働にかかる費用の大部分を占めるインスタンス料金も増加しています。最近では、オンデマンドインスタンスの価格で計算すると、半年で 2 倍近くに増加しました。そこで、コスト削減の一環としてスポットインスタンスを導入することになりました。

Resource Visualizerについて

Resource Visualizer は設定ファイルへ登録されたプロジェクトごとに AWS アカウントからリソース情報を取得し、Backlog の wiki に管理表を出力する構成管理ツールです。構成の概要は以下のとおりで、AWS Batch を活用しています。

平日の深夜 0 時に自動実行し、現在約 300 プロジェクトのリソース情報を取得・更新しているのですが、この処理には以下のような特徴があります。

  • 自動実行全体は 1 時間弱で完了する。翌朝までにすべての更新が完了していれば十分なので、時間制限に余裕がある
  • 1 ジョブ(= 1 プロジェクト)あたりの処理時間は 5 分以下がほとんどで、長くても 30 分未満
  • ジョブに冪等性がある(何度実行しても問題ない、中断してもリトライするだけでよい)

このシステムにスポットインスタンスを導入していきます。

スポットインスタンスの特徴的な事象に対する対応

まずはスポットインスタンスを導入することで発生しうる特徴的な以下の状況について、対応を考えたいと思います。

  • インスタンスが中断した場合
  • スポットプールの空キャパシティがなくなり、インスタンスを起動できない場合

インスタンスが中断した場合

92% のスポットインスタンスがユーザーにより終了されているとはいえ、8% は Amazon EC2 による中断が発生するということなので対応は必須です。

(参考:Amazon EC2 Auto Scaling によるスポットインスタンス活用講座

通常ならば中断の 2 分前に通知を Amazon EventBridge 等で受けとり、そこから中断処理を行うということになります。

しかし、Resource Visualizer は処理の特徴でも挙げたように1ジョブの処理時間が短く、冪等性があるため、AWS Batch のジョブの再試行の自動化を利用して「中断が発生した場合はジョブをはじめからやり直す」という対応にしました。この方法ならば中断処理はとくに不要です。

最後の再試行時にもインスタンスが中断された場合は、Slack に通知をするようにしています。

インスタンスを起動できない場合の対応

インスタンスが起動できない場合、ジョブは無期限に RUNNABLE ステータスのまま滞留する可能性があります。

(参考:AWS Batch ジョブ が RUNNABLE ステータスで止まっているのはなぜですか?

これを解消するためにスポット用のジョブキューとオンデマンド用のジョブキューを作成して対応することにしました。

まずはスポット用ジョブキューにジョブを投入します。そして、一定時間後に AWS Lambda を実行し、その時点で RUNNABLE のまま滞留しているジョブをすべてオンデマンド用ジョブキューに再投入します。最後に、スポット用ジョブキューに滞留しているジョブをキャンセルします。

Resource Visualizer は時間制限に余裕があるため、できるだけスポットプールの空キャパシティを待つようなかたちにしました。

このように複数ジョブキューを用意する以外にも AWS Batch ではジョブキューに複数のコンピューティング環境を設定できるため、コンピューティング環境1にスポット用環境を、2にオンデマンド用環境を設定して対応するということも可能です。

(参考:[AWS Black Belt Online Seminar] AWS Batch 資料及び QA 公開

各種設定

次に設定を行っていきます。先に今回設定する最終的な AWS Batch まわりの構成を示しておきます。

この構成のために行った主な設定は以下のとおりです。

  1. ジョブ投入時に再試行回数を指定する
  2. 起動テンプレートを作成する
  3. コンピューティング環境を作成する(スポット用)
  4. ジョブキューを作成する(スポット用)
  5. リソースが確保できない場合の対応のために AWS Lambda を作成する

Resource Visualizer はオンデマンド用のコンピューティング環境やジョブキューをすでに利用しているため、それらはそのまま残しておき、そこにスポット用の設定を追加していくようなかたちで進めました。

この中でポイントととなる1、2、3について紹介します。

1. ジョブ投入時に再試行回数を設定する

中断が発生した際に自動で再実行するために必要な設定です。

Resource Visualizer では AWS Lambda でジョブを投入しているため、該当箇所に下記のパラメータを追加しました。

retryStrategy={
    'attempts': 5
}

2. 起動テンプレートを作成する

中断通知を受け取った際に、インスタンスがそれ以降あらたなジョブを引き受けないようにするなどのために Amazon ECS コンテナインスタンスの状態を DRAINING に変更する必要があります。そこで、コンピューティング環境を作成するときに指定できる Amazon EC2 の起動テンプレートを利用して Amazon ECS のスポットインスタンス自動ドレインを有効にしておきます。

Amazon EC2 のコンソール画面で起動テンプレートを新規作成し、ユーザーデータに以下の内容を設定しました。

Content-Type: multipart/mixed; boundary="==BOUNDARY=="
MIME-Version: 1.0

--==BOUNDARY==
Content-Type: text/x-shellscript; charset="us-ascii"

#!/bin/bash
echo ECS_ENABLE_SPOT_INSTANCE_DRAINING=true>>/etc/ecs/ecs.config
--==BOUNDARY==

(参考:Amazon EC2 ユーザーデータを使用してコンテナインスタンスをブートストラップする

3. コンピューティング環境を作成する

「Containers + EC2 Spot: AWS Batch による大規模バッチ処理でのスポットインスタンス活用 」の資料にならい、できるだけスポットプールを幅広く分散し、リソースを確保しやすいように設定しました。

  • 最大料金:100%スポットインスタンスの料金はオンデマンドインスタンス料金の 90% を超えることはないため、価格変動による中断リスクを下げることができます。(参考:Amazon EC2 スポットインスタンスの例 概要
  • 許可されたインスタンスタイプ:optimalC4、M4、R4ファミリーから適切なインスタンスタイプが選択されるため、幅広い選択肢を持つことができます。
  • 配分戦略:SPOTCAPACITYOPTIMIZED中断される可能性が低いインスタンスタイプが優先されます。
  • 起動テンプレート:「2. 起動テンプレートを作成する」で作成した起動テンプレート
  • サブネット:複数の AZ が含まれるように選択複数の AZ を選択することでスポットプールがふえ、中断のリスクを分散できます。

実行結果

スポットインスタンスの環境で行われた自動実行 1 回分の結果を確認します。

Amazon EC2 コンソールの [スポットリクエスト] セクションにある [削減の概要] を確認してみると $6.60、オンデマンドと比較して 74% もインスタンス料金を削減できているようです。

ただ、実際には各インスタンスの起動時間は 1 時間未満なのでこの金額とは異なるはずです。そこで CostExplorer で費用を確認すると、なんと $1.47 でした。スポットインスタンス導入前のインスタンス費用は $110/月 ほどかかっていましたが、Resource Visualizer が実行されるのは平日深夜のみ、月間の平日数を 21 日とすると、スポットインスタンス導入後は $1.47 * 21 日 = $30.87/月約 72% も削減できることになります。

しかし、起動したインスタンス数を見てみると 180 もあり、単純計算ですが起動したインスタンスのうち 1/3 程度は 1 つのジョブしか実行しておらず、若干インスタンスを持て余している状態に見えます。ジョブ終了後からインスタンスが終了されるまでの待機時間のコストがムダに嵩んでいるかもしれません。

そこで、最大 vCPU をゆとりをもたせて設定している 512 から実際に使用された vCPU 数よりも少ない 256 まで下げて実行してみます。自動実行が完了するまでの全体的な時間は増加する可能性がありますが、Resource Visualizer は時間制限に余裕があるため問題ありません。

その結果がこちらです。スポット合計を見てみると $6.60 から $4.64 まで削減されました。

AWS Cost Explorer で費用を確認すると$1.23 で、僅かではありますがムダを省けたようです。全体の実行時間の増加も 2、3 分ほどにおさまりました。

実行回数が少ないため振れ幅を加味して 1 回あたり $1.3 になったとしても $27.3/月、スポットインスタンス導入前の月額と比較すると約 75% 削減できることになります。年間の平日数を 260 日とすると、年間で $982 のコストダウンに成功しました。

まとめ

AWS Batch で稼働しているシステムへスポットインスタンスを導入し、コスト削減を行いました。Resource Visualizer は処理時間が短い、冪等性があるといった特徴を持っていたことでスポットインスタンスとの相性がよく、プログラムの改修をせずに導入することができました。 冪等性は、AWS Lambda のようなサーバーレスシステムにも重要になってきます。

スポットインスタンスは、冪等性をもったシステムや、ステートレスなシステムにおいて、大幅なシステムの変更を必要とせずに導入できる可能性が高いです。 今回は必要としませんでしたが、適宜、チェックポイントを設け、処理を再開できるようにすることで、処理時間が長いシステムへの導入も可能です。

スポットインスタンスを活用することで、大幅なコストカットが実現可能です。 インスタンスタイプによっては、より大きな削減率になることもあります。スポットインスタンスは古くからありますが、徐々に使いやすくアップデートされています。今一度、見直してみてはいかがでしょうか?

======================================================================================

以上が、APN Ambassador であるアイレット株式会社 廣山 豊様より、寄稿いただいた内容となります。廣山様、ありがとうございました!第三弾もご期待いただければと思います。