MMMブログ

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

このエントリーをはてなブックマークに追加

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

VPC Lambdaの起動速度を検証

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

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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
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で以下のクエリを実行します。

1
2
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秒のレイテンシが発生する。何が起きているのか

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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
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でエラーが発生しているのです。

1
2
3
Status code distribution:
[200] 71 responses
[502] 39 responses

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

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

出力されたエラー内容

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

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

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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
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を選択するのかを決めたいところです。

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

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

以上です!

このエントリーをはてなブックマークに追加

お問い合わせ

見積もり依頼や詳しいご相談など、クラウド・AWSに関する困りごとをお気軽にご相談ください。
以下のお問い合わせ先から受け付けています。

お問合わせはこちら

※通常1営業日内にご回答いたします。