Posted at

AWS API GateWay (Labmda)に負荷テスト(ラッシュテスト)を実施したときのTips

More than 1 year has passed since last update.


概要

サーバレスアーキテクチャ(今回でいうとサーバレスAPI)を構築した際、負荷テスト(ラッシュテスト)を実施した際にいろいろ試行錯誤した時のTipsです。


アーキテクチャ構成

よくある構成。APIGW->Lambda->DynamoDBと処理しているAPIがほとんどです。

arch.png

 


実施内容


どうやってラッシュテストしようか。

下記のパターンがさっと思いつきます。

1. Device Farmを使ってテストケース投入してやってみる。

2. JMeterとかを使ってシナリオテストっぽくしてみる。

3. APIエンドポイントに対して負荷をかけてみる。

JMeterを使おうとも考えましたが、シンプルに想定RPSを耐え切るかを見たかったので、3を選択しました。


ラッシュテスト 前準備

結論から述べると、ApacheBenchもvegetaもうまくいかなかったので、wrk使います。

wrkでEC2を大量に立ち上げ、小さい時間間隔でリクエストを投げ続け、求めるRPSが出るまでチューニングを繰り返しました。


シンプルにApacheBench(ab)テストをしてみる

負荷テストといえばApacheBench、ABテストが一番に思い浮かぶのでEC2をさくっと立てて実施して見ます。構成的には下記のような感じですね。

ab.png


インストール

ApacheBenchインストールは、【初心者向け】ApacheBench入門を参考にしてください。


実行

API Gatewayのエンドポイント(下記図のURL)に対してabコマンドを実行します。

apiurl.jpg

$  [ec2-user@test ~]$ ab -n 100 -c 10 https://XXXXXXXXX.execute-api.ap-northeast-1.amazonaws.com/prod/YYYYYYYYYYY


結果

ABコマンド実行結果、大量のSSLハンドシェイクエラーが発生しました。。。

ab_error.png

なお、同じ事象に見舞われている記事がHITしました。どうやらAPIGatewayはSSL/TLSハンドシェイクがTLSv1を強要するようで、sslv3ではハンドシェイクできないのが原因の様子です。風の噂でjavaのバージョンを8にあげたら通るとかいう話もあったので試してみましたが、一度だけなぜか通り、それ以降は同様のSSLエラーに見舞われました。


vegetaというツールを使ってみる

Amazon API Gateway 経由でちょっとしたアクセスを流してみたで紹介されていた、

Go言語製ツールであるvegetaを使ってみました。


結果

vegetaは、あのべジータですww最強のサイヤ人の王子です!

これならばAPIエンドポイントに猛攻をかけてくれるに違いない!!とおもいながら試しましたが、同様にSSLハンドシェイクエラーで死にました。。。


wrkというツールを使ってみる

wrkという、Modern HTTP benchmarking toolを試してみました。


インストール

C言語で書かれているのでgithubにあがっているMakefileをつかってmakeします。make -j4ぐらいでやるとすぐ終わります。

$ sudo yum -y git

$ git clone https://github.com/wg/wrk.git
$ cd wrk
$ make -j4


実行

wrkコマンドをたたくとヘルプが表示されるので、必要なオプションを設定して対象のAPIエンドポイントに対してwrkコマンドを実行します。

./wrk -c 10 -t 2 -d 5s --latency "https://XXXXXXXXXX.execute-api.ap-northeast-1.amazonaws.com/prod/YYYYYYYY"

上記コマンドでは、2スレッドで10コネクションを確立し、5秒間リクエストを送り続けると意味になります。--latencyオプションをつけることで50-90パーセンタイルごとのレイテンシーを結果に表示することが出来ます。これはよくシステム開発の性能テストでは80パーセンタイルが性能目標を満たしているかを問われるシチュエーションでは非常に有効です。


結果

下記の通り、結果を取得することが出来ます。

wrk.png

なお、注意点としては持続時間を長くしたり、大きなコネクション数、スレッド数を指定するとタイムアウトエラーであったり、Non 2xx or 3xx レスポンスが返ってきたりします(下記参照)。短い時間で繰り返しコマンドを実行させることで、つどつどスレッドやコネクションを解放してあげる必要がありそうです。

wrk_error1.png

wrk_error2.png


ラッシュテスト

今回はとりあえず200RPSを目標にパラメータチューニングをしつつ、ラッシュテストを実施しました。


EC2起動時にwrkコマンドを自動実行

EC2で起動時やterminate時にシェルを実行するを参考にし、EC2インスタンスが起動するときに自動でwrkコマンドがうごくような設定をしました。

これにより、AWS CLIなどからEC2インスタンスを大量起動させたときに自動でwrkが走り、ラッシュが開始されるという仕組みになっています。


API Gatewayの負荷テスト時の注意点

これはAPI Gatewayというより、CloudFront利用時の注意点になるのですが、API Gatewayは内部的にCloudFrontを使っているのでCloudFront利用時の注意点と同様の注意が必要です。

AWS公式ページでCloudFront の負荷テストについては記載されています。

今回は、下記観点より、AllRegionからのリクエスト発行はしていません。

* API Gatewayのキャッシュは無効に設定

* キャッシュを利用せずラッシュをかける

* 日本からしかアクセスしない


CloudWatch で実行状況をモニタリング

APIGateway, DynamoDBの様子をモニタリングします。


試行1

下記パラメータで試行してみます。最初、Lambdaのデフォルト上限数で挑みましたが、HTTP429エラーが多発(ようはスロットリング)が発生したので上限緩和申請をしています。


  • APIGWの同時実行数(デフォルト:1000rps、バースト時:2000rps)

  • Lambdaの同時実行数(デフォルト100.下記試験では600まで上限緩和)、

  • DynamoDBのRead Provisioned Capacity(下記試験では読み込みAPIコールのため、Read:200を割り当て)

なお、注意点としては、パラメータチューニングしたとしても予期せぬ事態でAPIGWかLambdaがタイムアウトするとHTTP429エラーを返すため、クライアント側でリトライする機構が本来は必要ですが今回は無視します。

(APIGW->Lambda呼び出しは同期呼び出しとなるため、自動リトライやDeadLetterQueueは使えない)


試行1の結果

下記の結果となっています。サイズやスケールがあっておらずすいません。

RPS、DynamoのRead Provisioned Capacisy, throttle、API Gatewayの順です。


  • RPSを見ると、最初はどかーんと出ていますが、DynamoDBのスロットリングが発生し出したあたりからRPSが下がり、一定の値で進んでいます。

  • DynamoDBを見ると、なぜかProvisioned超えながらConsumed Capacityが走っています。このグラフを見ると完全にDynamoで詰まっていることが分かります。

  • API Gatewayの結果を見ても、APIGatewayは1000rpsまで許可しているのでスロットリングは発生していないがDynamo側で詰まり、Lambdaの実行時間が長くなり、LambdaでタイムアウトしているためAPI Gatewayでも一定のエラーが発生しています。

rps.png

dynamo.png

APIgateway.png


試行2

下記パラメータで試行してみます。最初、Lambdaのデフォルト上限数で挑みましたが、HTTP429エラーが多発(ようはスロットリング)が発生したので上限緩和申請をしています。

過剰な気もしますが、Lambdaの上限数とDynamoから読み込むレコードサイズをもとにキャパシティを600としています。


  • APIGWの同時実行数(デフォルト:1000rps、バースト時:2000rps)

  • Lambdaの同時実行数(デフォルト100.下記試験では600まで上限緩和)

  • DynamoDBのReadProvisioned Capacity 600


試行2の結果

下記の結果となっています。サイズやスケールがあっておらずすいません。

RPS、DynamoのRead Provisioned Capacisy, throttle、API Gatewayの順です。

rps.png

dynamo.png

apigateway.png


  • リクエストが一気になだれ込むがLambdaの上限設定値あたりでストップします。

  • rpsの目標値である200はとりあえずクリアしています。

  • Dynamoのキャパシティをあげたので十分さばききれています(Provisioned > Consumedとなっている)。スロットリングも発生していません。

  • APIGatewayをみると時々エラーが発生(1、2件)いますが、前回ほどタイムアウトは発生していません。


まとめ


  • サーバレスアーキテクチャ(今回でいうとサーバレスAPI)の負荷テスト(ラッシュテスト)を実施

  • オンプレの環境と違い、ツール実行までに時間がかかったがwrkで着地(余裕があればJMeterやガトリングも使いたい)

  • フルマネージドということもあり、LambdaやAPI Gatewayはオートスケーリングしてくれる


    • 注意点としてはDynamoのキャパシティであるがマネジメントコンソールからボタン1つでキャパシティ設定できる

    • サーバレスアーキテクチャ的にスロットリングが一定時間発生したらキャパシティを現在より増加させるなどのCloudWatchEventsを設定してオートスケーリングさせるとよい気がする。



  • サーバレス楽しいです!