こんにちは、夏の高校野球を見ながら(執筆期間中)高校は6、7年前か、年をとったなと感じてきました末廣です。
本ブログは、Lambda 関数を HTTP リクエストから呼び出せる 関数 URL を作成し、同機能を持つAPI Gateway と比較してみたり、こちらのブログで 調査してある Provisioned Concurrency を有効化してみたりしたものになります。
関数 URL の概要
公式ドキュメントより、関数 URL はLambda 関数のための専用 HTTP エンドポイントです。関数 URL を作成すると、 HTTP クライアントから URL に対して HTTP リクエストを送ることで Lambda 関数を実行することができます。 API Gateway を作成し、Lambda 関数のトリガーに設定することで同様に HTTP リクエストから Lambda 関数を実行できるので、関数 URL と比較して調査してみました。
やってみる
関数 URL の作成
今回はマネジメントコンソールからの作成をしていきます。
関数 URL を設定するには設定
から関数 URL
を選択し、関数 URL を作成します。
関数 URL を使用した Lambda の実行は IAM の認証、もしくはNONE
(認証なし)が選択できます。
マネジメントコンソールで関数 URL を作成する時にNONE
を選択すると、すべての認証されていないプリンシパル向けの関数 URL 呼び出しポリシーが自動で付与され、関数 URL がパブリックになるため、URL を知る人であれば誰でも Lambda 関数を実行することが可能になります。本ブログのように例を画像で示したりする場合は URL の情報には注意です。
AWS_IAM
を選択した場合は、関数 URL を呼び出すユーザにlambda:InvokeFunctionUrl
アクセスの許可が付与されており、URL に対する HTTP リクエスト に AWS Signature Version 4 (SigV4) による署名が必要になります。
以下で関数 URL が作成されたことが確認できます。
関数 URL へのアクセス
認証にNONE
を選択した場合、ブラウザから URL へアクセスする、cURL コマンドを実行するなど、URL には認証なしに HTTP リクエストを送信することでアクセスすることができます。
AWS_IAM
を選択した場合のアクセス方法として、AWS Signature Version 4 (SigV4) による署名に awscurl を使用したリクエストの例を示します。
まずは環境内で IAM 権限から awscurl を実行できるように設定を行います。関数 URL を実行することができるアイデンティティベースのポリシーをアタッチしたユーザを作成し、CLI で実行できるようにアクセスキーを発行します。
{ "Version": "2012-10-17", "Statement": [ { "Sid": "VisualEditor0", "Effect": "Allow", "Action": [ "lambda:InvokeFunctionUrl" ], "Resource": "arn:aws:lambda:ap-northeast-1:<accout-id>:function:<function-name>" } ] }
環境内でprofile 名を lambda-invoke
とし、awscurl コマンドを実行することで関数 URL から Lambda 関数を実行することができます。当然ですが、InvokeFunctionUrl
の権限のみしか付与されていなければ AWS CLI から aws lambda invoke
コマンドは実行できません。
$ awscurl \ --service lambda \ --region ap-northeast-1 \ --profile lambda-invoke \ https://<url-id>.lambda-url.ap-northeast-1.on.aws
API Gateway との比較
関数 URL と同様に HTTP リクエストから Lambda 関数を実行できる API Gateway との違いを見ていきます。
料金
わかりやすい大きな違いとして、関数 URL の料金は Lambda のリクエストと期間の料金に含まれるため、追加で料金はかかりません。
認証方法や機能
関数 URL へのアクセスの認証方法は、上記で試してみた IAM 方式のみしか対応しておらず、API Gateway で可能であるIAM 以外の Amazon Cognito や JWT を使用した認証には対応していません。また、フルマネージドに API の操作ができる API Gateway で可能なカスタムドメイン、キャッシュ、リクエスト・レスポンスの検証や変換、AWS WAF との組み合わせ、などの利用が関数 URL ではできません。
リクエストペイロード(イベントオブジェクト)の中身
ここから API Gateway を Lambda 関数のトリガーとして実際に設定して比較していきますが、API Gateway のエンドポイントは HTTP API を選択しています。
今回 Lambda 関数の言語は python で検証していますが、Lambda が関数ハンドラーを呼び出すと、event
という処理する Lambda 関数のデータを含む JSON 形式のドキュメントが引数として渡されます。その中身からペイロードを確認してみます。
※ 一部加工している箇所は <> で囲んでいます。
API Gateway の event
{ 'version': '2.0', 'routeKey': 'ANY/urlAndAPIGW', 'rawPath': '/default/urlAndAPIGW', 'rawQueryString': '', 'headers': { 'accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,*/*;q=0.8', 'accept-encoding': 'gzip,deflate,br', 'accept-language': 'ja,en-US;q=0.7,en;q=0.3', 'content-length': '0', 'dnt': '1', 'host': '<api-id>.execute-api.ap-northeast-1.amazonaws.com', 'sec-fetch-dest': 'document', 'sec-fetch-mode': 'navigate', 'sec-fetch-site': 'cross-site', 'sec-fetch-user': '?1', 'upgrade-insecure-requests': '1', 'user-agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10.15; rv:109.0) Gecko/20100101 Firefox/116.0' , 'x-amzn-trace-id': 'Root=<>', 'x-forwarded-for': '<my-ip>', 'x-forwarded-port': '443', 'x-forwarded-proto': 'https' }, 'requestContext': { 'accountId': '<accound-id>', 'apiId': '<api-id>', 'domainName': '<api-id>.execute-api.ap-northeast-1.amazonaws.com', 'domainPrefix': '<api-id>', 'http': { 'method': 'GET', 'path': '/default/urlAndAPIGW', 'protocol': 'HTTP/1.1', 'sourceIp': '<my-ip>', 'userAgent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10.15; rv:109.0) Gecko/20100101 Firefox/116.0' }, 'requestId': '<>', 'routeKey': 'ANY/urlAndAPIGW', 'stage': 'default', 'time': '15/Aug/2023:18:19:49+0000', 'timeEpoch': 1692123589315 }, 'isBase64Encoded': False }
関数 URL の event
{ 'version': '2.0', 'routeKey': '$default', 'rawPath': '/', 'rawQueryString': '', 'headers': { 'sec-fetch-mode': 'navigate', 'x-amzn-tls-version': 'TLSv1.2', 'sec-fetch-site': 'cross-site', 'accept-language': 'ja,en-US;q=0.7,en;q=0.3', 'x-forwarded-proto': 'https', 'x-forwarded-port': '443', 'dnt': '1', 'x-forwarded-for': '<my-ip>', 'sec-fetch-user': '?1', 'accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,*/*;q=0.8', 'x-amzn-tls-cipher-suite': '<>', 'x-amzn-trace-id': 'Root=<>', 'host': '<url-id>.lambda-url.ap-northeast-1.on.aws', 'upgrade-insecure-requests': '1', 'accept-encoding': 'gzip,deflate,br', 'sec-fetch-dest': 'document', 'user-agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10.15; rv:109.0) Gecko/20100101 Firefox/116.0' }, 'requestContext': { 'accountId': 'anonymous', 'apiId': '<url-id>', 'domainName': '<url-id>.lambda-url.ap-northeast-1.on.aws', 'domainPrefix': '<url-id>', 'http': { 'method': 'GET', 'path': '/', 'protocol': 'HTTP/1.1', 'sourceIp': '<api-id>', 'userAgent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10.15; rv:109.0) Gecko/20100101 Firefox/116.0' }, 'requestId': '<>', 'routeKey': '$default', 'stage': '$default', 'time': '15/Aug/2023:16:08:42+0000', 'timeEpoch': 1692115722085 }, 'isBase64Encoded': False }
どちらもアクセス URL や リクエスト元の IP アドレスが確認できるなど、ある程度同じなのですが、関数 URL の方はrequestContext
内のaccountId
の部分がanonymous
となっていました。Lambda 関数はクロスアカウントの API Gateway から呼び出せるため、呼び出し元の API Gateway が作成されているアカウントの ID が取得できますが、関数 URL はそもそも Lambda 関数と同じアカウントなので情報がないと思われます。
特に使用することはないと思いますが、関数 URL で呼び出す場合はevent
引数のペイロードからアカウント ID は取得できないことに注意が必要です。
比較に当たっての補足
公式ドキュメントには、「イベント形式は、Amazon API Gateway ペイロード形式バージョン 2.0 と同じスキーマに従います」、「マネジメントコンソールから API Gateway を作成すると最新バージョンで作成される」と記載されているのですが、Lambda 関数のトリガーに作成した API Gateway のペイロードのバージョンを確認した所、バージョン 1.0 で作成されていたので、以下手順でバージョン 2.0 へ変更してから比較しています。
Provisioned Concurrency を有効化してみる
以下ブログでは Provisioned Concurrency の料金や有効化した場合としていない場合の比較を行っているので、今回は Provisioned Concurrency の仕組み、有効化手順、そして API Gateway(HTTP API) と関数 URL をそれぞれ Provisioned Concurrency を有効化した場合、していない場合で速度を比較してみます。
実行環境の再利用と Provisioned Concurrency
Lambda の実行環境のサイクルは、初期化フェーズ → 呼び出しフェーズ → シャットダウンフェーズ となっています。Lambda 関数は初めに実行された後、同じ Lambda 関数がもう一度呼び出されること想定して、実行環境をしばらく維持します。
実行環境が再利用される場合は、初期化フェーズを実行せず、呼び出しフェーズから実行されるため、リクエストからレスポンスまでの時間が短縮されます。Provisioned Concurrency は Lambda 関数に割り当てる、事前に初期化された実行環境の数であり、Provisioned Concurrency を設定することで、指定した数分の実行環境が初期化された状態になり、受信した関数リクエストに即座に対応することができます
Provisioned Concurrency を有効化する
マネジメントコンソールから有効化してみます。Provisioned Concurrency は $LATEST で使用ができないため、バージョンやエイリアスに対して作成する必要があります。
設定後、ステータスが準備完了になるまでしばらく待機します。Lambda の初期化フェーズを実行しているため、handler 関数外のプログラムの処理時間によって、完了になるまでの時間が変わってくると思います。
Provisioned Concurrency が無効の状態
上記で Provisioned Concurrency を有効化しましたが、まずは以下のシンプルなコードで Provisioned Concurrency が無効な場合の API Gateway と 関数 URL のレスポンス速度を比較してみます。
import json def lambda_handler(event, context): return { 'statusCode': 200, 'body': json.dumps('Hello from Lambda!') }
API Gateway
$ ab -n 100 -c 100 https://<api-id>.execute-api.ap-northeast-1.amazonaws.com/default/urlAndAPIGW
Percentage of the requests served within a certain time (ms) 50% 548 66% 553 75% 556 80% 560 90% 569 95% 656 98% 698 99% 879 100% 879 (longest request)
何度が実行した結果だいたい700 ~ 900 程度の時間になりました。
関数 URL
ab -n 100 -c 100 https://<url-id>.lambda-url.ap-northeast-1.on.aws/
Percentage of the requests served within a certain time (ms) 50% 518 66% 639 75% 644 80% 645 90% 653 95% 655 98% 667 99% 695 100% 695 (longest request)
何度が実行した結果だいたい600 ~ 800 程度の時間になりました。 あまり差はありませんが、関数 URL の方が微妙にレスポンスまでの時間が短くなっていました。
Provisioned Concurrency が有効の状態
同様に Provisioned Concurrency を有効化した場合でも試してみます。
API Gateway
Percentage of the requests served within a certain time (ms) 50% 557 66% 558 75% 558 80% 559 90% 559 95% 560 98% 560 99% 560 100% 560 (longest request)
関数 URL
Percentage of the requests served within a certain time (ms) 50% 519 66% 531 75% 533 80% 536 90% 539 95% 540 98% 541 99% 542 100% 542 (longest request)
今回試したコードは初期化フェーズの実行プログラムがほとんどないため、Provisioned Concurrency が無効化の時とレスポンスまでの時間はあまり変わっていませんが、レスポンスが 50% から100% までの経過時間が短くなっていることがわかります。同時実行が可能になっているため、ほとんど同時に全てのレスポンスが返ってきていると思われます。
結果、レスポンスまでの速度は API Gateway と Lambda を同リージョンで作成しているので、API Gateway と関数 URL のレスポンスまでの時間はほとんど誤差程度のものでした。
まとめ
今回は関数 URL を作成し、機能や処理内容、Provisioned Concurrency を有効化した上で API Gateway と比較してみました。
認証方法や機能が限られているものの、マネジメントコンソールから数クリックで Lambda 関数の LATEST バージョンにも発行可能であり、別料金もかかりません。本番環境というよりも、Lambda 関数と HTTP エンドポイントを組み合わせた検証や簡単なアプリケーションを作成してみる際には選択肢に入れてよい機能だと思いました。
末廣 満希(執筆記事の一覧)
2022年新卒入社です。ここに何かかっこいい一言を書くことができるエンジニアになれるように頑張ります。