1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

大量のメールを送信する為にEC2インスタンスを自動で起動・停止する

Last updated at Posted at 2019-08-17

背景

大量のメールを短時間で送信し切る為に、送信時にハイスペックな専用のbatchサーバを起動し、並列数を多くして送信処理を行なう必要がありました。
これまではサーバの起動を手動で行なっていたのですが、メールの一斉送信の頻度が増えたので、SQSとLambdaを使って一斉送信時に自動でサーバを起動し、送信後にはサーバが停止されるようにしました。

構成

mail.png

  1. 一斉送信メールが設定されるとkickerが検知して、SQSにEC2起動のキューを投げます
  2. SQSにキューが投げられるとlambdaの関数が実行され、一斉送信専用batchサーバが起動します
  3. batchサーバは起動と同時に一斉送信メールの設定を読み込みメール送信処理を開始します
  4. メール送信処理が完了すると、SQSにEC2停止のキューを投げます
  5. SQSにキューが投げられるとlambdaの関数が実行され、一斉送信専用batchサーバが停止します

SQSの設定

新しいキューの作成から、キューを作成します。

EC2起動用のキュー
スクリーンショット 2019-08-17 17.12.07.png

EC2停止用のキュー
スクリーンショット 2019-08-17 17.13.55.png

lambdaの設定

まずlambda用の実行ロールを定義します。
ロールの作成で、Lambdaを選択します。

スクリーンショット 2019-08-17 16.43.01.png

ポリシーにはAmazonSQSFullAccessとLambdaEC2Controlを指定して作成します。

スクリーンショット 2019-08-17 16.47.37.png

LambdaEC2ControlはEC2の起動・停止を定義したポリシーです。
以下の設定で作成しておきます。

スクリーンショット 2019-08-17 16.31.23.png
{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Effect": "Allow",
            "Action": [
                "logs:CreateLogGroup",
                "logs:CreateLogStream",
                "logs:PutLogEvents"
            ],
            "Resource": "arn:aws:logs:*:*:*"
        },
        {
            "Effect": "Allow",
            "Action": [
                "ec2:Start*",
                "ec2:Stop*"
            ],
            "Resource": "*"
        }
    ]
}

次に関数の作成からEC2を起動させるlambda関数を作成します。
ランタイムにはpython3.7を選択し、実行ロールには先ほど作成したlambda-control-instanceを選択します。

screencapture-ap-northeast-1-console-aws-amazon-lambda-home-2019-08-17-16_59_04.png

lambdaの作成後、EC2起動用のSQSをトリガーに設定します。
最終的に以下のようになります。

スクリーンショット 2019-08-17 15.40.40.png

最後にインスタンスを起動させるlambda関数を設定します。

スクリーンショット 2019-08-17 15.47.16.png
import boto3
import os

def lambda_handler(event, context):
    ec2 = boto3.client('ec2', region_name='ap-northeast-1')
    ec2.start_instances(InstanceIds=[os.environ['instance_id']])
    print('Instance ' + os.environ['instance_id'] + ' Started')

一斉送信用のbatchサーバのインスタンスIDを、環境変数として指定します。

スクリーンショット 2019-08-17 15.47.40.png

これでEC2起動用のlambda関数作成は完了です。
同様の手順でEC2停止用のlambda関数も作成しておきます。

EC2停止用のlambdaでは以下の関数を設定します。

import boto3
import os

def lambda_handler(event, context):
    ec2 = boto3.client('ec2', region_name='ap-northeast-1')
    ec2.stop_instances(InstanceIds=[os.environ['instance_id']])
    print('Instance ' + os.environ['instance_id'] + ' Started')

今後の課題

排他制御

今後メール一斉送信の頻度がさらに増えた場合、メール送信処理中にkickerが起動して意図しない動きになってしまうので、排他制御の処理を追加する必要があります。

サーバレス構成に向けて

SQS + lambda + S3 + SESでサーバレスなメール配信システムを作ることができます。
それぞれの役割は以下の通りです。

SQS ... メールの送信処理待ちキュー
Lambda ... SQSからキューを受け取って、SES経由でメールを送る
S3 ... メールのペイロードを入れておく
SES ... メール送信

この構成の課題は、送信したメールのデータを更新したい場合、別でデータを管理する必要が出てくる点です。
例えば、HTMLメールを開封したタイミングでダミーピクセスのアクセスがサーバに飛んで、送信データのテーブルを更新する様なパターンです。

ちなみに、LambdaからMySQLにアクセスするのはコネクションプールの関係からアンチパターンらしいので、切り分ける場合でもDynamoDBとかに入れる必要があります。
ただし、最近はAurora Serverlessが出てきたのでLambdaからMySQLを使えるかもしれません。

1
0
0

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
1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?