Open5

AWS Lambdaあれこれ

mocknmockn

Lambdaを手動実行する方法

AWS CLI

aws lambda invoke --function-name YourFunctionName --payload '{"key1": "value1", "key2": "value2"}' output.json
  • YourFunctionName: 実行したいLambda関数の名前に置き換えてください。
  • --payload: Lambda: 関数に渡すイベントデータをJSON形式で指定します。適切なデータを指定してください。
  • output.json: Lambda関数の実行結果が保存されるファイル名です。不要な場合は省略できます。
mocknmockn

S3へのファイルの作成・アップロード

大きなファイルサイズのファイル(100万件のCSVなど)を作成し、アップロードする場合は、StringIOメソッドを使用してCSVファイルを作成する。
アップロードはs3.put_object

mocknmockn

Provisioned Concurrency

Provisioned Concurrencyとは

  • AWS Lambda 関数が同時に処理できる未完了のリクエストの数のこと。
  • Lambdaの同時実行数を事前にプロビジョニングできる機能。
  • 設定した数のコンテナは常にウォームスタート状態になるため、コールドスタートをある程度防ぐことが可能。
  • 設定した数以上のリクエストが来ると、Lambdaは通常通りスケールアウトしてコンテナを起動する(コールドスタート)。

ユースケース

予測できるスパイクへの対処

  • 期間指定のキャンペーン。
  • EventBridge+Lambdaのスケジュール実行でProvisioned Concurrencyの設定値を変更する。

ColdStartの抑制

  • 認証認可のユーザー体験を良くするために低レイテンシーでレスポンスを返す。
  • Application Auto Scalingを使用して閾値に基づいてProvisioned Concurrencyの設定値を変更する。
  • リクエストの波に沿ったProvisioned Concurrencyの利用が可能になり、余分なコストが発生しなくなる。

AWS Lambdaのバースト制限の抑制

  • Provisioned Concurrencyのほかにバースト制限がある。
    • リクエスト数(デフォルト1000)
      • 1000を超えるとスケールに制限がかかる
    • スケールアップの勾配(500/分 コールドスタート)
  • バースト制限が緩和され、コールドスタートが緩和され、システムのレイテンシーが改善されます。

ベストプラクティス

デプロイ

  • Lambdaのversionかaliasを設定する必要がある。
  • AWS SAMの設定で安全にデプロイすることができる。
    • 新旧versionの入れ替え比率を指定できる。(トラフィックシフティング)
    • 一般的に環境ごとにAWSアカウントが異なるので、1環境あたり1aliasを設定し、常に最新versionを参照するように設定すれば良さそう。

実装

  • ハンドラー外で初期化処理や外部接続処理を実行
    • インスタンス化、DB接続など
    • 外部接続の場合はタイムアウトに注意
    • Globalでの初期化処理は同期的な処理系を採用すること
  • ハンドラー内でGlobalの初期化データを利用
  • Concurrency QuotaはAWSアカウント - リージョン単位で共有
    • デフォルト1000
    • 複数のLambdaのConcurrencyの合計が上限に収まるようにする必要がある
  • 暖気したいAPIが多数の場合はアーキテクチャ設計を見直す必要があるかも
  • Dispatch Pattern
    • 複数関数を共通Quota消費で暖機
    • モノリスになってしまうのでアーキテクチャ回避できないか検討する

設定方法

同時実行数の計算

計算式

Concurrency = (average requests per second) * (average request duration in seconds)

例)1 秒あたり 200 件のリクエストを受け取り、各リクエストの処理に250 ミリ秒かかる場合、同時実行数は50。

Concurrency = (200 requests/second) * (0.25 second/request) = 50

計算に必要な情報

  • 平均リクエスト数(数/秒)
  • 平均処理時間(秒)

計算例

  • 平均リクエスト数(数/秒):100
  • 平均処理時間(秒):
    Concurrency = (100 requests/second) * (0.25 second/request) = 50

制限

  • 上限 - 100 まで設定可能。デフォルトの上限はリージョンあたり1000のため、900までしか設定できない。

コスト

Lambdaの利用料式

Lambda利用の合計料金 = Provisioned Concurrency料金 + リクエスト料金 + コンピューティング料金
  • Provisioned Concurrencyを利用すると基本的に料金が上がる
  • Provisioned Concurrencyを利用すると無料枠が使用できない

対応方針

  • まずはProvisioned Concurrencyを利用しない方法を試す
  • スパイク対応などで暖機が必要な場合は部分的にProvisioned Concurrencyを利用する
  • 暖機が必要な関数が多い場合、アーキテクチャ設計の見直しやAWSアカウントやリージョンの分離やQuota制限の緩和を実施する。

設定方法

ポイント

  • Provisioned ConcurrencyはLambdaの特定のバージョンもしくはエイリアスに紐付ける必要がある。
  • 特定のバージョンにエイリアスを設定することができる。
  • 一つのエイリアスを複数のバージョンにまたがって設定できる。
  • デプロイ方法を最新バージョンに一気に切り替える(AllAtOnce)か徐々に切り替える(Canary10Percent30Minutes など)を検討し設定する。
    • バージョン切り替え時のコールドスタート抑制や切り戻し戦略に関係する。

Cfnテンプレート

AWS SAMの場合

AWSTemplateFormatVersion: '2010-09-09'
Transform: AWS::Serverless-2016-10-31
Resources:
  MyLambdaFunction:
    Type: AWS::Serverless::Function
    Properties:
      FunctionName: MyLambdaFunction
      Handler: index.handler
      Runtime: python3.8
      CodeUri: path/to/your/code
      AutoPublishAlias: live
      ProvisionedConcurrencyConfig:
        ProvisionedConcurrentExecutions: 5
      DeploymentPreference:
        Type: AllAtOnce # または Canary10Percent30Minutes など
  • エイリアスの設定が必須。
  • スッキリ書ける。

Cloud Formationの場合

AWSTemplateFormatVersion: '2010-09-09'
Resources:
  MyLambdaFunction:
    Type: AWS::Lambda::Function
    Properties:
      FunctionName: MyLambdaFunction
      Runtime: python3.8
      Role: arn:aws:iam::123456789012:role/lambda-role
      Handler: index.handler
      Code: path/to/your/code
      DeploymentPreference:
        Type: AllAtOnce # または Canary10Percent30Minutes など

  MyLambdaVersion:
    Type: AWS::Lambda::Version
    Properties:
      FunctionName: !Ref MyLambdaFunction

  MyProvisionedConcurrencyConfig:
    Type: AWS::Lambda::Version ProvisionedConcurrencyConfiguration
    Properties:
      FunctionName: !Ref MyLambdaFunction
      ProvisionedConcurrentExecutions: 5
      Qualifier: !GetAtt MyLambdaVersion.Version
  • エイリアスの設定は不要。
  • コードが冗長になるが柔軟な設定が可能。

まとめ

Provisioned Concurrencyはスケールアップやコールドスタート防止を気軽に行えるが、料金やQuoatにはねやすくサーバレスの強みを消しかねないので、仕様を理解したうえで極力部分的な利用に留めるべき。
多くの関数を暖機する必要がある場合、アーキテクチャの見直しを検討する必要がある。
平均リクエスト数や平均処理時間を正確に計測したうえで設定値を決めないと思ったパフォーマンスが出ず余計なコスト増につながる可能性もあるため、普段からアクセス数や関数の処理時間などのメトリクスには注意を払っておいた方が良さそう。

参考

https://speakerdeck.com/_kensh/aws-lambda-provisioned-concurrency-dive-deep-and-practice?slide=1
https://docs.aws.amazon.com/ja_jp/lambda/latest/dg/lambda-concurrency.html
https://docs.aws.amazon.com/ja_jp/lambda/latest/dg/provisioned-concurrency.html
https://dev.classmethod.jp/articles/lambda-provisioned-concurrency-coldstart/
https://qiita.com/_kensh/items/2c8c884d709e429d0993
https://dev.classmethod.jp/articles/simulate-provisioned-concurrency-cost/
https://zenn.dev/shimo_s3/articles/0263536627e377
https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/sam-property-function-deploymentpreference.html
https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/automating-updates-to-serverless-apps.html