この記事は公開されてから1年以上経過しています。情報が古い可能性がありますので、ご注意ください。
はじめに
プロフィールビューアーサービスProflly(プロフリー)の開発にて、一部の Lambda の処理のコールドスタートが影響し、パフォーマンスの問題を抱えていました。
この問題を解決するために、Provisioned Concurenncy
を導入してみることにしたのですが、なるべくコストも抑えたかったので、合わせて Application Auto Scaling
を設定し、利用者が多い時間帯(08:00 - 20:00)だけ有効になるように設定してみましたので、その実装方法を紹介します。
作成するアーキテクチャ
今回作成するのはシンプルに決まった時間帯だけ、Provisioned Concurenncy が有効になるように、Application Auto Scaling を設定します。08:00 にスケールアウトするようにminCapacity
: 1
, maxCapacity
: 1
を設定し、20:00 にスケールインするように minCapacity
: 0
, maxCapacity
: 0
を設定します。
環境
- AWS CDK
1.130.0
- TypeScript
3.9.10
実装内容
利用するパッケージをインストール
今回作成するアーキテクチャに必要なパッケージをインストールします。
npm install --save-dev @aws-cdk/aws-lambda-nodejs @aws-cdk/aws-applicationautoscaling
スタックの実装
スタックの中で各 Construt を定義して、リソースを作成します。
Provisioned Concurenncy は特定のバージョンまたはエイリアスに対して設定することができる($LATEST
は不可)ので、今回は最新バージョンのエイリアスを作成して設定します。
lib/provisioned-concurrency-autoscaling-cdk-sample-stack.ts
import * as cdk from "@aws-cdk/core";
import { NodejsFunction } from "@aws-cdk/aws-lambda-nodejs";
import { Schedule } from "@aws-cdk/aws-applicationautoscaling";
export class ProvisionedConcurrencyAutoscalingCdkSampleStack extends cdk.Stack {
constructor(scope: cdk.Construct, id: string, props?: cdk.StackProps) {
super(scope, id, props);
// Lambda 関数を作成
const sampleLambda = new NodejsFunction(this, "sampleLambda", {
entry: "src/index.ts",
handler: "handler",
});
// currentVersion でエイリアスを作成
const alias = sampleLambda.currentVersion.addAlias("currentVersion");
// スケーラブルターゲットを作成
const scalableAttribute = alias.addAutoScaling({
minCapacity: 1,
maxCapacity: 1,
});
// JST の 20:00 にスケールインするアクションを作成
scalableAttribute.scaleOnSchedule("sampleLambdaScaleIn", {
minCapacity: 0,
maxCapacity: 0,
schedule: Schedule.cron({ minute: "0", hour: "11" }),
});
// JST の 08:00 にスケールアウトするアクションを作成
scalableAttribute.scaleOnSchedule("sampleLambdaScaleOut", {
minCapacity: 1,
maxCapacity: 1,
schedule: Schedule.cron({ minute: "0", hour: "23" }),
});
}
}
デプロイ後のリソースを確認
以下のコマンドでデプロイを実行し、実行結果を確認してみます。
cdk deploy
作成した Lambda 関数の currentVersion
エイリアスに Provisioned Concurenncy が設定されていることを確認できました。
スケーラブルターゲットおよび各スケーリングアクションが設定されていることを確認(AWS CLIにて)できました。
$ aws application-autoscaling describe-scalable-targets \
--service-namespace lambda
...
{
"ServiceNamespace": "lambda",
"ResourceId": "function:ProvisionedConcurrencyAutosca-sampleLambdaBA9DE42C-1vtOI2HB2pLx:currentVersion",
"ScalableDimension": "lambda:function:ProvisionedConcurrency",
"MinCapacity": 1,
"MaxCapacity": 1,
"RoleARN": "arn:aws:iam::XXXXXXXX:role/aws-service-role/lambda.application-autoscaling.amazonaws.com/AWSServiceRoleForApplicationAutoScaling_LambdaConcurrency",
"CreationTime": "2021-10-30T09:07:57.052000+09:00",
"SuspendedState": {
"DynamicScalingInSuspended": false,
"DynamicScalingOutSuspended": false,
"ScheduledScalingSuspended": false
}
}
...
$ aws application-autoscaling describe-scheduled-actions \
--service-namespace lambda
...
{
"ScheduledActionName": "sampleLambdaScaleOut",
"ScheduledActionARN": "arn:aws:autoscaling:ap-northeast-1:XXXXXXXX:scheduledAction:77f0bd55-cb28-45d5-a6bf-19bbb33807ad:resource/lambda/function:ProvisionedConcurrencyAutosca-sampleLambdaBA9DE42C-1vtOI2HB2pLx:currentVersion:scheduledActionName/sampleLambdaScaleOut",
"ServiceNamespace": "lambda",
"Schedule": "cron(0 23 * * ? *)",
"ResourceId": "function:ProvisionedConcurrencyAutosca-sampleLambdaBA9DE42C-1vtOI2HB2pLx:currentVersion",
"ScalableDimension": "lambda:function:ProvisionedConcurrency",
"ScalableTargetAction": {
"MinCapacity": 1,
"MaxCapacity": 1
},
"CreationTime": "2021-10-30T15:12:05.932000+09:00"
},
{
"ScheduledActionName": "sampleLambdaScaleIn",
"ScheduledActionARN": "arn:aws:autoscaling:ap-northeast-1:XXXXXXXX:scheduledAction:77f0bd55-cb28-45d5-a6bf-19bbb33807ad:resource/lambda/function:ProvisionedConcurrencyAutosca-sampleLambdaBA9DE42C-1vtOI2HB2pLx:currentVersion:scheduledActionName/sampleLambdaScaleIn",
"ServiceNamespace": "lambda",
"Schedule": "cron(0 11 * * ? *)",
"ResourceId": "function:ProvisionedConcurrencyAutosca-sampleLambdaBA9DE42C-1vtOI2HB2pLx:currentVersion",
"ScalableDimension": "lambda:function:ProvisionedConcurrency",
"ScalableTargetAction": {
"MinCapacity": 0,
"MaxCapacity": 0
},
"CreationTime": "2021-10-30T15:12:05.694000+09:00"
}
...
さいごに
Lambda のコールドスタート対策として、Provisioned Concurenncy
を導入したいけど、コストを抑えたい、効果の高い時間帯だけスケールしたいなどを実現したい際に、Application Auto Scaling
も合わせて設定しておくことで、より高い効果を得られると感じました。
今回は一部の処理にのみ導入してみましたが、ここの処理だけはなるべくコールドスタートしてほしくないといった処理に設定するのは、有効な対応かなと思いました。
部分的に導入してみて、すごくよい効果を得ることができたから、全部の Lambda に設定しよう!というのは、コスト面やパフォーマンス面的にもメリットが薄くなるかなと思います。その際は、この処理は Lambda でいいんだっけ?というのを今一度考えてみてもよいかなと思います。
どなたかの参考になれば幸いです。