Provisioned Concurrency は、Lambda 関数を常にクラウド上に起動させておく機能です。Amplify はこの機能をサポートしていませんが、CloudFormation ファイルをカスタマイズすることで Provisioned Concurrency の生成を自動化することができます。この記事では、Provisioned Concurrency にまつわる Amplify 特有の設定方法を紹介します。例えば
- プロダクション環境のみに Provisioned Concurrency を設定するには?
- Lambda トリガーや AppSync から Povisioned Lambda 関数を実行するには?
などです。それでは早速ごらんください!
なお、この記事は以下の自分の技術記事の日本語訳です。
CloudFormation の設定
Provisioned Concurrency では、CloudFormation ファイルに Alias と Version と呼ばれる 2 つの設定の追加が必要です。Provisioned Concurrency は、Version を持つ Lambda 関数にのみ設定できます。Version を持たない場合、$Latest という値がデフォルトについきますが、これには追加できません。Alias は Provisioned Concurrency の名前で、他のリソースから呼ぶ際に使います。後述しますが、複数の Provisioned Concurrency を定義して、ユースケースに応じて切り替えられます。
まずは最も単純な Provisioned Concurrency の例です。
{ ... "Resources": { "LambdaFunction": { ..., "Properties": { "ReservedConcurrentExecutions": 10, } }, "LambdaVersion": { "Type": "AWS::Lambda::Version", "DeletionPolicy": "Retain", "Properties": { "FunctionName": { "Ref": "LambdaFunction" } } }, "ProvisionedConcurrencyLambdaAlias": { "Type": "AWS::Lambda::Alias", "Properties": { "FunctionName": { "Ref": "LambdaFunction" }, "FunctionVersion": { "Fn::GetAtt": [ "LambdaVersion", "Version" ] }, "Name": "provisioned", "ProvisionedConcurrencyConfig": { "ProvisionedConcurrentExecutions": 10 } }, "DependsOn": "LambdaFunction" },
この例では、10 のインスタンスを Provisioned Concurrency 用に設定しました。
Provisioned Concurrencyに合わせてConcurrentに実行できるインスタンスを制約する ReservedConcurrentExecutions
も追記しています。ReservedConcurrentExecutions
は Properties
セクションで設定し、ProvisionedConcurrentExecutions
よりも大きい値にする必要があることに注意してください。
以下のコマンドを実行して、このアップデートをクラウドに反映します。
amplify push
プロダクション環境にのみ Concurrency を適用する
場合によっては、Provisioned Concurrency をプロダクション環境だけに適用して、コストを削減したいことがあります。そのためには、Conditions
リソースを追加する必要があります。
"Conditions": { ... "CreateProdResources": { "Fn::Equals": [ { "Ref": "env" }, "production" ] }
そして ProvisionedConcurrencyConfig
に以下を追加します。
"ProvisionedConcurrencyConfig": { "Fn::If": [ "CreateProdResources", { "ProvisionedConcurrentExecutions": 2 }, { "Ref": "AWS::NoValue" } ] }
amplify push
を実行すると、Production 以外の環境では Provisioned Concurrency や alias が表示されなくなります。
Lambda Trigger の設定
次に、Lambda Trigger に Provisioned Concurrency を適用する方法を見てみます。何も設定しないと、Lambda Trigger(DynamoDB のイベントストリームなど)は$LATEST
バージョンの Lambda 関数に接続されるため、Provisioned Concurrency は利用できません。ここで必要となるのが、Event Source Mapping の更新です。Event Source Mapping は、Lambda 関数が接続されるソースを定義します。
以下のコードは、AppSync による DynamoDB 上の Photo Table のイベントソースマッピングを表しています。なお GraphQLAPIIdOutput
は AppSync 構築時に生成される API アドレスです。
"LambdaEventSourceMappingPhoto": { "Type": "AWS::Lambda::EventSourceMapping", "DependsOn": [ "LambdaTriggerPolicyPhoto", "LambdaExecutionRole" ], "Properties": { "BatchSize": 100, "Enabled": true, "EventSourceArn": { "Fn::ImportValue": { "Fn::Sub": "${GraphQLAPIIdOutput}:GetAtt:PhotoTable:StreamArn" } }, "FunctionName": { "Fn::GetAtt": [ "LambdaFunction", "Arn" ] }, "StartingPosition": "LATEST" } },
ここで Event Source が Provision された Lambda を見るように、provisioned
というエイリアスを追加します。
"FunctionName": { { "Fn::Join": [ "", [ { "Fn::GetAtt": [ "LambdaFunction", "Arn" ] }, ":provisioned" ] ] }, ] },
ちょっとした落とし穴があって、まずクラウド上にエイリアスリソース(ここではProvisionedConcurrencyLambdaAlias
)を作成してください。Alias リソースが生成されないと、イベントソースマッピングの作成時に Function does not exist というエラーが発生します。
"Invalid request provided: Function does not exist (Service: Lambda, Status Code: 400, Request ID: 4c899598-b74a-4b71-b4df-2821e4c6098a, Extended Request ID: null)"
Provisioned Concurrency を Production にのみ適用するには、Conditions
リソースで定義したCreateProdResources
を使用します。
"FunctionName": { "Fn::If": [ "CreateProdResources", { "Fn::Join": [ "", [ { "Fn::GetAtt": [ "LambdaFunction", "Arn" ] }, ":provisioned" ] ] }, { "Fn::GetAtt": [ "LambdaFunction", "Arn" ] } ] },
参考:
AWS::Lambda::EventSourceMapping - AWS CloudFormation
AppSync の設定
Provisioned Concurrency を AppSync に設定したいケースもあります。AppSync GraphQL には @function
ディレクティブがあり、Lambda 関数を Query や Mutation に直接接続することができます。Provisioned Concurrency を適用するには、関数名に Alias を渡します。
type Mutation { createPhoto(...): Result @function(name: "createPhoto-${env}:provisioned")
残念ながら、@function
はAWS::NoValue
をサポートしていません。そのため、Lambda 関数や Lambda Trigger で Provisioned Concurrency を本番環境に設定したのと同じ方法を取ることはできません。今のところ最小値を設定するしかないようです。
"ProvisionedConcurrencyConfig": { "ProvisionedConcurrentExecutions": { "Fn::If": [ "CreateProdResources", 10, 1 ] } }
Amplify で Provisioned Concurrency を設定するためのあれこれについて紹介しました。Amplify はまだ進化している技術なので、将来的には Concurrency を Amplify から直接定義できるようになることを期待しています。