2011年6月27日月曜日

"SQS"と"CloudWatch"と"Auto Scaling"

スズキです。

"SQS"のメッセージ数を"CloudWatch"にカスタムメトリクスとして登録して、
そのカスタムメトリクスで"Auto Scaling"するってやつです。

今回は、一日一回の頻度でSQSに一気にメッセージを登録し、
それを複数インスタンスで処理するようなものなので
メッセージ数が1以上になったら、一気に10インスタンス立ち上げ、
メッセージ数が0になったら、全てのインスタンスをターミネートするようにしています。

SQSのメッセージ数を"CloudWatch"にカスタムメトリクスとして登録する部分は下記、
SQSのキューのサイズをCloudWatchに登録
SQSのメッセージを処理するインスタンスは下記で紹介しています。
SQSのキューのメッセージがなくなたらEC2インスタンスをシャットダウン
(ここでは結局シャットダウンはしないようにしています)
ということで、今回もPHP(AWS SDK)で実現してみました。

まずは共通設定です。

▼ common.php
define("AWS_KEY"         , "AAAAAAAA");
define("AWS_SECRET_KEY"  , "SSSSSSSS");
define("CP_SQS_URL_CRAWL", "https://sqs.ap-northeast-1.amazonaws.com/000000000000/crawl");
define("CP_AS_NAME"      , "crawl");
date_default_timezone_set("Asia/Tokyo");

次に"Auto Scaling"の"launch-configuration"を作成します。
指定している"ami-xxxxxxxx"は起動と同時にSQSのメッセージを処理し続けるAMIです。

▼ create-launch-configuration

require_once("/opt/cloudpack/bin/common.php");
require_once("/opt/aws/php/sdk.class.php");
$as = new AmazonAS();
$as->set_region(AmazonAS::REGION_APAC_NE1);
$response = $as->create_launch_configuration(
    CP_AS_NAME,
    "ami-xxxxxxxx",
    "t1.micro",
    array(
        "KeyName"        => "suz-lab_ap-northeast-1",
        "SecurityGroups" => array(
            "default",
            "crawl"
        )
    )
);
var_dump($response->isOK());

そして"Auto Scaling"の"auto-scaling-group"を作成します。
インスタンス数のMINを0、MAXを10としています。

▼ create-auto-scaling-group
require_once("/opt/cloudpack/bin/common.php");
require_once("/opt/aws/php/sdk.class.php");
$as = new AmazonAS();
$as->set_region(AmazonAS::REGION_APAC_NE1);
$response = $as->create_auto_scaling_group(
    CP_AS_NAME,
    CP_AS_NAME,
    0,
    10,
    array(
        "ap-northeast-1a",
        "ap-northeast-1b"
    )
);
var_dump($response->isOK());

PHP側の最後は"scaling-policy"の設定です。
ここでは"scale-out"のポリシー(10インスタンスになるように起動)と
"scale-in"のポリシー(全て"100%"のインスタンスをターミネート)を作成しています。

▼put-scaling-policy
require_once("/opt/cloudpack/bin/common.php");
require_once("/opt/aws/php/sdk.class.php");
$as = new AmazonAS();
$as->set_region(AmazonAS::REGION_APAC_NE1);
$response = $as->put_scaling_policy(
    CP_AS_NAME,
    "scale-out",
    10,
    "ExactCapacity"
);
var_dump($response->body->PutScalingPolicyResult->PolicyARN);
$response = $as->put_scaling_policy(
    CP_AS_NAME,
    "scale-in",
    -100,
    "PercentChangeInCapacity"
);
var_dump($response->body->PutScalingPolicyResult->PolicyARN);

上記で作成したポリシーを、"scale-out"はSQSのメッセージ数が1以上になったとき、
"scale-in"はSQSのメッセージ数が0になったとき実施されるようにするのですが、
この設定はCloudWatchのほうで行い、下記のように"AWS Management Console"で
行うこともできます。

CloudWatchのタブからアラームを作成します。


対象のメトリクス名(queue_size)を指定して、
統計情報の扱い方(Average)とチェックのインターバル(5分)を選択します。


アラームに名前(has-messages)と条件(queue_sizeが1以上になったらアラーム)を指定します。


アラームの状態が変わったときのアクションを指定します。
今回は、状態がアラームになった場合("queue_size"が1以上)は、
先ほど作成した"Auto Scaling"ポリシーの"scale-out"(10インスタンスになるように起動)、
状態がOKになった場合("queue_size"が0)は"scale-in"
(全て"100%"のインスタンスをターミネート)、が実施されるようにしています。


確認画面で問題なければ、"AWS Management Console"のCloudWatchの設定は終了です。


実際にSQSにメッセージを追加すると、EC2インスタンスが一気に10起動され、
メッセージの処理が進みSQSのメッセージ数が0になると、
全てのEC2インスタンスがターミネートされることがわかります。
(下記はアラームの状態とSQSのメッセージ数の推移です)


CloudWatchがデフォルトでSQSのメッセージ数を取れれば、
CloudWatchにデータを投入する管理インスタンスがいらなくなるのに...
--------
http://www.suz-lab.com

2 コメント:

kt さんのコメント...

こんにちは。

ひそかにこの機能が実装されたようですね。

http://docs.amazonwebservices.com/AmazonCloudWatch/latest/DeveloperGuide/CW_Support_For_AWS.html#sqs-metricscollected

十日遅れの七夕でしょうか。

suz-lab さんのコメント...

情報ありがとうございます。
掘り下げて、またこのブログで紹介できれば、
と思っています。