AWS EC2を使用したJMeterの分散テスト実行方法

# 目的
この記事では、1つのコントローラーノードと、複数のワーカーノードを使って、1つのサービスに対してJMeterベースの負荷テストを実行する手順をまとめてあります。なお、本稿は[AWS EC2でJMeterを実行しよう](https://qiita.com/toto2/items/560a21d0072250d087ec)で説明したEC2を使ったJMeterによる負荷テストを、分散ノードでの実行に拡張したものです。

# JMeterによる分散テストの概要

JMeterで分散テストを実行する際は、WorkerとContorollerの２種類のノードを用意する必要があります。ContorollerノードでJMeterのテスト内容を設定・開始し、実際のリクエストはWorkerノードが実行します。
```mermaid
graph TD;
    A[Controller Node<br>192.168.0.2] --> B[Worker Node 1<br>192.168.0.3]
    A --> C[Worker Node 2<br>192.168.0.4]
    B --> D[Target Service]
    C --> D
    subgraph Worker Nodes
        B
        C
    end

```
JMeterを使用した分散テストでは、コントローラーノードとすべてのワーカーノードが同じサブネット内にある必要があります（プロキシを使用しない限り）。
# 設定
## ノードの準備
まずは、テストで使用するコントローラーノードとワーカーノードを準備します。前述のとおり、すべて同一のサブネット内に置いておく必要があります。今回は、AWS EC2で以下のようにノードを準備しました。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3636063/5c67c6b9-52b7-e019-90fe-be4a70d9187e.png)
（余談）当初、t2.microで実行しようとしたところ、メモリ要件を満たさないとのことだったのでc5.xlargeを使用しています。メモリ要件については公式ドキュメントにも言及がなくやや謎です。

## ワーカーノード構成の設定
テストに使用するワーカーノードの構成はコントローラーノードに配置するjmeter.propertiesファイル内で設定できます。使用するワーカーノードを指定するために、jmeter.properties内の
```:jmeter.properties
remote_hosts=127.0.0.1
```
と書いてある部分を、実際に使用するリモートホストのプライベートIPアドレスに書き換えます。例えばワーカーノードのIPアドレスが（192.168.0.3, 192.168.0.4)である場合は、
```:jmeter.properties
remote_hosts=192.168.0.3,192.168.0.4
```
のように、カンマ区切りで入力します。

## テスト内容の設定（jmxファイルの作成）
JMeterのテスト内容はjmxファイルで設定します。GUIが使えるホストの場合、JMeterのGUIからjmxファイルを作成できます。GUI経由でのjmxファイルの作り方は

https://qiita.com/okoi/items/52d95a2d1642c4d68fc8

こちらに詳しく記載があります。

作成したjmxファイルは、コントローラーノードに配置します。コマンドラインから使用するjmxファイルのパスを指定できるため、コントローラーノード内のどこに配置しても大丈夫です。今回はローカルホストで作ったjmxファイルをscpでコントローラーノードに送信しました。
```bash: jmxファイルをscpでコントローラーノードに送信
scp -i (秘密鍵) /path/to/jmx_file/jmx_file.jmx ubuntu@(IPアドレス):/home/ubuntu
```
コントローラーノードがUbuntuではない場合、ホスト名や配置先ディレクトリは適宜変更してください。

## 各ノードの設定
JMeterを実行するすべてのノードでJMeterがインストールされている必要があります。コントローラーノードとすべてのワーカーノードで以下のコマンドを実行します。
```bash: JMeterのインストール
# aptのアップデート
$ sudo apt update
# JDKのインストール
$ sudo apt install openjdk-17-jre-headless
# JMeterプロジェクトの取得と解凍
$ wget https://dlcdn.apache.org//jmeter/binaries/apache-jmeter-5.6.3.tgz
$ tar vxzf apache-jmeter-5.6.3.tgz
```
また、JMeterの分散テストでは、ノードごとの通信プロトコルにRMI（Remort Method Invocation）が使われるため、RMIのためのSSLを設定する必要があります。
```bash: RMIのためのSSLの設定
cd jmeter/bin
./create-rmi-keystore.sh
```
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3636063/5efbe9f7-ef75-beb8-1c62-451db621101e.png)
(https://jmeter.apache.org/usermanual/remote-test.html#setup_ssl）
jmeter/bin/create-rim-keystore.shを実行すると、上記のように対話的に設定できます。

# 負荷テストの実行
## ワーカーノードのサービス開始
まずは各ワーカーノードでJMeterサービスを開始します。以下のコマンドを使用する各ワーカーノード実行することでサービスが開始され、待機状態になります。
```bash:SSHセッション：ワーカーノード
cd jmeter/bin
./jmeter-server
```

## リクエストの開始
コントローラーノードからリクエストを開始します。以下のコマンドを実行すると、jmeter.propetiesで設定したリモートホストのそれぞれで、jmxファイルで指定したプロファイルのテストが実行されます。
```bash:SSHセッション：コントローラーノード
cd jmeter/bin
# ログを記録しない場合
./jmeter -n -t /your/jmx_file_path/your_jmx_file.jmx -r
# ログを記録する場合
./jmeter -n -t /your/jmx_file_path/your_jmx_file.jmx -r　-l /path/to/results.jtl
```
以下が実際に実行したときのコンソール画面です。
Contoroller: 172.31.34.117
Wokerer: 172.31.32.231, 172.31.38.73
という構成になっています。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3636063/626870dd-ac16-81f3-f3b4-b71b483c569d.png)

# JMeterの制限
JMeterは非常に優れた負荷テストツールですが、いくつか制限があります。

1. すべてのノードが同じサブネット内にある必要がある
1. 開始時刻を正確に設定することはできない
1. ノードごとに異なるテストケースを設定できない（つまり、すべてのワーカーノードは同じjmxファイルに従ったテストを行うことになる）
1. 各ノードはマニュアルで起動・設定しておく必要がある
1. ノード間の通信がRMIなので、オーバーヘッドが比較的大きい

# 参考
https://qiita.com/shotets/items/d553d7be0d407a9a9a53

https://qiita.com/ksh-fthr/items/1e76f9be5260b61c861c

https://qiita.com/okoi/items/52d95a2d1642c4d68fc8

https://qiita.com/toto2/items/560a21d0072250d087ec