のべラボ.blog

Tech Blog | AWS や サーバーレスやコンテナ などなど

AWS Lambda の Provisioned Concurrency を設定した後、利用可能になるまでの状況を確認してみる

本記事は「AWS LambdaとServerless Advent Calendar 2022」11日目の記事です。


AWS Lambda では、「プロビジョニングされた同時実行数」を設定することができます。本記事においては便宜上、この設定を Provisioned Concurrency と呼称します。

この Provisioned Concurrency の設定を行うと、AWS Lambda 関数の実行環境を初期化して、関数の呼び出しに即座に応答する準備を行うため、コールドスタートによるレイテンシーの影響を低減することが期待できます。ただし、この設定を行うと AWS アカウントに課金が発生することに注意してください。詳細は、次のドキュメントを確認しましょう。

docs.aws.amazon.com

この Provisioned Concurrency の設定は、AWS マネジメントコンソールからも行えます。

AWS マネジメントコンソールで 対象の AWS Lambda 関数のページを表示し、[設定] タブを選択、左側のメニューで、[同時実行] のメニューを選択すると [プロビジョニングされた同時実行設定] セクションが表示されるので、そのセクションから [追加] ボタンを選択します。

https://cdn-ak.f.st-hatena.com/images/fotolife/n/neob/20221203/20221203180449.png

その後、対象の AWS Lambda 関数のエイリアス または バージョン とプロビジョニングさせる実行環境の数を入力、保存することで設定は完了です。

https://cdn-ak.f.st-hatena.com/images/fotolife/n/neob/20221203/20221203180520.png

ただしここで設定したからといって、すぐに AWS Lambda 関数の実行環境が作成され、利用可能になるわけではありません。

上記の設定後、AWS マネジメントコンソールでは下図のように表示されます。

https://cdn-ak.f.st-hatena.com/images/fotolife/n/neob/20221203/20221203180547.png

指定した値にも依りますが、しばらく待ってから手作業でページをリフレッシュ表示しないと [準備完了] とは表示されません。

https://cdn-ak.f.st-hatena.com/images/fotolife/n/neob/20221203/20221203180611.png

ここで 私は 下記 2つの点が気になりました。

  • Provisioned Concurrency の設定後に利用可能になるまで、どれくらいの時間がかかったのか知りたいけど、現状のAWS マネジメントコンソールでは、その情報は表示されない。
  • Provisioned Concurrency の設定後、現時点でどれくらいの環境の数をプロビジョニングできたのか知りたいけど、現状のAWS マネジメントコンソールでは手動でページをリフレッシュしないと、その情報は表示されない。

しかし、次の AWS CLI のドキュメントを読んで、 aws lambda get-provisioned-concurrency-config コマンド を活用すれば、この気になった 2つの情報を知ることができるのでは、と考えました。

awscli.amazonaws.com

この AWS CLI のコマンドの出力には、下記が含まれます。

  • AllocatedProvisionedConcurrentExecutions: アロケート(作成)済の実行環境数
  • AvailableProvisionedConcurrentExecutions: 利用可能な実行環境数
  • Status: アロケートの状態

Provisioned Concurrency の設定後に、この AWS CLI のコマンドを継続的に実行すれば、上記 2つの情報を得られそうです。

そこで、下記のスクリプトを作成しました。(このスクリプトLinux での使用を前提にしています。)

#!/bin/bash
# Provisioned Concurrency を設定
aws lambda put-provisioned-concurrency-config --function-name $1 --qualifier $2 --provisioned-concurrent-executions $3
# 開始時刻を取得
started_time=$(date +'%s.%3N')
# Status が READY になるまで待機
while [ "$STATUS" != "READY" ]
do
  RESULT=$(aws lambda get-provisioned-concurrency-config --function-name $1 --qualifier $2)
  STATUS=$(echo ${RESULT} | jq -r '.Status')
  ALLOCATE=$(echo ${RESULT} | jq -r '.AllocatedProvisionedConcurrentExecutions')
  AVAILABLE=$(echo ${RESULT} | jq -r '.AvailableProvisionedConcurrentExecutions')
  echo `date`, ${STATUS}, ${ALLOCATE}, ${AVAILABLE} 
  sleep 1
done
# 完了時刻を取得
ended_time=$(date +'%s.%3N')
# 完了時刻 - 開始時刻で経過時間を算出
elapsed=$(echo "scale=3; $ended_time - $started_time" | bc)
# 経過時間を表示
echo "ELAPSED : ${elapsed} seconds"
# Provisioned Concurrencyの状況を表示
aws lambda get-provisioned-concurrency-config --function-name $1 --qualifier $2 

このスクリプトでは、第1引数に AWS Lambda 関数名を、第2引数に エイリアス名またはバージョンIDを、第3引数に Provisioned Concurrency の値を受け取る前提にしています。

また、Provisioned Concurrency の設定後、1秒毎に AWS CLI でステータスとアロケート済の環境数や利用可能な環境数を取得・表示させています。またステータスの値をチェックして 設定した Provisioned Concurrency が利用可能になったら、それまでかかった時間(秒)を算出して停止します。

実際の実行例を次に示します。 上記スクリプトを test.sh として実行しています。AWS Lambda 関数名は Demo-Burst、バージョンIDは3、Provisioned Concurrency の値は 100 で指定しています。

$ ./test.sh  Demo-Burst 3 100
{
    "RequestedProvisionedConcurrentExecutions": 100, 
    "AllocatedProvisionedConcurrentExecutions": 0, 
    "AvailableProvisionedConcurrentExecutions": 0, 
    "LastModified": "2022-12-03T06:30:51+0000", 
    "Status": "IN_PROGRESS"
}
Sat Dec 3 06:30:51 UTC 2022, IN_PROGRESS, 0, 0
Sat Dec 3 06:30:53 UTC 2022, IN_PROGRESS, 0, 0
Sat Dec 3 06:30:54 UTC 2022, IN_PROGRESS, 0, 0
(・・・中略・・・)
Sat Dec 3 06:32:41 UTC 2022, IN_PROGRESS, 0, 0
Sat Dec 3 06:32:43 UTC 2022, IN_PROGRESS, 0, 0
Sat Dec 3 06:32:45 UTC 2022, IN_PROGRESS, 0, 0
Sat Dec 3 06:32:46 UTC 2022, IN_PROGRESS, 87, 0
Sat Dec 3 06:32:48 UTC 2022, IN_PROGRESS, 87, 0
Sat Dec 3 06:32:50 UTC 2022, IN_PROGRESS, 87, 0
Sat Dec 3 06:32:52 UTC 2022, IN_PROGRESS, 87, 0
Sat Dec 3 06:32:54 UTC 2022, IN_PROGRESS, 87, 0
Sat Dec 3 06:32:55 UTC 2022, IN_PROGRESS, 87, 0
Sat Dec 3 06:32:57 UTC 2022, READY, 100, 100
ELAPSED : 127.205 seconds
{
    "RequestedProvisionedConcurrentExecutions": 100, 
    "AllocatedProvisionedConcurrentExecutions": 100, 
    "AvailableProvisionedConcurrentExecutions": 100, 
    "LastModified": "2022-12-03T06:30:51+0000", 
    "Status": "READY"
}

上記の出力はあくまで例の1つですが、Provisioned Concurrency の設定後、約 127秒で利用可能になりました。また、利用可能になるまでアロケートされた数として 87 という数字が確認できました。 もちろん、このスクリプトは1つの例ですが、少なくとも AWS マネジメントコンソールで手動でページをリフレッシュしなくともよくなりました。


このスクリプトを何度か実行していて、また気になる点が出てきました。

Provisioned Concurrency の設定後、現在のアロケートされた値はスクリプトで確認できるようになりましたが、最終的にステータスが READY、つまり利用可能になるのは、AvailableProvisionedConcurrentExecutions の値が設定した値になったタイミングです。

上記の出力例だと、途中にアロケートされた値が 87 と表示されてますが、いくら 87 の環境がアロケートされていても、その段階ではまだ Provisioned Concurrency によってプロビジョニングされた環境は利用不能ということになります。

https://cdn-ak.f.st-hatena.com/images/fotolife/n/neob/20221203/20221203181307.png

そこで、本当に利用できないのか確認してみました。

方法としてはシンプルに、上記のスクリプトを実行しアロケートされた値が 50 より大きい値になったタイミングで、その AWS Lambda関数に同時アクセスを行い、Amazon CloudWatch のメトリクスで確認することにしました。

この仕組みを解説すると長くなるので、概略だけ説明します。

  • 対象の AWS Lambda 関数は、実行環境が再利用されにくい状態で一気に同時アクセスを行いたかったので、コードの中に 3秒ほど sleep するコードを入れておきます。
    • Python だと、time.sleep(3) など
  • Amazon CloudWatch では、次のメトリクスを監視できるように Amazon CloudWatch のダッシュボードに設定しておきます。
    • ProvisionedConcurrencyInvocations
    • Invocations
    • ProvisionedConcurrentExecutions
    • ConcurrentExecutions
    • ProvisionedConcurrencyUtilization
    • ProvisionedConcurrencySpilloverInvocations
  • 一気に同時アクセスを行う方法として、下記の AWS Step Functions の Distributed Map を使ったステートマシンを実行することにしました。Distributed Mapを使用し、AWS Lambda 関数に対して 並列度 50 で同時アクセスしてみます。

aws.amazon.com

上記の仕組みで試してみた結果をみると、やはり アロケートの値が 50 以上になっても、ステータスが IN-PROGRESS の状態だと、Provisioned Concurrency として使用できない ということがわかりました。

Amazon CloudWatch の メトリクスを確認してみます。

  • まず Invocations が50に対して、ProvisionedConcurrencyInvocations は値なしという結果から、Provisioned Concurrency によって関数コードは実行されなかったことを示しています。

https://cdn-ak.f.st-hatena.com/images/fotolife/n/neob/20221203/20221203200929.png

  • 次に ConcurrentExecutions が 50に対して、ProvisionedConcurrentExecutions は値なしという結果から、Provisioned Concurrency の環境でイベントを処理しているものがないことがわかります。つまり通常 のコールドスタートのプロセスを経て実行環境がプロビジョニングされたことを示します。

https://cdn-ak.f.st-hatena.com/images/fotolife/n/neob/20221203/20221203201023.png

  • なお、ProvisionedConcurrencyUtilization と ProvisionedConcurrencySpilloverInvocations は値がないという結果になりました。これは、そもそも 利用可能な Provisioned Concurrency の環境がないため算出されなかったと推察できます。

https://cdn-ak.f.st-hatena.com/images/fotolife/n/neob/20221203/20221203180903.png


同じ環境で、Provisioned Concurrency のステータスが READY になった後に同様のアクセスを行うと、これらのメトリクスの値は下記のようになります。

  • Invocations が50に対して、ProvisionedConcurrencyInvocations も 50 という結果から、50のリクエストは全て Provisioned Concurrency 環境の AWS Lambda 関数を呼び出したことがわかります。

https://cdn-ak.f.st-hatena.com/images/fotolife/n/neob/20221203/20221203202626.png

  • ConcurrentExecutions が 50に対して、ProvisionedConcurrentExecutions も 50 という結果から、50 の Provisioned Concurrency の環境で AWS Lambda 関数のコードを処理したことがわかります。

https://cdn-ak.f.st-hatena.com/images/fotolife/n/neob/20221203/20221203202701.png

  • ProvisionedConcurrencyUtilization は 0.5、つまり Provisioned Concurrency の 100 の環境のうち 50 が使用されて AWS Lambda 関数が実行されたことがわかります。また ProvisionedConcurrencySpilloverInvocations は 0 であり、Provisioned Concurrency で賄いきれなかったリクエストがなかったことがわかります。

なお、AWS Lambda 関数の メトリクスについては下記のドキュメントにも説明がありますので、ご参照ください。

docs.aws.amazon.com


まとめ

  • AWS Lambda の Provisioned Concurrency を設定後の状況については、AWS CLI を活用することで取得、表示できます。
  • その AWS CLI でアロケートされた環境数は確認できるものの、ステータスが READY になるまでは、Provisioned Concurrency としては使用できません。

これからも、このように「ちょっとした疑問」から Dive Deep して調べてみる、ということをドンドンやっていきたいと思います!

なお繰り返しの説明になりますが、Provisioned Concurrency を使用すると料金がかかりますので、もし実際に試す場合は課金に十分に留意して下さい。 詳細は、下記をご参照ください。

aws.amazon.com

(本記事は 2022年12月11日時点で確認した内容を基に記載しています。)

/* -----codeの行番号----- */