Artilleryを使った負荷テスト・性能テストの実行

Artilleryを使った負荷テスト・性能テストの実行

紹介

性能テストとは?なぜ負荷テストを実行すべきか?

性能テストは、ソフトウェアの試験であり、様々ワークロードでアプリケーションの稼働状況を評価することです。

性能テストは、パフォーマンスが低下したり障害が発生したりすることなくユーザーからの想定リクエスト数をアプリケーションが処理できるのを確保するため、応答時間、帯域幅、拡張性といった色々な情報を測定します。

性能テストは、パフォーマンスに関わる問題やボトルネックを特定することもでき、パフォーマンスの最適化のために必要な変更を行うのに役立ちます。 この目的としては、高負荷状態でもスムーズで速やかな、信頼性の高いユーザー体験をアプリケーションが提供できるように確保するためです。

Artillery.ioについての紹介

Artillery.ioはWebアプリケーション、API サービス、マイクロサービスのパフォーマンスと拡張性を確認するために使われるオープンソースの性能試験ツールです。ユーザーの実際操作を模倣して複数のソースから負荷を生成することでシナリオ通りにアプリケーションを確認することができます。

プロトコルのサポート

Artillery.ioはNode.jsで作成されて、HTTP、Websocket、socket.io. の各プロトコルをサポートします。

その他に、Artilleryのプラグインを使うことで、HLS(HTTP Live Streaming)、Amazon Kinesis、 Apache Kafkaといったスタックを確認することができます。

スクリプトの形式

Artillery.ioは他の一般的なテストツールとは異なり、負荷テストのシナリオを定義するため、柔軟な YAMLベースの構文を提供します。また、JSON形式もサポートします。

インストールおよび基本機能

インストール

以下のように、npmかyarnのコマンドを使うことでArtillery.ioをグローバルな依存関係でインストールことができます。

#npm
npm install -g artillery
#yarn
yarn global add artillery

或いは、以下のようにコマンドを使うことでNode.jsプロジェクトで開発的な依存関係でインストールすることもできます。

npm install -D artillery

簡易テスト

quickサブコマンドを使うことでテストスクリプトを作成せずにテストを実施することができます。例えば、10名の仮想ユーザー(VUs)が実行し、ユーザー毎に「http://localhost:3000/:」へリクエストを20回送信する場合、以下のようになります。

artillery quick -c 10 -n 20 http://localhost:3000/api/user

「-c」パラメーターはVUの総数を指定し、「-n」パラメーターは1名のVUあたりのリクエスト数を指定します。

テストスクリプト実行

runサブコマンドはテストスクリプトをローカルマシンから実行するために使われます。テストを実行する基本方法は以下の通りです。

artillery run script.yaml -o report.json

「-o」パラメーターはJSON帳票をあるファイルに書き込むためのオプションです。

帳票出力

artillery report report.json -o report.html

reportサブコマンドを使うことで、runサブコマンドで生成されたJSON帳票を新しいHTML帳票に変換することができます。

簡単な負荷テストの作成

下記の説明のように、YAML構文を使用します。まず、「script.yml」のようなファイル名を作成しておきます。次に、ファイルの上部にあるコンフィグを定義します。

コンフィグ

「target」オプションを使用してテスト スクリプトのベースURLを設定する必要があります。

config:
  target: "http://localhost:3000/api"

次に、ロード フェーズの定義を開始します。ロード フェーズは、指定された期間内にArtilleryが新しい VU を生成する方法を定義します。

config:
  ...
  phases:
    - duration: 60
      arrivalRate: 100

シナリオ

一つまたは複数のシナリオを定義することができます。シナリオの定義はそれぞれで「flow」プロパティのあるオブジェクトです。

scenarios:
  - name: "Get All Users"
    flow:
      - get:
          url: "/user"
          qs:
            limit: 10
            offset: 20

「flow」プロパティには、HTTPの メソッドをオブジェクト属性として定義することができます。その後、API のパスを確定する必要があります。また、URL-encoded forms、Multipart forms、JSONといったform bodyやquery stringをセットできます。

スクリプトを保存してから、テストスクリプトとして実行することができます。

実際のユーザーフロー

例えば、以下のようにユーザーフローがあります。

config:
  target: "http://localhost:3000/api"
  phases:
    - duration: 120
      arrivalRate: 10
      name: "Preparing"
    - duration: 240
      arrivalRate: 30
      rampTo: 100
      name: "Increasing"
    - duration: 600
      arrivalRate: 100
      name: "Sustained Load"
  payload:
    path: "login.csv"
    cast: false
    fields:
      - "user"
      - "pass"
  processor: "./processor.js"

before:
  flow:
    - log: "Get auth token"
    - post:
        url: "/auth/login"
        json:
          username: "{{user}}"
          password: "{{pass}}"
        capture:
          - json: $.tokens.accessToken
            as: token
scenarios:
  - name: "Search Users"
    flow:
      - get:
          url: "/user"
          headers:
            authorization: "Bearer {{ token }}"
  - name: "Create New User"
    flow:
      - post:
          url: "/user"
          beforeRequest: "setJsonBody"
          headers:
            authorization: "Bearer {{ token }}"

上記のスクリプトでは、コンフィグに3つのフェーズがあります。

  • 第1フェーズでは、1 秒あたり 10 個の VU を生成してアプリケーションへ2分以内で送信します。
  • 第2フェーズでは、負荷テストは 1 秒あたり 30名のユーザーで行い、、4 分以内で 1 秒あたり 100名のユーザーまで徐々に増加します。
  • 第3フェーズでは、10分以内で1 秒あたり 100名の ユーザーで連続的に負荷テストを行います。

複数のフェーズを使用することで、実際のアクセス数のシナリオを正確にシミュレートし、いきなり送信してくるリクエストを一括に処理するアプリケーションの性能を評価することができます。

シナリオの第1フローで、各 VU からは GET | “Search user” へリクエストを送信します。次に、第2フローで POST | “Create user”へリクエストを送信します。

データを生成しやすくなるため、リクエストする前にbeforeRequestというカスタマイズフック上でのsetJsonBody関数を使用します。setJsonBody関数はprocessor.jsファイルで定義され、config.processorで参照されます。

# processor.js
const { faker } = require("@faker-js/faker");

function setJsonBody(requestParams, context, ee, next) {
  var body = {
    username: faker.internet.userName(),
    password: faker.internet.password(3),
    email: faker.internet.exampleEmail(),
    name: faker.name.fullName(),
    role: faker.datatype.number({ min: 0, max: 1 }),
  };

  requestParams.json = body;
  return next();
}

module.exports = {
  setJsonBody,
};

K6と比較

ArtilleryとK6の両方はオープンソースの性能試験ツールであり、拡張性、CI/CD ツールとの統合、テストパターンの設定機能といった同様の機能を持っていますが、いくつかの違いがあります。ArtilleryはNode.jsで作成されましたが、K6はGoで作成されました。そのため、Artilleryはマルチスレッドではなく、メモリー使用量もより多いので、K6より遅いです。以下に、K6 と Artillery およびその他のツールの間のメモリ使用量を比較したグラフを示します。

メモリー使用

VU毎のメモリー使用量

結論として、ArtilleryとK6のどちらも強力なツールです。しかし、K6はArtilleryより利点が多いです。簡単な負荷テストを作成する場合、YAML構文を使用するArtilleryが最適なソリューションです。

参考元

https://www.artillery.io/
https://k6.io/blog/comparing-best-open-source-load-testing-tools/