【初心者向け】AWS Lambda について改めて整理してみた
AWS Lambda
はじめに
本ページは、AWS に関する個人の勉強および勉強会で使用することを目的に、AWS ドキュメントなどを参照し作成しておりますが、記載の誤り等が含まれる場合がございます。
最新の情報については、AWS 公式ドキュメントをご参照ください。
Contents
AWS Lambda とは
Duration: 4:01:22
サーバーをプロビジョニングまたは管理せずにコードを実行できるようにするコンピューティングサービスです。FaaS(Function as a Service:ファース、エフアース)に分類されるサービスです。
【AWS Black Belt Online Seminar】AWS Lambda Part1(YouTube)(1:02:22)
【AWS Black Belt Online Seminar】AWS Lambda Part2(YouTube)(1:01:17)
【AWS Black Belt Online Seminar】AWS Lambda Part3(YouTube)(1:01:15)
【AWS Black Belt Online Seminar】AWS Lambda Part4(YouTube)(56:28)
チュートリアル: Amazon S3 トリガーを使用して Lambda 関数を呼び出す
チュートリアル: API Gateway で Lambda を使用する
チュートリアル: スケジュールされたイベントでの AWS Lambda の使用
ネットワーク
Duration: 0:01:00
Lambda は Lambda サービスが所有する VPC 内で実行されています。
Lambda を自 VPC に接続すると、Lambda サービスの VPC と自VPC を接続するために Hyperplane ENI(Elastic Network Interface)を作成し、関数に割り当てます。
実行環境
Duration: 0:01:30
安全で分離されたランタイムを実行するための環境で、実行環境のライフサイクルは次のようになっています。
- 通常
- INIT(初期化) → INVOLE(呼び出し) → SHUTDOWN(シャットダウン)
- SnapStart を利用している場合
- RESTORE(復元) → INVOLE(呼び出し) → SHUTDOWN(シャットダウン)
コールドスタート問題
生成された Lambda 関数インスタンスは、一定時間後に消失します。消失するまでの間は実行環境が再利用されることがありますが、そうでない場合は、初期化から開始します。
実行頻度が低い関数の実行時に毎回起動時間がかかってしまうことです。
- コンパイルが必要な言語で作成された関数は、コンパイル時間も毎回必要になります。
- 「プロビジョニングされた同時実行」という機能がなかったときは、定期実行をして、コールドスタートの発生確率を下げる方法でした。
- 「プロビジョニングされた同時実行」にすることで、予めプロビジョニングされた状態にできます。ただし、Lambda の特徴である「関数が実行された時間だけ」課金されるメリットが失われ、「プロビジョニングされていた時間」の課金となります。
- VPC Lambda は ENI の起動が必要になるため遅い。
- ENI は作成までに 10秒以上かかることがある
- 2019/09 以前は、関数ごとに ENI が作成されており、実行環境がスケールしてリクエストが増加するにつれて、多くの ENI が作成されるようになっていました。ENI 数に比例して サブネットに割り当てた IP アドレスを消費してしまいます。
- 現在は、事前に作成した 共通利用する ENI を利用して VPC に接続しているため ENI の作成に関する問題は解消されました。
SnapStart for Java
Lambda の起動時のレイテンシー(主に、コールドスタート時間)の最大要因は関数の初期化です。
それを解消するために、関数のバージョンを発行するときに関数を初期化し、その実行環境(メモリとディスク状態)のスナップショットをキャッシュさせ、キャッシュさせたスナップショットから実行環境を再開することで起動時のレイテンシーが短縮される機能です。
SnapStart の使用に追加コストは発生しませんが、利用するには以下の制約があります。
- サポートしているのは、
Java 11
のみ - エフェメラルストレージのサイズが512 MB 以下
- プロビジョニングされた同時実行ではない
- arm 64 アーキテクチャではない
- EFS を利用していない
- X-Ray を利用していない
命令セットアーキテクチャ
Duration: 0:00:30
- arm64 — AWS Graviton2 プロセッサ用の 64 ビット ARM アーキテクチャ
- アームろくよん
- x86_64アーキテクチャより34%のコスト効率よく利用できる
- 実際のコストは 東京リージョンでは 20%ほど低い。
- 利用できる場合は、こちらを選ぶ。
- x86_64 — x86 ベースプロセッサ用の 64 ビット x86 アーキテクチャ
- エックスはちろく・ろくよん
それぞれの違いは、このあたりを参考に。
ARM と x86:その違い:https://www.redhat.com/ja/topics/linux/ARM-vs-x86
Lambda のアクセス権限
Duration: 0:01:00
Lambda のアクセス権限には、IAM ロール(=実行ロールと呼ばれます。ロールの中には、IAMポリシーが含まれます)とリソースベースのポリシーがあります。
実行ロールでは、Lambda 関数が他のリソースにアクセスできる権限や実行をまかせるための信頼ポリシーを記述するロールで、Lambda 関数を作成する際には必ず付与します。
リソースポリシーでは、どのサービスやアカウントが Lambda 関数を呼び出せるかを記述します。後述する Push モデルのトリガー(S3, CloudWatch など)を使用する場合に指定します。
Key | IAM ポリシー | リソースポリシー |
---|---|---|
Resource | 適用対象のリソースのARN | 適用対象のリソースのARN |
Action | オペレーション | オペレーション |
Effect | Allow or Deny | Allow or Deny |
Principal | × | 権限を受け取りたいエンティティ(サービス、アカウント、ユーザ) |
トリガー
Duration: 0:01:30
Pull モデルと Push モデルがあります。
Pull モデル
Pull モデルは、ポーリング型の実行です。Lambda のイベントソースマッピングで指定されたイベントソースをポーリングして読み取りを行うものです。イベントが一度ストリームまたはキューに格納されるので、処理順序が保証されています。
以下のサービスとの連携が対象です。
- Amazon DynamoDB
- Amazon Kinesis
- Amazon MQ
- Amazon Managed Streaming for Apache Kafka (Amazon MSK)
- セルフマネージド Apache Kafka
- Amazon Simple Queue Service (Amazon SQS)
Push モデル
Push モデルは、イベント駆動型の実行です。Lambda がイベントソースから直接呼び出されるものです。発生したイベントの実行順序は保証されていません。発生したイベントの順番に処理される場合もありますし、タイミングによっては前後する場合もあります。
イベントソースとなるサービスによって、Lmabda の呼び出しタイプ(同期、非同期)が決まっています。
主に以下のようなサービスがあります。
- Amazon S3(非同期)
- Amazon CloudWatch(非同期)
- Amazon SNS(非同期)
- Amazon Cognito(同期)
- Amazon API Gateway(同期)
呼び出しタイプ
Duration: 0:01:30
AWS SDK や CLI から実行する際に、InvocationType
を指定することでコントロールできます。
-
RequestResponse
- デフォルト
- 同期実行
- 直接 Lambda を1回実行し、処理が完了したらレスポンスが返ってきます。
aws lambda invoke --function-name hoge-function \ --payload .... response.json # Response { "StatusCode": 202, "ExecutedVersion": "$LATEST", "FunctionError": "...." }
-
Event
- 非同期実行
- Lambda の実行はキューイングされます。
- キューイングされたタイミングでレスポンスが返ってきます。
- 失敗した場合自動的に2回までリトライされます。
- DLQ(デッドレターキュー)で、失敗した場合の設定が行えます。
aws lambda invoke --function-name hoge-function \ --invocation-type Event --payload .... response.json # Response { "StatusCode": 202 }
-
DryRun
- 関数を実行しないで必要な権限が付いているか確認できます。
aws lambda invoke --function-name hoge-function \ --invocation-type DryRun --payload .... response.json # Response { "StatusCode": 204, "FunctionError": "...." }
対応ランタイム
Duration: 0:01:30
- Node.js
- 18,16,14,12
- 非推奨:12 (2023-3-31)
- Python
- 3.9,3.8,3.7
- Java
- 11,8
- .NET Code
- 非推奨:3.1 (2023-4-3)
- .NET
- 6,5
- Go
- 1
- Ruby
- 2.7
- カスタムランタイム
ランタイムの非推奨化は、2つのフェーズで発生します。
- フェーズ1
- ランタイムに対するセキュリティパッチの更新停止
- 既存関数は更新可能
- 新規関数は作成不可
- フェーズ2
- フェーズ1から少なくとも30日経過したものがフェーズ2になる
- Python 3.6 の場合、非推奨フェーズ1(2022-7-18)→フェーズ2(2022-8-29)
- 新規関数、既存関数ともに作成、更新不可
- ただし、既存関数は継続して実行可能
- サポートされているランタイムに移行が必要
- フェーズ1から少なくとも30日経過したものがフェーズ2になる
サポート終了がスケジュールされている場合、60日以内なったら Eメールで通知が来るようになります。
また、Trusted Advisor では、非推奨となる120日の前チェックが出来ます。
Layer
Duration: 0:01:00
Lambda 関数で使用するライブラリとその他の依存関係をパッケージ化できる機能です。関数には最大で 5つのレイヤーを含めることができます。
レイヤーを使用することで、デプロイパッケージのサイズを削減し、デプロイスピードを速めることができます。
デプロイパッケージ
Duration: 0:03:00
関数をデプロイするには、関数コードと依存関係を含む .zip ファイルまたは、Open Container Initiative (OCI) の仕様に準拠したコンテナーイメージでデプロイできます。
Lambda 関数を作成するには、次の方法があります。
- コンソール上でコードを記述
- CloudFormation
- AWS CDK
- AWS SAM
コンソール
CloudFormation
CLoudFormation で関数をデプロイするには、次の方法があります。
-
S3 バケットにコードの .zip ファイルをアップロードする
Resources: Function1: Type: AWS::Lambda::Function Properties: Code: S3Bucket: !Ref S3Bucket S3Key: !Ref S3Key Environment:
-
CloudFormation の YAML ファイルにインラインで記述する(コードの依存関係がない場合のみ)
Resources: Function2: Type: AWS::Lambda::Function Properties: Code: ZipFile: | import boto3 import json import os def lambda_handler(event, context): :
-
コンテナイメージから
Resources: Function3: Type: AWS::Lambda::Function Properties: Code: ImageUri: !Ref ImageUri
AWS CDK
const Function1 = new lambda.Function(
this,
'Function1',
{
functionName: "Function1",
description: 'comment....',
code: lambda.Code.fromAsset(
path.join(__dirname, `${srcLambdaDirBase}/hello_world`)
),
handler: 'index.lambda_handler',
runtime: lambda.Runtime.PYTHON_3_9,
timeout: cdk.Duration.seconds(300),
architecture: lambda.Architecture.ARM_64,
environment: {
LOG_LEVEL: props.lambdaLogLevel ?? 'INFO',
:
},
role: xxxx,
tracing: lambda.Tracing.ACTIVE,
}
);
AWS SAM
AWS Serverless Application Model (AWS SAM) でデプロイするには次のようにします。
Function1:
Type: AWS::Serverless::Function
Properties:
CodeUri: hello_world/
Handler: app.lambda_handler
Runtime: python3.9
Architectures:
- arm64
エフェメラルストレージ(一時領域)
Duration: 0:00:30
AWS Lambda で最大 10 GB のエフェメラルストレージをサポート可能に
512 MB ~ 10 GB まで /tmp
領域を作成できます。
同時実行
Duration: 0:00:30
ある時点で実行されているリクエストの数のことです。
Lambda関数の同時実行数は同一アカウントの同一リージョン内につき、1,000に制限されています。
Lambdaの同時実行数の計測は以下のように考えます。
同時実行=(1秒あたりの呼び出し数)x(平均実行時間(秒))
Lambda関数が平均10秒かかり、1秒あたり100個のイベントを発行するとLambda関数を1000同時に実行することになり、制限ぎりぎりとなります。
Qualifier
Duration: 0:01:00
関数を呼び出す場合のバージョン(my-function:1)やエイリアス(my-function:BLUE)を指定できます。
エイリアス作成時にWeighted alias (加重エイリアス)
を指定することで、リクエストの振り分けに重みをつけることができます。
ほとんどのトラフィックを既存バージョンに振り分けて一部のトラフィックを新しいバージョンに振り分けるといったことができます。これにより、新しいバージョンを展開するリスクを軽減できます。
関数 URL
Duration: 0:01:00
関数を呼び出すための HTTPS エンドポイントが作成できます。
APIGateway を作成しなくても、HTTPS の URL を利用することができます。
https://<url-id>.lambda-url.<region>.on.aws
このエンドポイントには、IAM 認証も付けることができます。
IAM 認証を付けた場合は、AWS Signature Version 4 (SigV4)
による署名が必要です。詳しくは下記ドキュメントを参照してください。
モニタリング
Duration: 0:01:30
監視するメトリクスとしては次のようなものがあります。
- Invocations
このメトリクスは監視間隔として300秒(5分)若しくは60秒(1分)を設定してください。監視の際には、stasticsとして「Sum」を利用することを推奨します。 - Errors
このメトリクスは監視間隔として300秒(5分)若しくは60秒(1分)を設定してください。監視の際には、stasticsとして「Sum」を利用することを推奨します。 - Throttles
このメトリクスは監視間隔として300秒(5分)若しくは60秒(1分)を設定してください。監視の際には、stasticsとして「Sum」を利用することを推奨します。
その他、Lambda 関数のメモリをモニタリングするしたい場合は、次のドキュメントを参照します。
ベストプラクティス
Duration: 0:01:00
主なベストプラクティスは次の通りです。
- Lambda ハンドラーをコアロジックから分離
-
lambda_handler
の中にロジックを全て記述しないで、メソッド分割する。 - 単体テストがしやすい、コードの可読性が向上する、など。
-
- ランタイムを必要最低限にしてサイズを小さく
- 起動時間にも影響するので最小限に
- レイヤー使う
- 共通化しよう
- 再帰呼び出しを行わない
- 位置しない処理で料金が急増するリスクがあるため
- 環境変数を使う
- ハードコーディングしない。
- 冪等性のコード
- Lambda が重複して実行されることも考慮しておく。
クォータ
Duration: 0:00:30
主に、同時実行数を引き上げたいなど。
Discussion