Lambda Provisioned ConcurrencyのオートスケーリングをCDKで設定してみた(ターゲット追跡編)
目次
はじめに
こんにちは、スカイアーチHRソリューションズのsugawaraです。
前回の記事『Lambda Provisioned ConcurrencyのオートスケーリングをCDKで設定してみた』では、スケジュールされたProvisioned Concurrencyを設定しました。今回はターゲット追跡のProvisioned ConcurrencyをCDKで設定してきます。
ターゲット追跡とは、Application Auto Scalingを用いてスケーリングポリシーを定義し、 それに基づいてCloudWatch アラームを作成するLambdaのオートスケールの一種です。Provisioned Concurrencyの使用率やリクエスト数についてのメトリクスでアラームを作成できます。アラームがアクティブになると、Application Auto Scaling はProvisioned Concurrencyの割り当てられる数を自動的に調整します。トラフィックパターンが予測できないようなときに有効なアプローチです。
こちらに関してもコンソール画面からの操作は対応しておらず、現状はCLIで実行するようになっています。
そのため、今回もCDKで設定したいと思います。
なぜProvisioned Concurrencyが必要かなどは、以前の記事を見ていただければと思います。
環境
- WSL2
- CDK 2.138.1
- Node.js 20.12.1
構築の流れ
CDKの初期化
まずWSL上に作業フォルダtarget_track_provisioned_concurrencyを作成し、そのディレクトリにてCDKの準備をします。
$ mkdir lambda_target_track_provisioned_concurrency
$ cd lambda_target_track_provisioned_concurrency
$ cdk init app --language typescript
作成されたフォルダは下記のような構成になっています。
├── bin
│ └── lambda_target_track_provisioned_concurrency.ts // ここにenvを定義
├── cdk.json
├── jest.config.js
├── lib
│ └── lambda_target_track_provisioned_concurrency.ts // ここにAWSリソースを定義
├── package.json
├── package-lock.json
├── README.md
├── test
│ └── lambda_target_track_provisioned_concurrency.test.ts
└── tsconfig.json
CDKコードの全体像
下記がスタックファイルの全体となります。今回はバージョンに加えてエイリアスも指定しています。そのため、エイリアスに対してオートスケーリングの設定をしています。なお、エイリアス部分はcdk deploy時に失敗してしまうため、addDependencyでデプロイの順序に依存関係を追加しています。
import * as cdk from 'aws-cdk-lib';
import { Construct } from 'constructs';
import * as lambda from 'aws-cdk-lib/aws-lambda';
import * as applicationautoscaling from 'aws-cdk-lib/aws-applicationautoscaling'
export class LambdaTargetTrackProvisionedConcurrencyStack extends cdk.Stack {
constructor(scope: Construct, id: string, props?: cdk.StackProps) {
super(scope, id, props);
const lambdaFunction = new lambda.Function(this, 'LambdaFunction', {
functionName: "TargetTrackingProvisionedConcurrencyTestLambda",
description: "ターゲット追跡型のプロビジョニング済み同時実行の検証用Lambda",
runtime: lambda.Runtime.PYTHON_3_12,
handler: 'lambda_function.lambda_handler',
code: lambda.Code.fromAsset(`../target_tracking_provisioned_concurrency/lib`),
timeout: cdk.Duration.seconds(600),
memorySize: 256,
});
// バージョンの設定
const lambdaVersion = new lambda.Version(this, 'LambdaVersion', {
lambda: lambdaFunction,
description: 'Version for Target Tracking Provisioned Concurrency',
});
// エイリアスの設定
const alias = new lambda.Alias(this, 'LambdaAlias', {
aliasName: 'Load-Test',
version: lambdaVersion,
});
// オートスケーリングのターゲットの設定
const scalingTarget = new applicationautoscaling.ScalableTarget(this, 'ScalableTarget', {
serviceNamespace: applicationautoscaling.ServiceNamespace.LAMBDA,
minCapacity: 1,
maxCapacity: 50,
resourceId: `function:${lambdaFunction.functionName}:${alias.aliasName}`,
scalableDimension: 'lambda:function:ProvisionedConcurrency',
});
// デプロイ順序の依存関係を追加
scalingTarget.node.addDependency(alias);
// ターゲット追跡スケーリングの追加
scalingTarget.scaleToTrackMetric('TargetTracking', {
targetValue: 0.5,
predefinedMetric: applicationautoscaling.PredefinedMetric.LAMBDA_PROVISIONED_CONCURRENCY_UTILIZATION,
scaleInCooldown: cdk.Duration.seconds(10),
scaleOutCooldown: cdk.Duration.seconds(10),
});
}
ターゲット追跡のオートスケーリングですが、今回はProvisioned Concurrencyの使用率50%でオートスケールする設定にしています。
// ターゲット追跡スケーリングの追加
scalingTarget.scaleToTrackMetric('TargetTracking', {
targetValue: 0.5,
predefinedMetric: applicationautoscaling.PredefinedMetric.LAMBDA_PROVISIONED_CONCURRENCY_UTILIZATION,
scaleInCooldown: cdk.Duration.seconds(10),
scaleOutCooldown: cdk.Duration.seconds(10),
});
また、libフォルダ配下には下記のlambda_function.pyを作成します。
import json
def lambda_handler(event, context):
# TODO implement
return {
'statusCode': 200,
'body': json.dumps('Hello from Lambda!')
}
上記のCDKコードでデプロイします。lambda_target_track_provisioned_concurrencyディレクトリにて下記のコマンドを実行します。
$ cdk diff
$ cdk deploy
デプロイが完了したら、Lambdaコンソールにて設定の確認をします。エイリアスが設定されていることがわかります。
Application Auto Scaling設定はコンソール画面で確認ができないため、下記のCLIで見てみます。CDKのコードで書いたような設定になっています。また、CDKがCloudWatch Alarmもよしなにやってくれていることがわかります。
aws application-autoscaling describe-scaling-policies \
--service-namespace lambda
{
"ScalingPolicies": [
{
"PolicyARN": "arn:aws:autoscaling:ap-northeast-1:008458347550:scalingPolicy:2cc56c12-0b71-429e-b39e-8fb4af70dd70:resource/lambda/function:TargetTrackingProvisionedConcurrencyTestLambda:Load-Test:policyName/LambdaTargetTrackProvisionedConcurrencyStackScalableTargetTargetTracking177ED8D9",
"PolicyName": "LambdaTargetTrackProvisionedConcurrencyStackScalableTargetTargetTracking177ED8D9",
"ServiceNamespace": "lambda",
"ResourceId": "function:TargetTrackingProvisionedConcurrencyTestLambda:Load-Test",
"ScalableDimension": "lambda:function:ProvisionedConcurrency",
"PolicyType": "TargetTrackingScaling",
"TargetTrackingScalingPolicyConfiguration": {
"TargetValue": 0.5,
"PredefinedMetricSpecification": {
"PredefinedMetricType": "LambdaProvisionedConcurrencyUtilization"
},
"ScaleOutCooldown": 10,
"ScaleInCooldown": 10
},
"Alarms": [
{
"AlarmName": "TargetTracking-function:TargetTrackingProvisionedConcurrencyTestLambda:Load-Test-AlarmHigh-b7f7064d-95a0-4a08-a5a3-ebf0f9e95b54",
"AlarmARN": "arn:aws:cloudwatch:ap-northeast-1:008458347550:alarm:TargetTracking-function:TargetTrackingProvisionedConcurrencyTestLambda:Load-Test-AlarmHigh-b7f7064d-95a0-4a08-a5a3-ebf0f9e95b54"
},
{
"AlarmName": "TargetTracking-function:TargetTrackingProvisionedConcurrencyTestLambda:Load-Test-AlarmLow-9c70af13-d33a-40bc-a882-3654e56c784c",
"AlarmARN": "arn:aws:cloudwatch:ap-northeast-1:008458347550:alarm:TargetTracking-function:TargetTrackingProvisionedConcurrencyTestLambda:Load-Test-AlarmLow-9c70af13-d33a-40bc-a882-3654e56c784c"
}
],
"CreationTime": "2024-05-10T16:22:12.630000+09:00"
}
]
}
CloudWatch Alarmの詳細はコンソール画面から確認ができます。なお、デフォルトではスケールアウトは3分以内の3データポイント、スケールインは15分以内の15データポイントとなっているようです。
負荷をかけてみる
Provisioned Concurrencyの使用率に応じてオートスケールするのかどうかを確認するために、簡単に負荷をかけてみます。スクリプトを用意して、同時実行させてみます。
しばらくすると、下記のようにアラーム状態となります。
Lambdaのコンソール画面を見てみると、Provisioned Concurrencyの値が変更中になっているようです。
さらに少し待っていると、ステータス準備完了となりました。最終的にはProvisioned Concurrencyは4まで上がりました。これも時間が経てば徐々にスケールインされるはずです。
これでProvisioned Concurrencyの使用率に応じてオートスケールさせることができました!
おわりに
前回に引き続き、Lambda Provisioned Concurrencyのオートスケールを実施していきました。ターゲット追跡となると、実際にどのメトリクスを対象とし、しきい値はどのくらいにするかなどといったアラームの詳細の作り込みが必要そうです。
また、CloudWatchへメトリクスが流れるのがリアルタイムではないため、若干のタイムラグが気になるところです。ただ、急激なスパイクがないなどの場合には利用できるかもしれません。
一旦Lambdaのオートスケーリングはこれで終わりにしたいと思います!