Auto Scalingでスポットインスタンスを活用しつつ可用性も確保する

よく訓練されたアップル信者、都元です。Auto Scalingと言うと、サーバ負荷に応じて自動的にサーバ台数を制御してくれる機能、という印象が強いと思います。まぁ実際にこのような使い方がベストではありますが、単に「(仮に一部のサーバが落ちたとしても、自動で追加起動して)一定数のサーバを維持したい」「手動による台数コントロールを楽にしたい」といった目的でもしばしば利用されます。

スポットインスタンス

それはそうと、皆さん、安いの好きですよね! 安いは正義。

EC2のインスタンスは大きく「オンデマンドインスタンス」「リザーブドインスタンス」「スポットインスタンス」の3種類に分かれます。ざっと一言で説明しますと、以下の通りです。

  • オンデマンドは普通に立ち上げたインスタンス
  • リザーブドインスタンスは「前払金を払って1年or3年間の継続的な利用を約束」することによって単価が安くなったインスタンス
  • スポットインスタンスは「確実に起動できることを保証せず、場合によっては起動中のサーバであっても強制的にTerminateされてしまう」というリスクを受け入れることによって単価が安くなったインスタンス

というわけで、オンデマンドが一番高価、そしてスポットが最も安価なインスタンスです。スポットインスタンスは、常に変動する市場価格があり、さらに利用者は指値でスポットインスタンスの入札(bid)を行います。市場価格が指値を下回っている時、インスタンスが利用できます。スポットインスタンスの人気が高まったことにより、市場価格が指値を上回ると、インスタンスはTerminateされてしまいます。

スポットインスタンスは、Amazonの立場から言えば「余剰リソースのオークション販売」です。その余剰リソースについて、各利用者が指値で入札(bid)を行い、入札額の高い順にリソースが割り当てられます。従って「そもそもリソースが余っていない場合」や「指値が相場を下回った場合」は落札ができないので、確実に起動できる保証が無い、というわけです。

しかし現実的には、日本市場では利用者がこのような「不確実性」を嫌う傾向にありますので、日本国内ではスポットインスタンスの利用者が少なく、「インスタンスが確保できない」という事態は少ないと思います。が、スポットインスタンスを使う場合は、リスクとして認識しておく必要はあるでしょう。

Auto Scalingでスポットインスタンスを使う

さて、このスポットインスタンスですが、Auto Scalingでも利用することができます。Auto Scalingの設定をする際には、Launch Configurationというものを作成しますが、その時のオプションとして、指値を指定します。

さて、指値と言ってもいくらを指定すれば良いのか困りますね。ここではt1.microを起動する場合の指値を考えてみましょう。まず、t1.microオンデマンドインスタンス(東京)の執筆時点の単価は$0.027でした。

次に、スポットインスタンスの過去の相場変動を見てみましょう。EC2 Management Consoleより、Spot Requestsのセクションを選択し、Pricing Historyボタンをクリックします。以下の例では、過去3ヶ月の相場はほぼ$0.0070で横這いであることが分かります。たまに ap-northeast-1a にて相場が上昇していることがありますね。注意点として、相場はオンデマンド価格よりも高くなることがある、ということは認識しておく必要がありそうです。

2013-08-14_1057-spot1

ちなみに、us-east-1の相場変動例は以下の通り。東京と違って、結構値動きがありますね。

2013-08-14_1625-spot2

以上の情報より、「いくらまで相場が上昇したらインスタンスの維持を諦めるのか」を考えます。今回はお試しですので、$0.008を上回ったら早々に諦める、ということにします。その上で、Auto ScalingのLaunch Configurationを以下のようなコマンドで作成します。ポイントとなるのは--spot-priceオプションですね。通常の設定に加え、このオプションを追加するだけです。

$ aws autoscaling create-launch-configuration \
 --launch-configuration-name cmlc1 \
 --image-id ami-173fbf16 \
 --instance-type t1.micro \
 --spot-price "0.008"

あとは通常のAuto Scalingと変わりません。Auto Scaling Groupを作ってみましょう。以下のコマンドで、2台構成のクラスタの起動を試み、起動できたらcmlbというロードバランサの配下に追加します。大事なのは、あくまでも「試みる」だけであり、落札できる保証は無いということです。

$ aws autoscaling create-auto-scaling-group \
 --auto-scaling-group-name cmasg1 \
 --availability-zones "ap-northeast-1a" "ap-northeast-1c" \
 --desired-capacity 2 \
 --max-size 2 \
 --min-size 2 \
 --load-balancer-names "cmlb" \
 --launch-configuration-name cmlc1

上記設定が終わると、EC2 Management Consoleより、Spot Requestsのセクションにおいて、Spot Requestが作成されたことが分かります。

2013-08-14_1140-spot3

$0.008による入札が行われ、落札できれば、間もなく表示が以下のように変化します。

2013-08-14_1141-spot4

以上で、スポットインスタンスを使ったAuto Scaling設定ができました。ちなみに、これらの2インスタンスはcmlbというELBの配下に追加されていますが、起動したのは素のAmazon Linuxなのでhttpdが立っていません。ヘルスチェックに失敗します。が、まぁそれは本番では上手くやってください。

可用性は…?

やったー安いぜ、とは言え…。相場が上昇した時は2台のインスタンスは全て潰され、サービスは停止してしまいます。安いんだから割り切れ、という話なのかもしれませんが、不意のサービス停止を受け入れられるようなおおらかなプロジェクトには、筆者は不幸にも(?)一度も出会ったことがありません。じゃあ実用性ないじゃん! ということになってしまいます。このままでは。

スポットインスタンスは、オンデマンド(またはリザーブド)インスタンスと組み合わせて使うのが王道なんです。4台のクラスタが欲しい時は、例えば2台はスポット、残りの2台はオンデマンドを利用する、といった使い方です。そうすれば、相場が安い時は4台でサービス提供ができ、万一相場が急上昇しても最低2台のサーバは維持され、サービス停止という最悪の事態は免れます *1

このような、スポットとオンデマンドの併用はどのようにしたら良いのでしょうか。さすがにLaunch Configurationには「2台はスポットで、2台はオンデマンドで」といった設定はできません。

これは、Launch ConfigurationとAuto Scaling Groupをもう一組作ってしまい、同じロードバランサの配下に設定すれば良いのです。というわけでやってみます。何も難しいことはありません。普通の設定を行い、ELBの設定を共通にするだけです。

$ aws autoscaling create-launch-configuration \
 --launch-configuration-name cmlc2 \
 --image-id ami-173fbf16 \
 --instance-type t1.micro

$ aws autoscaling create-auto-scaling-group \
 --auto-scaling-group-name cmasg2 \
 --availability-zones "ap-northeast-1a" "ap-northeast-1c" \
 --desired-capacity 2 \
 --max-size 2 \
 --min-size 2 \
 --load-balancer-names "cmlb" \
 --launch-configuration-name cmlc2

というわけで、一定の可用性を確保したオートスケーリングの設定ができました。

脚注

  1. まぁ、リソースが半減するわけですから、パフォーマンスは半減するでしょうけど…。