従来から12倍高速化した同期呼び出しLambdaのスケールアウト能力を確認してみた

爆速スケールアウト!!
2023.12.06

CX事業本部@大阪の岩田です。

re:inventで大量のアップデート情報が流れる中、Lambdaにもこんなアップデートが来ていました。

なんと同期実行のLambdaが従来の12倍のスピードでスケールアウト可能になったとのことです!

従来Lambdaの同時実行数は1分ごとに500ずつスケールアウトしていく仕様でしたが、このアップデートによって10秒ごとに1,000ずつスケールアウト可能になりました。

新サービスや新機能というわけではありませんが、コレはなかなか熱いアップデートではないでしょうか?ということで実際にLambdaを大量起動してスケールアウトの速さを確認してみました。

環境

今回検証に利用した環境です。

  • Lambda
    • ランタイム: Python3.11
    • アーキテクチャ: arm64
    • リージョン: バージニア(us-east-1)
    • メモリ割り当て: 128M
  • EC2
    • インスタンスタイプ: m5.large
    • リージョン: バージニア(us-east-1)
  • hey: v0.1.4

AWS Service QuotasからLambdaの上限緩和申請

まずはAWS Service QuotasからLambdaの同時実行数の上限緩和申請を行います。

AWSブログの内容に合わせて7,000で申請しました。大体1時間後ぐらいだったと記憶していますが、しばらく作業してからマネコンの様子を見にいったら同時実行数が7,000に上限緩和されていました。対応が早い!

Lambdaのコードを準備

次に大量に起動するLambdaのコードを準備します。Python3.11のarm64で以下のようなコードを書きました。0.5秒のSleep処理を入れているので、実行完了には約0.5秒を要するLambda関数です。

import json
import time

def lambda_handler(event, context):
    time.sleep(0.5)
    return {
        'statusCode': 200,
        'body': json.dumps('Hello from Lambda!')
    }

このLambda関数をHTTP APIのAPI GWと統合し、負荷テスト用のツールheyから大量にアクセスした後に各種のメトリクスとログを分析してみます。

やってみる

準備が整ったので、大量起動を試してみます。ウォーム状態のLambda実行環境が破棄されていることと、同時実行数がスケールアウトしていないことを担保するために何もせずに1日ほど寝かせます。。。

7,000クライアントからのアクセスを実行

準備ができたらEC2からheyを実行します。

hey -c 7000 -n 250000 -q 1 <API GWのエンドポイント>

7,000クライアントの同時アクセスで合計25万リクエストを発行します。Lambdaのスロットリングエラーを引いた場合は5秒のsleepが実行されずにエラーが返却されることになるので、あまり連続でAPIを呼び出しすぎないように-qオプションでworkerごとのレートリミットを1秒につき1回に制限しています。

実行結果はこちらです。

Summary:
  Total:	217.0975 secs
  Slowest:	17.8377 secs
  Fastest:	0.0065 secs
  Average:	4.2831 secs
  Requests/sec:	1128.5252

  Total data:	5696474 bytes
  Size/request:	23 bytes

Response time histogram:
  0.007 [1]	|
  1.790 [56453]	|■■■■■■■■■■■■■■■■■
  3.573 [6071]	|■■
  5.356 [135269]	|■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■
  7.139 [26377]	|■■■■■■■■
  8.922 [9211]	|■■■
  10.705 [1416]	|
  12.488 [492]	|
  14.271 [159]	|
  16.055 [1573]	|
  17.838 [821]	|


Latency distribution:
  10% in 0.3557 secs
  25% in 2.3418 secs
  50% in 5.0143 secs
  75% in 5.0186 secs
  90% in 6.1979 secs
  95% in 7.4285 secs
  99% in 14.5004 secs

Details (average, fastest, slowest):
  DNS+dialup:	0.0657 secs, 0.0065 secs, 17.8377 secs
  DNS-lookup:	0.1000 secs, 0.0000 secs, 4.0979 secs
  req write:	0.0016 secs, 0.0000 secs, 1.5405 secs
  resp wait:	4.0173 secs, 0.0065 secs, 15.8699 secs
  resp read:	0.0005 secs, 0.0000 secs, 0.8759 secs

Status code distribution:
  [200]	168733 responses
  [503]	68694 responses
  [504]	416 responses

Error distribution:
  [7157]	Get "https://<API GWのエンドポイント>": context deadline exceeded (Client.Timeout exceeded while awaiting headers)

約16万8千回のリクエストが200 OKで正常終了となりました。

CloudWatchのメトリクスを確認してみる

テスト完了後にCloudWatchのメトリクスを確認してみましょう。Lambdaのメトリクスは1 分間隔でCloudWatchに送信されるため、全てのメトリクスは期間に「1分」を指定して表示しています。

Lambda 関数のメトリクスの使用

まずは同時実行数です。

467 → 5,945 → 6,996 → 6,705 → 1,344と遷移しています。最初の1分間で同実行数が5,945まで伸びているので、スケールアウトが高速していることが分かります。

同時実行数に被せてスロットリングの合計値も表示してみました。1分ごとの集計なので少し極端な見え方をしていますが同時実行数の上昇に合わせてスロットリングの件数が下がっているのが分かります。

最後にスロットリングと呼び出し回数を被せて表示してみます。こちらもスロットリングの減少に合わせて呼び出し回数が伸びているのがよく分かります。

CloudWatch Logsを確認してみる

続いてCloudWatch Logsのログを集計してコールドスタートの件数を確認してみます。ざっくり10秒ごとに1,000件ずつコールドスタートが発生するような傾向になるのが期待値です。

CloudWatch Logs Insightsから以下のクエリを実行してみます。

filter @message like  /INIT_START Runtime Version:/
  | stats count(*)  by bin(10s) as time
  | sort time

結果は以下の通りでした。

Time count(*)
2023-12-05 12:16:50.000 467
2023-12-05 12:17:00.000 2
2023-12-05 12:17:10.000 1611
2023-12-05 12:17:20.000 1001
2023-12-05 12:17:30.000 1023
2023-12-05 12:17:40.000 805
2023-12-05 12:17:50.000 1053
2023-12-05 12:18:00.000 958
2023-12-05 12:18:10.000 84
2023-12-05 12:18:20.000 1
2023-12-05 12:18:30.000 3
2023-12-05 12:19:00.000 2
2023-12-05 12:19:10.000 3
2023-12-05 12:19:30.000 2
2023-12-05 12:19:50.000 2

概ね期待値に近い分布と言えるのではないでしょうか。グラフにすると以下のようになりました。

(おまけ) 非同期呼び出しのスケールアウトは従来どおり

実は最初このアップデートの恩恵を受けるのが同期呼び出しだけということを見逃していて、AWS SDKから大量にLambdaの非同期呼び出しを繰り返すことで検証しようとしていました。が、何度やっても1分あたり500ずつしかスケールアウトしてくれず、「うーん。。。」と悩んでいました。その後スケールアウトが高速化したのは同期呼び出しのみだと気付いたのですが、非同期呼び出しのスケールアウトについては従来通り1分につき500ずつと確認できたので、これも良い検証になった気がします。参考までにその時のメトリクスも貼っておきます。

1分につき500ずつ伸びていってるのがよく分かります。

まとめ

Lambdaのスケールアウトが更に高速化したことを実際に確認してみました。従来比12倍というパワーアップの裏にはLambdaというサービスのアーキテクチャの見直し等があったのかなと想像しています。re:inventで毎年恒例のSVS4xx系セッションで詳細が聞けるかなと期待していたのですが、セッションカタログを検索した限りどうも今年はSVS4xx系のセッションが無さそうです。もし本アップデートの裏側等について解説されているDeep Dive系のセッションをご存知の方がいれば是非教えて下さいmm。

参考