目的
仕事で.NET環境のLambdaを動かしているのですが、やはりアプリケーション単位でデプロイするとコールドスタートが足枷です。ってかかかなり遅いです。
.NET 7からAOTで早くなったというのですが、使用できるライブラリに制限があったりとまだまだ実用的ではありません。
じゃあ定期実行か?なんて博打みたいなことはしてられないので、お金で解決するためにProvisioned Concurrencyを設定しようとなりました。
ただ、アクセス時間帯が少ない夜間帯にProvisioned Concurrencyを設定してもお金の無駄になってしまうので、Auto Scalingを設定し日中の時間帯だけウォーム状態にすることにしました。
で、CLIとか使ってもいいんですが、せっかくServerless.Templateを用意してCloudFormationで構築できるようにしてくれているので、そちらを改造してデプロイ時に作ってしまえばらくだなーって思ったんですね。
環境
IDE:VisualStudio 2022
AWS .NET Serverless Framework C#
(minimalAPI or .NET CORE API)
.NET 6
OS Windows 10 Pro
Serverless.Template
テンプレートはデフォルトで生成されるものを少しいじった程度です。
名前と時間帯だけ変更すればそのまま使えると思います。(多分)
今回はHTTP APIでAPI GateWayが作成されるのでその辺変えてます。
ちなみにAuto Scalingは朝9時にスケールアウトして、夜9時にスケールインします。
{
"AWSTemplateFormatVersion": "2010-09-09",
"Transform": "AWS::Serverless-2016-10-31",
"Description": "An AWS Serverless Application that uses the ASP.NET Core framework running in Amazon Lambda.",
"Parameters": {},
"Conditions": {},
"Resources": {
"AspNetCoreFunction": {
"Type": "AWS::Serverless::Function",
"Properties": {
"AutoPublishAlias": "test",
"ProvisionedConcurrencyConfig":
{
"ProvisionedConcurrentExecutions": 1
},
"Handler": "<Your Application Name>::<Your Application Name>.LambdaEntryPoint::FunctionHandlerAsync",
"Runtime": "dotnet6",
"CodeUri": "",
"MemorySize": 256,
"Timeout": 30,
"Role": null,
"Policies": [
"AWSLambda_FullAccess"
],
"Events": {
"ProxyResource": {
"Type": "HttpApi",
"Properties": {
"Path": "/{proxy+}",
"Method": "ANY"
}
}
}
}
},
"ScalableTarget": {
"Type": "AWS::ApplicationAutoScaling::ScalableTarget",
"Properties": {
"MaxCapacity": 10,
"MinCapacity": 0,
"ResourceId": { "Fn::Sub" : "function:${AspNetCoreFunction}:test" },
"RoleARN": { "Fn::Sub":"arn:aws:iam::${AWS::AccountId}:role/aws-service-role/lambda.application-autoscaling.amazonaws.com/AWSServiceRoleForApplicationAutoScaling_LambdaConcurrency" },
"ScalableDimension": "lambda:function:ProvisionedConcurrency",
"ScheduledActions": [
{
"ScalableTargetAction": {
"MaxCapacity": 5,
"MinCapacity": 5
},
"Schedule": "cron(0 0 * * ? *)",
"ScheduledActionName": "scale-out"
},
{
"ScalableTargetAction": {
"MaxCapacity": 0,
"MinCapacity": 0
},
"Schedule": "cron(00 12 * * ? *)",
"ScheduledActionName": "scale-in"
}
],
"ServiceNamespace": "lambda"
},
"DependsOn": ["AspNetCoreFunctionAliastest"]
}
},
"Outputs": {
"ApiURL": {
"Description": "API endpoint URL for Prod environment",
"Value": {
"Fn::Sub": "https://${ServerlessHttpApi}.execute-api.${AWS::Region}.amazonaws.com/Prod/"
}
}
}
}
苦戦したとこ DependsOnの値
ここの値の部分はなかなか苦労しました。
・ネットで調べてもyml形式が多く、jsonではなかった。
・配列形式ではなく、単純なstringで書かれていたこと
・【AspNetCoreFunction(任意の名前)+Alias+"AutoPublishAlias"で指定したエイリアス】
というのがなかなかわかりにくかったですね。ChatGPTに聞けば早かったかも、、、。
"DependsOn": ["AspNetCoreFunctionAliastest"]
もし、"AutoPublishAlias"の値が"provisioned"であれば以下のようになります。
"DependsOn": ["AspNetCoreFunctionAliasprovisioned"]
もちろんそれに応じて、以下のようにResourceIdを変更する必要性があります。
"ResourceId": { "Fn::Sub" : "function:${AspNetCoreFunction}:provisioned" },
残念な部分
どうもSAMで構築すると1台はProvisioned Concurrencyの設定をしないとだめそうです。
具体的には以下の部分なんですけど、ここは0ではダメでした。参考記事も1でやってます。
"ProvisionedConcurrencyConfig":
{
"ProvisionedConcurrentExecutions": 1
}
参考もと
Serverless FrameworkでLambda Provisioned ConcurrencyのAutoScalingを実装する
Sample AWS SAM Template using Provisioned Concurrency with Application Auto Scaling
次回はAPiGatetway周りいじります。