シナリオから学ぶ連携テスト

# シナリオ背景
連携API(VPC A)とAPIを使うサービス(VPC B)はAWSの違うVPCに存在する。
２つのシステムは**Peering設定***されて通信できる状況。
連携APIのVPCは***マルチAZ構成***になっている（２つのAZ）

**Peering**：*2つのVPC間の通信を外部ネットワーク経由でなくL3ネットワーク経由で、でVPC間の相互に通信ができるサービスです。* 

**マルチAZ構成**：*クラウド上で構築・運用されるシステムの可用性を高めるためのベストプラクティスの一つであり*

![peering-intro-diagram.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/108475/7559e09c-cd36-eaa5-a3fa-5c01d9140116.png)
VPCピア機能については[こちら](https://docs.aws.amazon.com/ja_jp/vpc/latest/peering/what-is-vpc-peering.html)を参考してください。


# シナリオ概要
サービス運用途中急に連携APIの1/3のResponseがTimoutになった。
「VPC A」環境からの接続には問題なし。

# 原因調査準備
「VPC B」の環境に新しいEC2インスタンスを作ってテスト環境を用意

# APIの負荷テスト
vegeta・ApacheBenchを使ってAPIサーバーの性能に問題があるのかを調査。
負荷テストを行なったが特に性能上問題はなかった。

### vegetaテスト方法
*{API URL}* に向けて 10 request/sec のレートで 30秒間 負荷をかけ続ける場合

```:vegeta実行(Sample)
$ echo "GET {API URL}" | vegeta attack -rate=10 -duration=30s | tee results.bin | vegeta report

```

```:vegeta実行結果
Requests      [total, rate, throughput]         300, 10.03, 10.03
Duration      [total, attack, wait]             29.908s, 29.9s, 8.468ms
Latencies     [min, mean, 50, 90, 95, 99, max]  2.424ms, 9.616ms, 8.06ms, 15.127ms, 23.502ms, 29.709ms, 88.864ms
Bytes In      [total, mean]                     60000, 200.00
Bytes Out     [total, mean]                     0, 0.00
Success       [ratio]                           100.00%
Status Codes  [code:count]                      200:300  
Error Set:
```

[Vegetaの使い方についてはこちらを参考](https://qiita.com/chidakiyo/items/f8cdfac7683216a29c56)

### ApacheBenchテスト方法
10ユーザがそれぞれ10回リクエストした場合

```:ab実行
ab -n 100 -c 10 {API URL}
```

```:option
n: 生成するリクエスト数を指定します
c: 並列実行する数（コネクション数）を指定します
```

```:実行結果(Sample)
This is ApacheBench, Version 2.3 <$Revision: 1874286 $>
Copyright 1996 Adam Twiss, Zeus Technology Ltd, http://www.zeustech.net/
Licensed to The Apache Software Foundation, http://www.apache.org/

Benchmarking xxxxxxxxxx (be patient).....done


Server Software:        nginx/1.15.12
Server Hostname:        xxxxxxxxxxxxx
Server Port:            80

Document Path:          /api
Document Length:        25 bytes

Concurrency Level:      10
Time taken for tests:   0.148 seconds
Complete requests:      100
Failed requests:        0
Total transferred:      15300 bytes
HTML transferred:       2500 bytes
Requests per second:    676.97 [#/sec] (mean)
Time per request:       14.772 [ms] (mean)
Time per request:       1.477 [ms] (mean, across all concurrent requests)
Transfer rate:          101.15 [Kbytes/sec] received

Connection Times (ms)
              min  mean[+/-sd] median   max
Connect:        1    2   2.3      1      14
Processing:     2   11   7.2      9      31
Waiting:        2   11   7.2      9      30
Total:          3   13   8.4     10      35

Percentage of the requests served within a certain time (ms)
  50%     10
  66%     16
  75%     20
  80%     21
  90%     26
  95%     30
  98%     34
  99%     35
 100%     35 (longest request)
```

[ABの使い方についてはこちらを参考]
(https://dev.classmethod.jp/articles/ab-tutorial/)

# 連携APIサーバーの疎通テスト
curlを使ってテストサーバーからAPIを直接実行して疎通確認した結果、Timeoutが再現できました。
Timeoutの原因調査のため、curlのTraceオプションをつけて実行

```:curl_trace実行
$curl -sS {API URL} --trace-ascii trace.log -o /dev/null
```


DNS名前解決ができなかったのが原因でTimeoutになったのが分かりました。

```:trace(Traceのドメイン名・IPアドレスは編集)
== Info:   Trying xx.xxx.xx.xx...
== Info: TCP_NODELAY set
== Info: connect to xx.xxx.xx.xx port 80 failed: Connection timed out
== Info:   Trying xx.xxx.xx.x...
== Info: TCP_NODELAY set
== Info: Connected to {API URL} (xx.xxx.xx.x) port 80 (#0)
=> Send header, 169 bytes (0xa9)
0000: GET /api HTTP/1.1
0032: Host: {API URL}
0072: amazonaws.com
0081: User-Agent: curl/7.61.1
009a: Accept: */*
00a7:
<= Recv header, 15 bytes (0xf)
0000: HTTP/1.1 200
<= Recv header, 37 bytes (0x25)
0000: Date: Wed, 02 Sep 2020 06:59:42 GMT
<= Recv header, 32 bytes (0x20)
0000: Content-Type: application/json
<= Recv header, 28 bytes (0x1c)
0000: Transfer-Encoding: chunked
<= Recv header, 24 bytes (0x18)
0000: Connection: keep-alive
<= Recv header, 23 bytes (0x17)
0000: Server: nginx/1.15.12
<= Recv header, 2 bytes (0x2)
0000:
<= Recv data, 209 bytes (0xd1)
0000: c6
0004: {"result":{""}}]}}
00cc: 0
00cf:
== Info: Connection #0 to host {API URL} left intact
~                                                                                                                                                                                                           
~                                                                                                                                          
```

[curlのTraceについての詳細はこちらを参考](https://qiita.com/yasuhiroki/items/a569d3371a66e365316f)

その後```nslokup```でDSNが３つに増えてその１つに接続できなくてTimeoutになったのが判明しました。


# 結論
背景で連携APIサーバーのマルチAZ構成は２つだと説明したと思います。
APIサーバー(VPC A)のAZ構成を３つに増やしたけど連携APIを使うサーバー(VPC B)のPeering設定は２つのAZを許可したままになっているので新しいAZのDNSに接続できないためエラーになります。
「VPC B」のPeering設定に新しく追加されたAZサブネットのCIDRを追加することで解決。

[Amazon API Gateway](https://docs.aws.amazon.com/ja_jp/apigateway/latest/developerguide/welcome.html)を使って連携すれば上記のような設定変更の影響は無くなる。