はじめに
- Serverless Advent Calendar 2016の22日目です。
- サーバレスネタとしては、以前 在席管理をSlackとAWSのサーバレスアーキテクチャで解決してみた(iruca API編) てな記事も書いてるので、そちらも良かったらチェックしてください。
- 本記事では、サーバレスで、何とか先輩の手を煩わせないためにどうしたものかと考えてた内容を書きます。
- 来年も自分のためだけじゃなくて、人のためにもサーバレスアーキテクチャを考えて生きていきたいと思います。
要件
- 世界展開を行うECシステムで、ネットワークレイテンシーを解消するために、AWSの各リージョンにフロントエンド機能を設置する。
- 但し、個人情報は既存のDCに保管するものとして、ECで発生したオーダーデータ等の個人情報についても一定期間以上 AWSのDBに保持してはならない。
- 尚、今回利用するECパッケージは、オーダーが入ると同一リージョンのオーダーテーブルにデータが登録される。
ソリューション
- ECは、パッケージ利用想定なので、なるべくイジらないのがセオリー。
- で、オーダーテーブルに登録されたレコードを普通に移動させれば良いので、以下の構成は普通に思いつくわけです。
- 上記だと、いかんせんサーバレスじゃないので、以下のような構成が発案されます。
- しかしながら、上記だと赤丸部分でオーダーと同時にSQSにメッセージ投げるというECパッケージの改修が必要となるのでゲンナリします。(これを通すと先輩の手を煩わせることに...)
- 結合度も高いので、疎結合なサーバレスアーキテクチャとして、以下のような構成が発案されます。
- 因みにRDSのエンジンは、良いことしかないのでAuroraにしましょう。
テーブルへのInsert通知をServerlessで処理する
- 上記を踏まえてテーブルへのInsert通知をServerlessで処理する方法を紹介します。
- 具体的には、オーダーテーブルへのAfter InsertにTrigger仕込んで、Lambda経由でSQSにメッセージを登録する方法になります。
- SQSに伝わればその先は幾らでもやりようがあると思います。
- Triggerは、複雑過ぎると良いことないので、シンプルに使いましょう。
IAM Roleを作成する
- Lambda用Role
項目 | 設定内容 |
---|---|
ロール名 | (任意:[例] LambdaDbTriggerTestRole) |
AWS サービスロール | AWS Lambda |
アタッチするポリシー | AmazonSQSFullAccess |
- RDS用Role
項目 | 設定内容 |
---|---|
ロール名 | (任意:[例] RdsDbTriggerTestRole) |
AWS サービスロール | AWS RDS |
アタッチするポリシー | 無し |
※超重要※ | 作成後、アクセス許可タブでAWSLamdbaRole をアタッチ |
SQSでQueueを作成する
- 任意のキュー名でキューを作成します。
- 例)DbTriggerTestQueue
LambdaでFunctionを作成する
- RDSからキックされ、SQSにメッセージ送信するLambdaファンクションを作成します。
項目 | 設定内容 |
---|---|
Runtime | Python 2.7 |
Handler | lambda_function.lambda_handler |
Role | 先程作成したLambda用Role |
- コードは以下の内容です。(queueNameは、先程作成したqueueNameを指定してください)
main.py
import boto3
import json
import logging
queueName='DbTriggerTestQueue'
def lambda_handler(event, context):
try:
logger.info(event)
response = boto3.resource('sqs').get_queue_by_name(
QueueName = queueName
).send_message(
MessageBody = json.dumps(event)
)
logger.info(response)
return response
except Exception as e:
logger.error(e)
raise e
Auroraを起動する
- 以下の内容で起動しました。
項目 | 設定内容 |
---|---|
リージョン | ap-northeast-1 |
インスタンスクラス | db.t2.medium |
マルチAZ | No |
サブネットグループ | Default |
パブリックアクセス可能 | No |
Availability Zone | ap-northeast-1a |
パラメータグループ | 新規のDB Parameter Group 新規のDB Cluster Parameter Group |
AuroraにIAMロールを設定する
- クラスターのIAMロールの管理から先程作成した
RDS用Role
を紐付けます。
- 先程作成&Auroraに指定した
DB Cluster Parameter Group
のパラメータの編集から、aws_default_lambda_role
の値に、先程作成したRDS用Role
のARNを設定します。 - 例)arn:aws:iam::xxxxxxxxxx:role/RdsDbTriggerTestRole
- DBクラスタパラメータグループが
pending-reboot
になるはずなので、Auroraを再起動します。
Triggerを作成する
- 再起動したらAuroraに接続して、以下のStored Procedure、Table、Triggerを作成します。
- Stored Procedure
- mysql.lambda_asyncの第一引数は、先程作成したLambdaのARNを設定します。
sqs_order_data_ai_message.sql
DROP PROCEDURE IF EXISTS sqs_order_data_ai_message;
DELIMITER ;;
CREATE PROCEDURE sqs_order_data_ai_message (IN id INT(11),
IN item VARCHAR(50)) LANGUAGE SQL
BEGIN
CALL mysql.lambda_async('arn:aws:lambda:ap-northeast-1:xxxxxxxx:function:TestFunction',
CONCAT('{ "id" : "', id,
'", "item" : "', item, '" }')
);
END
;;
DELIMITER ;
- Table
order_data.sql
CREATE TABLE `order_data` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`item` varchar(50) NOT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
- Trigger
trigger_order_data_ai.sql
DELIMITER ;;
CREATE TRIGGER trigger_order_data_ai
AFTER INSERT ON order_data
FOR EACH ROW
BEGIN
CALL sqs_order_data_ai_message(NEW.id, NEW.item);
END
;;
DELIMITER ;
動作テスト
- 以下のSQLを実行してみます。
insert.sql
INSERT INTO order_data VALUES (NULL, 'item_001');
- 取り急ぎ、SQSの画面で利用可能なメッセージがカウントアップされていれば成功です。
備考
- エンジンは
Aurora
一択です。MySQL
を選んだところで以下のようにmysql.lambda_async
がコール出来ないです。
MySQL
mysql> show create procedure mysql.lambda_async \G
ERROR 1305 (42000): PROCEDURE lambda_async does not exist