はじめに
builders.flash 読者の皆さん、こんにちは ! AWS のシニアテクニカルトレーナー 野邊 (のべ) です。
今回は AWS Lambda 関数の実行の仕組みをテーマに、主に初学者の方向けに解説していきます !
私は初学者の方向けに AWS Lambda を解説する時、後述の目次の順番で説明するようにしています。目次のうち、1 から 3 は、AWS Lambda の概要と基本のお話ですので、そのあたりはすでに知ってるよ ! という方は、4 から読んで頂いても大丈夫です !
なお、今回の記事のタイトルの中で「AWS Lambda 関数」という言葉を使ってますが、記事の本文では用語として次のように使っていきますので、あらかじめ確認しておいて下さい!
AWS Lambda : サーバーを意識せずにコードを実行できる AWS のサーバーレスコンピューティングサービス
Lambda 関数 : AWS Lambda によって管理、実行されるアプリケーションのコードとその設定
また、今回の記事に掲載しているスライドは、あくまで筆者のテクニカルトレーナーとしてのネタ帳の一部であり、AWS の有償トレーニングのテキストからの抜粋ではないことを念のためお伝えしておきます !
builders.flash メールメンバー登録
builders.flash メールメンバー登録で、毎月の最新アップデート情報とともに、AWS を無料でお試しいただけるクレジットコードを受け取ることができます。
1. サーバーレスコンピューティングとは
まずアプリケーションを実行する環境について考えてみましょう。
次の図は、自分たちでサーバーを用意してアプリケーションの実行環境を構築しています。
図で示されているように、自分たちでサーバーを用意してアプリケーションの実行環境を構築する場合は、そのサーバーの運用管理も自分たちで行っていく必要があります。また、アプリケーションを実行するために必要な ミドルウェア のインストールや構成も自分たちで行う必要があります。

サーバーレスコンピューティングの場合の図
では、サーバーレスコンピューティングの場合はどうなるのでしょうか ?
次の図をみてみましょう。
図で示しているように、サーバーレスコンピューティングの場合は、サーバーのプロビジョニングやその後の運用管理、ミドルウェアの構成などは、クラウドサービスの機能でカバーされるため、利用者はアプリケーションの開発にリソースを集中させやすくなるメリットがあります。
また、サーバーレスコンピューティングでは基本的にサーバーが動いている時間ではなく、アプリケーションが実行された時間に対して支払いが発生します。つまり、アプリケーションがアイドル状態の時間に対して支払いを行う必要がないのも特長の一つになります。
このサーバーレスコンピューティングを実現するための代表的なサービスが AWS Lambda です。

2. AWS Lambda の全体像
では次に、AWS Lambda にフォーカスしていきましょう。AWS Lambda では Lambda 関数をアプリケーションとして実行できます。次の図を見てみましょう。
この図のように、開発者は Lambda 関数として実行するコードを用意し、そのコードの実行に関する設定を行います。また、複数の Lambda 関数で共通的に使用するパッケージやライブラリを Lambda レイヤーとして切り出すことができます。
作成した Lambda 関数は、様々なイベントによって呼び出すことができます。このイベントの発行元のことをイベントソースといいます。

Lambda 関数を呼び出すイメージ
次の図では、いくつかのイベントソースを例に Lambda 関数を呼び出すイメージを表しています。
この図のように、イベントソースによって同期的、非同期的、またはポーリングによって呼び出されるのかが異なります。この図以外のサービスについては、AWS Lambda のドキュメントの「他のサービスで AWS Lambda を使用する」に記載がありますので、興味があればご参照ください。
また、AWS Lambda と他のサービスとを組み合わせたユースケースやパターンについては「形で考えるサーバーレス設計」にまとめられています。さらに「サーバーレスアプリケーション開発におけるエラーハンドリング」ではエラーハンドリングのパターンやベストプラクティスについてもわかりやすく解説されていますので、これらも参考にしてみてください !

3. シンプルな Lambda 関数のコードの例
次に Lambda 関数のコードについてみてきましょう。AWS Lambda は下記のランタイムをサポートしており、これらのランタイムで実行できるコードを使用して Lambda 関数を作成できます。
Python
Node.js
Java
.NET
Ruby
Go
またカスタムランタイムを作成することで、上記以外のプログラミング言語を使用して Lambda 関数を作成できます。
Python で記述した シンプルな Lambda 関数のコード
例として Python で記述した シンプルな Lambda 関数のコードをみてみましょう。
lambda_handler について
このコードでは lambda_handler という名前の Python の関数が定義されています。これは、この Lambda 関数におけるハンドラーになります。ハンドラーは、Lambda 関数が呼び出された時に最初に実行されるエントリーポイントです。ハンドラーとなる関数名またはメソッド名は、Lambda 関数の設定として指定する必要があります。
ハンドラーとなる関数またはメソッドは、イベントオブジェクトとコンテキストオブジェクトを引数として受け取る形にする必要があります。これらの引数のオブジェクトは、実行時に AWS Lambda により渡され、コードの中で参照できます。
イベントオブジェクト
Lambda 関数に処理させたいデータや、イベントソースから渡されたデータを含んでいます。
例えば、Amazon S3 バケットにオブジェクトが Put されたイベントにより Lambda 関数が実行された場合は、その S3バケット名やオブジェクトのキーなどが含まれます。
コンテキストオブジェクト
ランタイムの環境の情報が含まれています。
例えば Lambda 関数の名前や Amazon リソースネーム (ARN) 、設定されている メモリ容量などが含まれています。
JSON 形式のデータをイベントオブジェクトに指定して実行
AWS マネジメントコンソールや AWS CLI を用いて、任意のイベントオブジェクトを指定して Lambda 関数を実行できます。上記のサンプルの Lambda 関数に、次の JSON 形式のデータをイベントオブジェクトに指定して実行してみます。
結果
すると、Lambda 関数が次のような結果を戻します。
ハンドラーのコードを記述する際のポイント
この結果から、サンプルの Lambda 関数のハンドラーの 2 行目の event['first_name'] や event['last_name'] で イベントオブジェクトからデータを読み取れていることが確認できますね。
ハンドラーのコードを記述する上で、下記の 2 つをおさえておきましょう。
ハンドラーの実行時間は最長 15 分まで
1 回の呼出しにより 15 分を超えるような処理の場合、AWS Lambda の関数としては適用ができないため、処理を分割するか、もしくは AWS Lambda 以外のサービスをご検討ください。「コンテナとサーバレスの使い分け」の資料も参考になりますので、ご参照ください !
ハンドラーの関数やメソッド内に全てのコードを記述する必要はない
ハンドラーはあくまで Lambda 関数のコードの中で最初に実行する関数またはメソッドであり、その中にすべてのコードを記述する必要はありません。上記のサンプルのように短いコードであれば別ですが、必要に応じてハンドラーから他の関数を呼び出したり、他のオブジェクトのメソッドを呼び出すような設計にしましょう。そうすることで、コードの可読性を向上でき、関数やメソッド単位の単体テストも実施しやすくなります。
4. Lambda 関数の実行の仕組み
4-1. Lambda 関数の実行環境のライフサイクル
では、AWS Lambda において Lambda 関数が実行される仕組みをみていきましょう !
次のアニメーションは、Amazon API Gateway と Lambda 関数 を統合している環境を例に、Lambda 関数が呼び出された時の動きを示したものです。

このアニメーションから、Lambda 関数の実行環境は呼出しに応じて自動的に用意されることがわかりますね。
ただし、Lambda 関数を作成・更新した直後では、まず実行環境が作成され、初期化処理を経てハンドラーが実行されます。このような流れで Lambda 関数が実行されることを、一般的に「コールドスタート」と呼びます。ハンドラーのコードを実行する以外に、実行環境を作成して初期化処理を行う時間が必要になるので、その分のレイテンシーが発生することを把握しておきましょう。
コールドスタートを経て Lambda 関数の実行環境が作成されますが、作成されハンドラーが実行された後も、その実行環境はすぐには削除されず、残っています。次のアニメーションをご覧ください。

このアニメーションのように、実行環境が残っている期間内に再び同じ Lambda 関数を呼び出すと、その環境が再利用されることがあります。再利用された場合は、実行環境も作成済で初期化処理も完了しているので、ハンドラーだけが実行されます。 このような流れで Lambda 関数が実行されることを、一般的に「ウォームスタート」と呼びます。ウォームスタートの場合は、コールドスタートと比較すると実行環境作成や初期化処理は必要ないので、その分処理時間を短縮できます。
コールドスタートとウォームスタートは、「お風呂に最初に入る」か「2 番目以降に入る」かで例えるとわかりやすいかもしれません。お風呂に最初に入る場合は、湯船に湯がためて適温になるまで待つ必要がありますが、 2 番目に入る人はすでに湯船に適温のお湯があるので、待たずにそのまま入れますよね。
さて、実行環境は最終的にどうなるのでしょう ? 次のアニメーションをご覧ください。

実行環境を使わない状況が続くと、いずれ AWS Lambda サービスより不要と判断され、シャットダウン処理を経て自動的に実行環境が削除されます。その後、再び呼び出されるとコールドスタートを経て実行環境が作成される、というライフサイクルを繰り返します。
4-2. Lambda 関数の実行環境のスケーリング
次に同じ Lambda 関数で複数の呼び出しが発生した場合の動作をアニメーションでみてみましょう。

このアニメーションが示しているように、AWS Lambda は Lambda 関数の呼び出し数や、現在使用中の実行環境の数に応じて、自動的に実行環境の数を増やします。
ただし、すでにコールドスタートを経て実行環境が複数残っている場合、同じクライアントが再び 同じ Lambda 関数を呼び出したとしても、前回と同じ実行環境が使用されるとは限りません。次のアニメーションをみてみましょう。

よって、Lambda 関数の実行環境内にセッションデータ (特定のクライアントの固有データ) を保存するべきではありません。つまり、Lambda 関数のコードはステートレスにする必要があることを理解しておきましょう !
4-3. 予約済同時実行数の設定
さて、これまでの説明で Lambda 関数の実行環境は自動的にスケーリングすることを、ご理解いただけたと思います。ただ、Lambda 関数の実行環境は無制限にスケールアウトで増やせるわけではありません。
AWS Lambda では サービスの制限値として、その AWS アカウントで同時に実行環境を作成できる数がリージョン毎に決められています。これは、AWS Service Quotas というサービスから AWS Lambda の Concurrent executions の値で確認できます。
この図は東京リージョンで表示したもので 1,000となっています。ただし、[調整可能] 列の値が [はい] になっているので、緩和申請は可能です。

予約済同時実行数
これはリージョン単位の値なので、例えば 東京リージョンに Lambda 関数を A, B, C と 3 つ作成した場合、その A, B, C の合計の同時実行数が 1,000 までということになります。
また、Lambda 関数単位で同時に作成できる実行環境数を設定できます。この設定は「予約済同時実行数」または「Reserved Concurrency」と呼ばれます。次のアニメーションをみてみましょう。

このアニメーションで示しているように、1 つの Lambda 関数に対して同時に多くのリクエストが発生し、設定した予約済同時実行数を超える場合は、超えた分はエラー (ステータスコード: 429 エラーコード: TooManyRequestsException) になります。この状態をスロットリングといいます。極端な例として、予約済同時実行数に 0 を設定すると、その Lambda 関数はいくらリクエストがきても、一切実行されないということになります。
また、東京リージョンの同時実行数がデフォルト 1,000 なので、例えば Lambda 関数 X の予約済同時実行数もそれに合わせて 1,000 にしておく、ということもできません。リージョン内のすべての Lambda 関数の予約済同時実行数の合計は、最大でリージョンの同時実行数 -100 の値までしか設定できません。つまり東京リージョンでいうとすべての Lambda 関数の予約済同時実行数の合計は 900 までしか設定できないので、注意しておきましょう。
4-4. Lambda 関数のバージョンとエイリアス
1 つの Lambda 関数に対して、複数のバージョンやエイリアスを作成できます。
次のアニメーションをご覧ください。

このアニメーションのように、Lambda 関数には $LATEST というデフォルトのバージョンがあり、コードの編集は常に $LATEST に対してのみ行います。その $LATEST から新しいバージョンを発行できます。ただし、発行されたバージョンのコードは変更できないので、注意しておきましょう。
また 、エイリアスを作成してバージョンと関連付けて使用できます。これにより、Lambda 関数の呼び出し元は常に特定のエイリアスだけを指定して Lambda 関数を呼び出せばよく、複数のバージョンの存在を意識する必要がなくなります。さらにエイリアスとバージョンの関連付けでは トラフィックの比重を設定できるので、次のアニメーションのように、新しいバージョンにはひとまず 10% にして確認し、問題がなければ 100% にするという運用も可能です。

4-5. プロビジョニングされた同時実行数の設定
さて、「4-1. Lambda 関数の実行環境のライフサイクル」のセクションでコールドスタートとウォームスタートの説明をしました。コールドスタートは、ウォームスタートと比較し、実行環境を作成して初期化処理を行う分のオーバーヘッドが発生していましたよね。コールドスタートが発生したタイミングとはいえ、このオーバーヘッドによるレイテンシーの遅延を避けたい場合はどうすればいいでしょうか ?
一つの対処法として、プロビジョニングされた同時実行数 (Provisioned Concurrency) を設定して、Lambda 関数の実行環境を事前に作成し、その数を維持するという方法があります。この設定は、Lambda 関数の特定のバージョンもしくはエイリアスに対して行います。
次のアニメーションをみてみましょう。

このアニメーションでは例として プロビジョニングされた同時実行数を 2 に設定しています。この設定により、Lambda 関数の実行環境が 2 つ作成され、その数は維持されます。作成されればコールドスタートが終わった状態になっているので、その後同時に 2 つの実行環境が必要になっても、ウォームスタートの状態からそれらのリクエストに対応できます。では、プロビジョニングされた同時実行数を超える実行環境が必要になった場合は、どうなるでしょう? もし他に実行環境がなければ、必要な分の実行環境が追加で作成されコールドスタートが発生しますが、既に起動済の実行環境があれば、それを使用してウォームスタートでリクエストに対応します。いずれにしても、リクエストに対処できないということはありません。
「4-1. Lambda 関数の実行環境のライフサイクル」のセクションでは、コールドスタートを「お風呂に入るときに湯船に湯がたまるまで待つ」と比喩で説明しましたが、このプロビジョニングされた同時実行数の設定は、同じように比喩で表現するなら、「いつでもすぐにお風呂に入れるように常に湯船に湯をはっておく」ということになります。
ただし、このプロビジョニングされた同時実行数の設定には注意点もあります。それはコストです。この設定を行うと Lambda 関数の実行環境が維持されている時間に対してもコストが発生することは十分留意しておいて下さい。詳細は、AWS Lambda 料金の Web ページの「Provisioned Concurrency 料金」のセクション に記述がありますので、ご参照ください。
なお、コールドスタート対策という観点では、 Lambda SnapStart という機能も知っておきましょう。これはコールドスタートの時間短縮を期待できる機能で、Lambda 関数のランタイムとして、この記事を執筆している 2023 年 7 月時点で Corretto の Java 11 と Java 17 がサポート されています。詳細は ドキュメントの「Lambda SnapStart による起動パフォーマンスの向上」や Amazon Web Services ブログの「SnapStart で AWS Lambda 関数の Java コールドスタートを削減する」をご参照ください。
5. まとめ
今回は AWS Lambda の初学者の方向けに AWS Lambda 関数の実行の仕組みをテーマに、以下のトピックについて説明しました。
1. サーバーレスコンピューティングとは
2. AWS Lambda の全体像
3. シンプルな Lambda 関数のコードの例
4. Lambda 関数の実行の仕組み
4-1. Lambda 関数の実行環境のライフサイクル
4-2. Lambda 関数の実行環境のスケーリング
4-3. 予約済同時実行数の設定
4-4. Lambda 関数のバージョンとエイリアス
4-5. プロビジョニングされた同時実行数の設定
これらのトピックは、AWS のドキュメントやトレーニングのテキストの文章や静的な図でも説明されています。ただし、文章や静的な図だけだと伝わりにくい部分もありますが、この記事のようにアニメーション GIF を使って「動き」も併せてご覧いただくことで、イメージを掴んでいただきやすいのではないかと思っております。
みなさんがこの記事で、 AWS Lambda などのサーバーレスのサービスについて、より理解と関心を深めていただけると嬉しいです !
もっと、AWS のサーバーレスについて学びたい!という方向けの学習パスとして、「サーバーレスの始め⽅」という資料もありますので、ぜひご参照ください !
筆者プロフィール
野邊 哲男
アマゾン ウェブ サービス ジャパン合同会社
AWS トレーニングサービス本部 シニアテクニカルトレーナー
自分が体験した「成功」と「失敗」、そこから「学んだこと」を皆さんにお伝えするべく、日々 AWS のトレーニングの登壇をしています。
最近は「仮面サーバーレス」として サーバーレスのトレーニング や デジタルトレーニング の情報を皆様にお届けしています。
