「AWS無料相談会」をオンラインで開催中

VPC LambdaとRDS Proxyはサーバーレスの常識を変えるのか。検証しました!

最近はコンテナオーケストレーションに興味が偏っているやっさんでございます。
弊社ではサーバーレスを積極的に活用しておりまして、
Lambda SDPに認定されております。
本記事では、VPC LambdaとRDS Proxyはサーバーレスの常識を変えるのかを検証しました。

VPC Lambdaの起動速度を検証

VPC Lambdaは2019年9月に東京リージョンで起動速度が改善されました。
Lambda関数が最初に作成された時、Hyperplane ENIを作成するようになります。

VPC Lambdaの起動速度を測ってみます。
Heyという負荷試験ツールで200リクエストを実行します。
結果を見ていただくと分かります通り、レイテンシは大きく改善されています。

Summary:
  Total:    1.2073 secs
  Slowest:    0.9351 secs
  Fastest:    0.0392 secs
  Average:    0.2379 secs
  Requests/sec:    165.6654

  Total data:    9059 bytes
  Size/request:    45 bytes

Response time histogram:
  0.039 [1]    |
  0.129 [135]    |■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■
  0.218 [9]    |■■■
  0.308 [5]    |■
  0.398 [0]    |
  0.487 [0]    |
  0.577 [0]    |
  0.666 [15]    |■■■■
  0.756 [26]    |■■■■■■■■
  0.846 [6]    |■■
  0.935 [3]    |■

同時実行数を見てみます。
CloudWatch メトリクスの ConcurrentExecutions を確認します。
26の同時実行数を確認できました。

Lambdaの同時実行数

コールドスタートの速度も測ってみます。
CloudWatch Logs Insightで以下のクエリを実行します。

filter @type = "REPORT" and @initDuration > 0
| stats avg(@initDuration) as init_dur_avg, max(@initDuration) as init_dur_max , min(@initDuration) as init_dur_min

コールドスタート時間の計測

平均76msecはとても速いですね。素晴らしい結果が出ました。
これだけ見るとVPC Lambdaは本番のワークロードでも活用できそうに思えますが ...

2秒 ~ 6秒のレイテンシが発生する。何が起きているのか

何度か実行していると以下のように、レイテンシ増加のケースがありました。
何が起きているのでしょうか。

Summary:
  Total:    2.7564 secs
  Slowest:    2.0630 secs
  Fastest:    0.0792 secs
  Average:    0.5095 secs
  Requests/sec:    72.5585

  Total data:    10975 bytes
  Size/request:    54 bytes

Response time histogram:
  0.079 [1]    |
  0.278 [139]    |■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■
  0.476 [0]    |
  0.674 [5]    |■
  0.873 [4]    |■
  1.071 [1]    |
  1.269 [0]    |
  1.468 [29]    |■■■■■■■■
  1.666 [16]    |■■■■■
  1.865 [3]    |■
  2.063 [2]    |■

確認したところ、レイテンシが増加するケースにおいて
追加のENIが作成されていることが分かりました。

追加のENIは利用されていないと削除されました

つまるところ、ENI作成によるレイテンシを許容できない場合においては
VPC Lambdaを本番のワークロードで利用するべきではないと考えます。
これは今後改善されるのでしょうか。期待したいところです。

RDS Proxy

次にRDS Proxyを試します。
スケールしたLambdaの実行はそれぞれ独立していて、
RDSへのコネクションをプールすることは難しく、
アンチパターンとされていました。

RDS Proxyによりコネクションが一定数確保され、使い回すことができるようになります。

接続プールの最大接続数について

RDS Proxyの重要な設定項目として、
ターゲットグループの 接続プールの最大接続数 があります。

接続プールの最大接続数

Lambdaは同時実行数が増加すれば、その数だけコネクションが発生します。

なお、RDSの最大コネクション数はインスタンスタイプによって異なります。
もちろん、この最大コネクション数を変更することは可能ですが、
小さいインスタンスタイプに対して最大コネクション数を増やした場合、メモリ枯渇などRDS側の問題が発生します。

ですので、Lambdaの本番ワークロードの同時実行数を定め、
同時実行数に適したRDSのインスタンスタイプを選択し、
コネクション数をRDS Proxyで確保する必要があります。

RDS Proxyを利用した場合においても、最大接続数を超えた接続要求がある場合、
Lambdaはコネクションの解放を待つことになり、
レイテンシ増加を引き起こします。

RDS Proxyは料金が発生する

RDS Proxyは利用料金が発生します。
2020年4月時点の料金は以下となっています。

基となるデータベースインスタンスの vCPU あたりの料金: 0.018USD/時間

m5.large、1,440 vCPU 時間 (2 vCPU x 24 時間 x 30 日) の場合は25.92USDの料金が発生します。
スペックの高いインスタンスタイプを利用している場合は、決して無視できない金額になるでしょう。

RDS Proxyの検証

RDS Proxyを検証していきます。

Heyで200リクエストを実行しコネクション数の増加を確認しました。
コネクション超過エラーとはならず捌けていることが確認できます。

コネクション数の確認

しかし、ここで思わぬ問題に遭遇しました。
いくつかのLambdaでエラーが発生しているのです。

Status code distribution:
  [200]    71 responses
  [502]    39 responses

golangで検証していたのですが、
この問題につまづき、Pythonでも検証を進めました。
しかしながら、Pythonでも同様のエラーが発生します。
エラー内容としては、DBに接続できない旨のエラーが出力されていました。

Amazon RDS ProxyがGAとなり、DBに接続できないエラーは解消されました!

出力されたエラー内容

mysql.connector.errors.ProgrammingError: 1045 (28000): Access denied for user 'root'@'%' (using password: YES)

RDS Proxyを利用しない場合はエラーは発生しない

PythonでRDS Proxyを利用せずに検証した結果が以下の通りです。
エラーなくすべて捌けています。

Summary:
  Total:    3.6572 secs
  Slowest:    2.2241 secs
  Fastest:    0.1054 secs
  Average:    0.8839 secs
  Requests/sec:    54.6862

  Total data:    1000 bytes
  Size/request:    5 bytes

Response time histogram:
  0.105 [1]    |
  0.317 [4]    |■■
  0.529 [105]    |■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■
  0.741 [41]    |■■■■■■■■■■■■■■■■
  0.953 [0]    |
  1.165 [0]    |
  1.377 [0]    |
  1.589 [1]    |
  1.800 [1]    |
  2.012 [5]    |■■
  2.224 [42]    |■■■■■■■■■■■■■■■■


Latency distribution:
  10% in 0.4624 secs
  25% in 0.4930 secs
  50% in 0.5254 secs
  75% in 0.6284 secs
  90% in 2.1326 secs
  95% in 2.1370 secs
  99% in 2.1884 secs

Details (average, fastest, slowest):
  DNS+dialup:    0.1087 secs, 0.1054 secs, 2.2241 secs
  DNS-lookup:    0.0942 secs, 0.0000 secs, 0.3778 secs
  req write:    0.0001 secs, 0.0000 secs, 0.0010 secs
  resp wait:    0.7748 secs, 0.1052 secs, 1.7916 secs
  resp read:    0.0001 secs, 0.0000 secs, 0.0002 secs

Status code distribution:
  [200]    200 responses

コネクション数は限界近くまで達しました。
それでもPythonはDBクローズが速いのか、捌けました。

コネクション数の増加

2020年4月時点で、RDS Proxyはプレビュー版となっており、
それゆえに動作が安定しないと思いたいですね。
GAした時にもう一度検証したいと思います。
Amazon RDS ProxyがGAとなり、DBに接続できないエラーは解消されました!

Provisioned Concurrencyの考察

Lambdaにおいて見逃せないアップデートとして、
Provisiond Concurrensyがございます。
こちらについて考察します。

料金について

プロビジョニングされた同時実行は個別の料金が発生します。

コネクション数の増加

リクエストと実行時間とは別に 1 GB-秒あたり 0.0000053835USD の料金が請求されます。
さらに言いますと、 Lambda の無料利用枠は、Provisioned Concurrency が有効になっている関数には適用されません。
前述したように、Lamdaの同時実行数はスケールします。
あくまで個人的な意見ですが、Lambdaの無料利用枠を捨ててまで、
Provisioned Concurrencyを適用する本番ワークロードとは、どのようなケースなのでしょうか。

20や30の同時実行数をProvisioned Concurrencyで確保するのでしたら、
それはもう、コスト的な観点においてECSやEKSの
Fargateも比較対象になってくるのではないかなと思います。

まとめ

  • VPC Lambdaの起動速度は高速になり、本番のワークロードで活用できるようになりました。
  • しかしながら、ENIが追加作成される場合にレイテンシが発生することを確認できました。これを許容できるシステムであれば問題ありません。
  • Lambdaの想定されるワークロードを定め、RDSのインスタンスサイズとRDS Proxyの最大接続数を決めたいところです。
  • RDS Proxyは動作が安定せず、エラーが発生しました。2020年4月時点ではプレビュー版であり、GAで改善することを期待したいです。
  • RDS Proxy, Provisiond Concurrensyの料金を確認し、Lambdaであるべきなのか、それともECSやEKSのFargateを選択するのかを決めたいところです。

今回利用したソースコードについて

ソースコードは以下の場所にありますので、よろしければご参照ください。

以上です!