スマートキャンプ、エンジニア井上です。
突然ですがみなさん、負荷試験はどのように実施していますか?
私はJmeterなどで負荷試験をすることがあるのですが、テスト作成からテスト実施までがとても時間がかかり継続的にやるのはかなり大変だなと感じてます。
そんなときに見つけた、負荷テストツールArtilleryについて簡単にご紹介できればと思います。
Artilleryとは
Artillery は yamlファイルで宣言的にシナリオを作成し、負荷をかけることができる Nodejs 製の負荷テストツールです。
Artilleryのドキュメントにも開発者の生産性が何よりも優先され、そのために簡単に記述して実行できる構造になっていると記載がある通り 複雑になりがちなテストをyamlで書けるので、簡単にかけて理解がしやすい構造が魅力の1つと感じています。
また、CircleCIやGithubActionにも簡単に組み込むことができるのも良いなと思う点です。
Artilleryで負荷試験を実装してみる
では、実際にArtilleryでのテスト実行を試してみます。
事前時準備
npm i -g artillery
まずはクイック実行
負荷試験でシンプルに下記のコマンドで負荷をかけることができます
※ quickはお試し用のコマンドなのでhttpのみテスト可能で、WebSocketsなどはテストできません
下記は例として20人の仮想ユーザーが5回ずつ、計100リクエストをhttp://example.comに投げます
artillery quick --count 5 --num 20 http://example.com
コマンドを実行すると下記のような実行結果が表示されRPSやLatencyが計測可能です。
All virtual users finished Summary report @ 08:15:22(+0900) 2021-09-15 Scenarios launched: 5 Scenarios completed: 5 Requests completed: 100 Mean response/sec: 10.71 Response time (msec): min: 110 max: 445 median: 230 p95: 373 p99: 417.5 Scenario counts: 0: 5 (100%) Codes: 200: 100
yamlからテストを実行する
yamlで定義すると、より詳細に負荷テストのシナリオを構築可能です。 今回は例として下記のような負荷試験を行いたいと思います。
例) http://example.comに対して、10秒間に1人のユーザーで下記のようなシナリオを実行する
- example.comにログインする
- indexにGet Requestする
- createにPost Requestでnameを送る
config: target: "http://example.com" phases: - duration: 10 arrivalRate: 1 scenarios: - flow: - log: "get index" - get: url: "/index" - log: "post create" - post: url: "/create" json: name: "test"
テストを実行する
$ artillery run script.yml All virtual users finished Summary report @ 09:45:20(+0000) 2021-09-13 Scenarios launched: 10 Scenarios completed: 10 Requests completed: 20 Mean response/sec: 2.11 Response time (msec): min: 0 max: 1 median: 0.5 p95: 1 p99: 1 Scenario counts: 0: 10 (100%) Codes: 200: 20
さらに高負荷にしたい
さらに負荷を上げたい場合にはServerless-artillery
というツールを使います。
Serverless-artilleryとは
serverless-artillery はArtilleryをサーバーレス環境で実行できるツールです。
Serverless-artilleryで負荷試験をする利点
通常の負荷試験をする際には、負荷をかける側のサーバースペックが懸念点になります。 高い負荷をかけるにはそれに見合うサーバースペックが必要になります。 サーバースペックの不足により想定していただけの負荷がかからず試験失敗となるケースがあるため、負荷試験計画時にはそれを考慮する必要があります。
Serverless-artilleryを利用すると、Serverless Frameworkと組み合わせてArtilleryをAWS Lambdaで実行できるためサーバースペックを意識せずにテストが可能になり、前述の懸念が解消できます。
Serverless-artilleryを準備する
Serverless-artilleryのinstall
$ npm i -g serverless@1.83.3 $ npm i -g serverless-artillery
※2021/09時点では2系のserverlessではエラーになるため1系をinstallしています。
AWSにデプロイする
$ slsart configure $ slsart deploy Deploying function... Serverless: Packaging service... Serverless: Excluding development dependencies... Serverless: Uploading CloudFormation file to S3... Serverless: Uploading artifacts... Serverless: Uploading service serverless-artillery-test.zip file to S3 (16.85 MB)... Serverless: Validating template... Serverless: Updating Stack... Serverless: Checking Stack update progress...
Lambdaでのテスト実行
AWSへのdeployが完了したら先程つくったテストファイルでテストを実行してみます。
$ slsart invoke Invoking test Lambda { "timestamp": "2021-09-13T09:27:44.639Z", "scenariosCreated": 10, "scenariosCompleted": 0, "requestsCompleted": 0, "latency": { "min": null, "max": null, "median": null, "p95": null, "p99": null }, "rps": { "count": 10, "mean": 1.06 }, "scenarioDuration": { "min": null, "max": null, "median": null, "p95": null, "p99": null }, "scenarioCounts": { "0": 10 }, "errors": { "ENOTFOUND": 10 }, "codes": {}, "matches": 0, "customStats": {}, "phases": [ { "duration": 10, "arrivalRate": 1 } ] } Your function invocation has completed. { "timestamp": "2021-09-13T09:27:44.639Z", "scenariosCreated": 10, "scenariosCompleted": 0, "requestsCompleted": 0, "latency": { "min": null, "max": null, "median": null, "p95": null, "p99": null }, "rps": { "count": 10, "mean": 1.06 }, "scenarioDuration": { "min": null, "max": null, "median": null, "p95": null, "p99": null }, "scenarioCounts": { "0": 10 }, "errors": { "ENOTFOUND": 10 }, "codes": {}, "matches": 0, "customStats": {}, "phases": [ { "duration": 10, "arrivalRate": 1 } ] }
Github Actionsで実行する
GithubActionsで Serverless-artilleryを実行してみます。
やることはシンプルで事前にslsart deployを実行し環境を構築していれば テストを実行するだけになるので下記の設定ファイルで実行できます。
name: serverless-rtillery sample on: push: branches: - main tags: - "!*" jobs: serverless-artillery-sample: runs-on: ubuntu-latest steps: - name: checkout uses: actions/checkout@v1 - name: setup Node uses: actions/setup-node@v1 with: node-version: 12.x - name: build run: | npm i -g artillery npm i -g serverless@1.83.3 npm i -g serverless-artillery - name: run test env: AWS_SECRET_ACCESS_KEY: ${{secrets.AWS_SECRET_ACCESS_KEY}} AWS_ACCESS_KEY_ID: ${{secrets.AWS_ACCESS_KEY_ID}} run: | slsart invoke
実行すると下記のようになります。
まとめ
いかがでしたでしょうか
負荷試験はテスト自体の設計だけでなく、準備のコストも高いため継続的に実施が難しいですが、Serverless-artilleryのようにサーバレスで構築されたものであればリソースが足りず負荷が想定よりかけれてないなどの問題もなくなるのでテストの設計だけに集中できそうで良いなと思いました。