2020年1月26日 追記
Serverless Frameworkで行うLambdaのコールドスタート対策 という記事を書きました。
今は Serverless Frameworkで行うLambdaのコールドスタート対策 を参考にする事をオススメします。
この記事で扱うテーマ
AWS Lambdaで発生するコールドスタートを軽減させる為の対策を実施します。
前提条件
Serverless Framework でAWS Lambdaの開発を行っている事。
コールドスタート?
実業務でAWS Lambdaを使っている方なら分かると思いますが、AWS Lambdaにはコールドスタートという、Lambda関数のレイテンシが極端に悪化する現象が発生します。
コールドスタートは主に以下の原因で発生します。
- 実行可能なコンテナが1つも存在しない時
- 利用可能な数以上の同時リクエストが送信された時
- コードや設定変更を行った時(デプロイを行った時)
このあたりに関しては既に詳しくまとめてある記事がありますので、リンクを共有させて頂きます。
対策
実行可能なコンテナが消えないように定期的にAWS Lambdaを実行する事でコールドスタートの可能性を軽減します。
自分で0から作っても良いのですが、 こちら で紹介されていた、serverless-plugin-warmup というPluginを利用すると楽なので、こちらを利用していきます。
導入方法
serverless-plugin-warmup の通りに進めていけば問題ありません。
はじめに npm install serverless-plugin-warmup --save-dev
を実行してpackageのインストールを行います。
※ yarn を利用している場合は yarn add serverless-plugin-warmup --dev
でインストールします。
pluginを読み込ませる設定を追加
serverless.yml
に以下の設定を追加します。
plugins:
- serverless-plugin-warmup
IAM Roleの追加
以下の記述を追加します。
既に lambda:InvokeFunction の権限がある場合はこの手順は省略出来ます。
iamRoleStatements:
- Effect: 'Allow'
Action:
- 'lambda:InvokeFunction'
Resource:
- Fn::Join:
- ':'
- - arn:aws:lambda
- Ref: AWS::Region
- Ref: AWS::AccountId
- function:${self:service}-${opt:stage, self:provider.stage}-*
定期実行の対象にしたい関数に warmup: true
を指定
以下のように記述します。(helloを対象にする場合)
functions:
hello:
warmup: true
これが基本ですが、他にも特定のstageの時だけ定期実行の対象にしたり、定期実行の時間間隔を調整(デフォルトは5分間隔で実行)したり出来ます。
詳しくは GitHub を見ると良いでしょう。
私の場合はデプロイ後に対象の関数を実行する prewarm
を true
に設定しました。
custom:
warmup:
prewarm: true
デプロイ
設定が終わったら serverless deploy
を実行します。
デプロイ完了後、マネジメントコンソールでLambda関数の一覧を見ると、 [サービス名]-[stage]-warmup-plugin
という関数が生成されている事が確認出来ます。
"use strict";
/** Generated by Serverless WarmUP Plugin at 2017-11-09T01:54:08.198Z */
const aws = require("aws-sdk");
aws.config.region = "ap-northeast-1";
const lambda = new aws.Lambda();
const functionNames = "[サービス名]-[stage]-[関数名]".split(",");
module.exports.warmUp = (event, context, callback) => {
let invokes = [];
let errors = 0;
console.log("Warm Up Start");
functionNames.forEach((functionName) => {
const params = {
FunctionName: functionName,
InvocationType: "RequestResponse",
LogType: "None",
Qualifier: process.env.SERVERLESS_ALIAS || "$LATEST",
Payload: JSON.stringify({ source: "serverless-plugin-warmup" })
};
invokes.push(lambda.invoke(params).promise().then((data) => {
console.log("Warm Up Invoke Success: " + functionName, data);
}, (error) => {
errors++;
console.log("Warm Up Invoke Error: " + functionName, error);
}));
});
Promise.all(invokes).then(() => {
console.log("Warm Up Finished with " + errors + " invoke errors");
callback();
});
}
serverless logs
コマンド等で見てみると定期実行されている事が確認出来るかと思います。
まとめ
以上が serverless-plugin-warmup を利用したコールドスタート軽減対策でした。
これから正式に導入しようと考えているので、また知見が溜まったら何かで共有させて頂きます。
最後まで読んで頂きありがとうございました。