AWS CDK で Lambda 関数に Provisioned Concurenncy を Application Auto Scaling と一緒に設定してみた
はじめに
プロフィールビューアーサービス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
は不可)ので、今回は最新バージョンのエイリアスを作成して設定します。
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 でいいんだっけ?というのを今一度考えてみてもよいかなと思います。
どなたかの参考になれば幸いです。