LoginSignup
0

More than 1 year has passed since last update.

AWS SDK for PHP3 AutoScalingClientからAuto Scaling グループを設定してみる

Last updated at Posted at 2021-10-29

経緯

LaravelアプリケーションでAWSのメッセージキューイングサービス(Amazon SQS)を利用する機会があり、
Webから取得したデータをキューに送信、定期的にキューからデータを取得しては処理をするということをしていました。
但し、気づいたらキューに数万件のメッセージが。。
もう少し早く、柔軟に処理できないかと模索した結果、キューに溜まっているメッセージ件数に応じてAuto Scaling グループ(AWS Auto Scaling)の設定を変更、必要なだけサーバーを立てるということをしたいと思い、この記事を書くに至りました。

以下、ざっくりとした処理フローです。
①Laravelアプリケーション実装しているCommandでwebから情報を定期取得

②Amazon SQS(メッセージキューイングサービス)に取得したデータを追加
 *必要なデータを配列に入れ、serializeしたものを送信しています。

③定期的にキューからメッセージを取得し処理を実施

追伸:
私もまだまだ道半ば故、ご指摘やアドバイスを頂ければとっても嬉しいです。

■事前準備

今回はローカルに構築したLaradock環境下で行っています。

・まず、workspaceコンテナへ

docker-compose exec workspace bash

・ホームへ移動

cd ~

・.awsディレクトリを作成し、移動

mkdir .aws
cd .aws

・以下ファイルを作成し、AWSへのアクセス情報を書き込んでおきましょう

vim credentials

[default]
aws_access_key_id = アクセスキーID
aws_secret_access_key = シークレットキー

vim config

[default]
output = json
region = ap-northeast-1

・config、credentailsファイルの権限を600に変更
・.awsフォルダの権限を775に変更

chmod 600 *
chmod 775 .aws

作成したcommandクラスのソース内容

ソースに一時的にコメントを記載しています。

OptimizeAutoScalingGroup.php
namespace App\Console\Commands;

use Aws\Sqs\SqsClient;
use Aws\Sqs\AwsException;
use Aws\AutoScaling\AutoScalingClient;
use Illuminate\Console\Command;

class OptimizeAutoScalingGroup extends Command
{
    protected $signature = 'command:optimize_auto_scaling_group';
    protected $description = '監視対象のSQSキューのメッセージ件数に応じてAutoScalingGroupの設定を最適化'

    /**
     * @return int
     *
     */

    public function handle()
    {
        try {

            // SQSクライアント生成
            $sqs_client = new SqsClient(['profile' => 'default', 'region' => 'ap-northeast-1', 'version' => 'latest']);

            // AutoScalingClient生成
            $auto_scaling_client = new AutoScalingClient(['profile' => 'default', 'region' => 'ap-northeast-1', 'version' => 'latest']);

            // SQSキューからメッセージ件数を取得
            $receive_result = $sqs_client->getQueueAttributes([
                'AttributeNames' => ['ApproximateNumberOfMessages'],
                'QueueUrl' => 'queue_url' // こちらに対象のSQSキューのURLを設定
            ]);

            $message_count = intval($receive_result->get('Attributes')['ApproximateNumberOfMessages']);

            // LaunchConfigurationNameを設定
            $launch_configuration_name = 'CONFIGURATION-TEMPLATE';

            // AutoScalingGroupNameを設定
            $auto_scaling_group_name = 'AUTO-SCALING-GROUP';

            // AutoScalingGroupの存在確認
            $receive_result = $auto_scaling_client->describeAutoScalingGroups(['AutoScalingGroupNames' => [$auto_scaling_group_name]]);
            $auto_scaling_group = $receive_result['AutoScalingGroups'];

            if (empty($auto_scaling_group) !== true) {
                // 指定したAutoScalingGroupプロセスを停止
                $auto_scaling_client->suspendProcesses([
                    'AutoScalingGroupName' => $auto_scaling_group_name
                ]);

                // AutoScalingGroupを削除
                $auto_scaling_client->deleteAutoScalingGroup([
                    'AutoScalingGroupName' => $auto_scaling_group_name,
                    'ForceDelete' => true,
                ]);

                // AutoScalingGroupが削除されるまで待機
                while (true) {
                    $receive_result = $auto_scaling_client->describeAutoScalingGroups(['AutoScalingGroupNames' => [$auto_scaling_group_name]]);

                    $auto_scaling_group = $receive_result['AutoScalingGroups'];

                    if (empty($auto_scaling_group)) {
                        echo '削除処理が完了した為、AutoScalingGroupを再構築します.PHP_EOL;
                        break;
                    }
                    echo '削除処理中...'.PHP_EOL;

                    sleep(30);
                }
            }

            // キューから取得したメッセージ件数に応じてAutoScalingGroupの最小値、最大値を設定
            $auto_scaling_min_count = 2; // デフォルト値をとりあえず設定
            $auto_scaling_max_count = 3;
            if ($message_count > 5000 && $message_count <= 10000) {
                $auto_scaling_min_count = 5;
                $auto_scaling_max_count = 7;
            }
            if ($message_count > 10000 && $message_count <= 50000) {
                $auto_scaling_min_count = 10;
                $auto_scaling_max_count = 15;
            }

            // AutoScaling起動テンプレート設定
            $receive_result = $auto_scaling_client->describeLaunchConfigurations(['LaunchConfigurationNames' => [$launch_configuration_name]]);
            $launch_configuration = $receive_result['LaunchConfigurations'];

            if (empty($launch_configuration)) {
                $auto_scaling_client->createLaunchConfiguration([
                    'LaunchConfigurationName' => $launch_configuration_name,
                    'ImageId' => 'EC2のAMI',
                    'InstanceType' => 't2.nano',
                    'KeyName' => 'キーペア名',
                    'SecurityGroups' => [
                        'セキュリティグループ',
                    ],
                ]);
            }

            // AutoScalingGroup設定
            $auto_scaling_client->createAutoScalingGroup([
                'AutoScalingGroupName' => $auto_scaling_group_name,
                'LaunchConfigurationName' => $launch_configuration_name,
                'HealthCheckType' => 'EC2',
                'HealthCheckGracePeriod' => 300,
                'MinSize' => $auto_scaling_min_count,
                'MaxSize' => $auto_scaling_max_count,
                'AvailabilityZones' => [
                    'ap-northeast-1a',
                    'ap-northeast-1c',
                    'ap-northeast-1d',
                ],
            ]);
        } catch(AwsException $e) {
            echo "[Error]".PHP_EOL;
            echo $e->getMessage().PHP_EOL;
            echo $e->getFile()."(LINE:".$e->getLine().")".PHP_EOL;
            die();
        }
    }
}

ポイント1. SQSキューからメッセージ件数を取得

// SQSキューからメッセージ件数を取得
$receive_result = $sqs_client->getQueueAttributes([
  'AttributeNames' => ['ApproximateNumberOfMessages'],
  'QueueUrl' => 'queue_url'
 ]);

$message_count = intval($receive_result->get('Attributes')['ApproximateNumberOfMessages']);

AttributeNames(key)にApproximateNumberOfMessages(value)を指定することでキューからメッセージ件数を取得できます。
*approximateなんであくまで近似値なんでしょう。
こちらの公式ページ参考に

ポイント2. AutoScalingGroupの存在確認

再構築しようとしているAtuoScalingGroupが既に存在しているかの判定処理です。

$receive_result = $auto_scaling_client->describeAutoScalingGroups([
  'AutoScalingGroupNames' => [$auto_scaling_group_name]
]);

$auto_scaling_group = $receive_result['AutoScalingGroups'];

DescribeAutoScalingGroups
 => 対象のオートスケーリンググループ名を指定し、オートスケーリンググループに関する情報を取得。
こちらも公式ページ参考に

ポイント3. 起動中のAutoScalingGroupのプロセスを停止し、AutoScalingGroupを削除

if (empty($auto_scaling_group) !== true) {
   $auto_scaling_client->suspendProcesses([
     'AutoScalingGroupName' => $auto_scaling_group_name
   ]);

   $auto_scaling_client->deleteAutoScalingGroup([
      'AutoScalingGroupName' => $auto_scaling_group_name,
      'ForceDelete' => true,
   ]);

   while (true) {
     $receive_result = $auto_scaling_client->describeAutoScalingGroups(
        ['AutoScalingGroupNames' => [$auto_scaling_group_name]
     ]);

     $auto_scaling_group = $receive_result['AutoScalingGroups'];

     if (empty($auto_scaling_group)) {
         echo '削除処理が完了した為、AutoScalingGroupを再構築します.PHP_EOL;
         break;
     }

     echo '削除処理中...'.PHP_EOL;

     sleep(30);
   }
}

SuspendProcesses
 => 指定したAutoScalingのプロセスを一時停止。
 *第二引数の「ScalingProcesses」でsuspendするプロセスを細かく指定できそうな感じです。多分。
こちらも公式ページ参考に

DeleteAutoScalingGroup
 => 指定したAutoScalingGroupを削除。起動中のAutoScalingGroupを削除する為に第二引数のForceDeleteをtrueとしています。
 *このあたりはもう少し調べる必要がありそうです。。
こちらも公式ページ参考に

次が私が少し苦労した点です。

上記でDeleteAutoScalingGroupを実行すると、
①スケーリングされたインスタンスが削除される
②紐づいているAutoScalingGroupを削除
といった流れなんですが、②でAutoScalingGroupが完全に削除されるまでの時間がまちまちの為、
以後の処理でAutoScalingGroupを再構築する際、既にAutoScalingGroupが存在しているというエラーになる場合があります。
そこでこんな不恰好なコードになっています。。

   while (true) {
     $receive_result = $auto_scaling_client->describeAutoScalingGroups(
        ['AutoScalingGroupNames' => [$auto_scaling_group_name]
     ]);

     $auto_scaling_group = $receive_result['AutoScalingGroups'];

     if (empty($auto_scaling_group)) {
         echo '削除処理が完了した為、AutoScalingGroupを再構築します.PHP_EOL;
         break;
     }

     echo '削除処理中...'.PHP_EOL;

     sleep(30);
   }

完全に削除されるまで、whileの中でdescribeAutoScalingGroups(オートスケーリンググループに関する情報を取得)を実行しています。

ポイント4. キューから取得したメッセージ件数に応じてAutoScalingGroupの最小値、最大値を設定

// キューから取得したメッセージ件数に応じてAutoScalingGroupの最小値、最大値を設定
$auto_scaling_min_count = 2;
$auto_scaling_max_count = 3;

if ($message_count > 5000 && $message_count <= 10000) {
  $auto_scaling_min_count = 5;
  $auto_scaling_max_count = 7;
}
if ($message_count > 10000 && $message_count <= 50000) {
  $auto_scaling_min_count = 10;
  $auto_scaling_max_count = 15;
}

ここは大したポイントではないですね。インスタンスの増減を確認する為に一時的にスケーリングするインスタンスの最小値、最大値を設定しています。

ポイント5. AutoScaling起動設定の作成

$receive_result = $auto_scaling_client->describeLaunchConfigurations(['LaunchConfigurationNames' => [$launch_configuration_name]]);
$launch_configuration = $receive_result['LaunchConfigurations'];

if (empty($launch_configuration)) {
   $auto_scaling_client->createLaunchConfiguration([
     'LaunchConfigurationName' => $launch_configuration_name,
     'ImageId' => 'EC2のAMI',
     'InstanceType' => 't2.nano',
     'KeyName' => 'キーペア名',
     'SecurityGroups' => [
        'セキュリティグループ',
       ],
   ]);
}

CreateLaunchConfiguration
 => AutoScalingの起動設定を作成。
こちらも公式ページ参考に

ポイント6. AutoScalingGroupの作成

$auto_scaling_client->createAutoScalingGroup([
   'AutoScalingGroupName' => $auto_scaling_group_name,
   'LaunchConfigurationName' => $launch_configuration_name,
   'HealthCheckType' => 'EC2',
   'HealthCheckGracePeriod' => 300,
   'MinSize' => $auto_scaling_min_count,
   'MaxSize' => $auto_scaling_max_count,
   'AvailabilityZones' => [
     'ap-northeast-1a',
     'ap-northeast-1c',
     'ap-northeast-1d',
    ],
]);

CreateAutoScalingGroup
 => AutoScalingGroupの作成。
 *最低限必要であろうパラメータを設定していますが、こちらももう少し調べる必要がありそうです。
こちらも公式ページ参考に

所感

一旦やりたいことはできましたが、まだまだブラッシュアップする必要があるなと感じました。
随時記事も整理していきます。
以上です。

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0