AWS Lambda in VPC

この記事は[DMM.com #2 Advent Calendar 2017 - Qiita](https://qiita.com/advent-calendar/2017/dmm2)の9日目です。

カレンダーはこちら
[DMM.com #1 Advent Calendar 2017 - Qiita](https://qiita.com/advent-calendar/2017/dmm)
[DMM.com #2 Advent Calendar 2017 - Qiita](https://qiita.com/advent-calendar/2017/dmm2)

# はじめに
こんにちは、@funa1gと申します。
社内で共通で利用されるAPIなどの開発をやっています。
技術選定のために、AWSについても色々と試しています。
今回は、その中でAWS LambdaとVPCをつないだ、アンチパターンについてです。

# 全体の構成
API Gateway + LambdaでAPIを作成する時、RDSにアクセスしたい場合があります。
しかもRDSとなるとやっぱりVPC内に置きたいです。
この組み合わせがアンチパターンなのは、すでに色々検証記事が出ていますが、
多少遅くても動くなら許せるかなと思って、検証してみました。

全体の構成です
![AWS Networking (1).png](https://qiita-image-store.s3.amazonaws.com/0/91466/28a8d55f-b439-8939-8977-3462fa17c5f5.png)


# 動作テスト
雑に動けばいいので、こんなエンドポイントにしました
レスポンスはDB内のデータです

METHOD: GET
URL: /LambdaTest
Response

```
[
  {
    "id": 1,
    "name": "test1"
  },
  {
    "id": 2,
    "name": "test2"
  }
]
```

Lambda側のコードも、DBにアクセスして、JSONを返すだけです

```js
const { Client } = require('pg');

exports.handler = (event, context, callback) => {
    // 接続先のPostgresサーバ情報
    const client = new Client()

    client.connect()
    client.query("SELECT * FROM test", (err, res) => {
        if (err) throw err
        client.end()
        callback(null, res.rows)
    })
};
```

負荷テストにはGatlingを使いました。
利用したコードは以下です。

```scala:constantTest.scala
  setUp(
    scn.inject(
      // 50人のアクセスを40秒間継続
      constantUsersPerSec(50) during(40 seconds)
    )
  ).protocols(httpConfig)
```
これでテストの準備は整いました。
あとは実行結果を待つだけです。

# テスト結果

上記の設定でテストした結果が以下になります。

```
---- Global Information --------------------------------------------------------
> request count                                       2000 (OK=1839   KO=161   )
> min response time                                      0 (OK=144    KO=0     )
> max response time                                  57613 (OK=57613  KO=0     )
> mean response time                                   471 (OK=512    KO=0     )
> std deviation                                       2902 (OK=3023   KO=0     )
> response time 50th percentile                        259 (OK=262    KO=0     )
> response time 75th percentile                        279 (OK=281    KO=0     )
> response time 95th percentile                        454 (OK=479    KO=0     )
> response time 99th percentile                       1304 (OK=1410   KO=0     )
> mean requests/sec                                     20 (OK=18.39  KO=1.61  )
---- Response Time Distribution ------------------------------------------------
> t < 800 ms                                          1802 ( 90%)
> 800 ms < t < 1200 ms                                   1 (  0%)
> t > 1200 ms                                           36 (  2%)
> failed                                               161 (  8%)
---- Errors --------------------------------------------------------------------
> j.u.c.TimeoutException: Request timeout to not-connected after    161 (100.0%)
 60000 ms
================================================================================
```
いくつか問題がありますね。

* かなり遅いレスポンスが一部発生している
* タイムアウトが発生している

何度か試しましたが、1700前後のシナリオを実行したところで、処理ができなくなっていました。
実行側の問題なのか、AWS側の問題なのかまで確認できず。
そこの検証を続けていたんですが、わからないまま、日付が変わりそうなので(12/9 22:00)、一旦の結果を放流です。
寂しい結果になりましたが、検証だとこういうこともありますね。
引き続き調査は続けて、わかったら追記したいと思います。

二ヶ月ほど前に試した際には、300ユーザーのアクセスを60秒間ほどやることで、API GatewayとVPC間のENIを限界(300)まで到達させることができたのですが、そこまでたどり着きませんでした。
http://docs.aws.amazon.com/ja_jp/lambda/latest/dg/vpc.html
実際にそうなると、この記事の一番下のような現象が発生します。
ENIがこれ以上作成できないため、Lambdaの起動ができず、その分が全て失敗します。
しかも、CloudWatchにログが出ないので、かなり厳しいです。
やはりアンチパターンはアンチパターンですね。

# 最後に
さて、AWS側からアンチパターンということになっているのは、それなりの理由があることがわかりました。
今後もこの方法は取れないかというと、まだわからないかと思っています。

先日のre:Inventで[API Gateway VPC integration](https://aws.amazon.com/jp/about-aws/whats-new/2017/11/amazon-api-gateway-supports-endpoint-integrations-with-private-vpcs/)が発表されました。
これはAPI GatewayからVPCのリソースにアクセスする手段を提供したものです。
アーキテクチャの問題上、Lambdaには明示的なエンドポイントがあるわけではないので、現状はアクセスできません。
しかし、VPCへのアクセス手段が用意されたということで、展開に希望が持てないかなと考えています。
今後の発表が楽しみなところです。