JMeterで負荷テストを始める
Apache JMeterの基本概念・コンポーネントの理解からTest Planの作成、CLI実行、HTMLレポートの確認まで
この記事でやること
- JMeterをインストールする
- 主要コンポーネントを理解する
- テスト対象のHTTPサーバーを用意する(Node.js組み込みモジュールで3行)
- GUIでTest Planを作り、実行する
- JMXファイルをCLIで実行する
- HTMLレポートを確認する
インストール
Javaが必要(JDK 11以上を推奨)。先にバージョンを確認する。
java -versionmacOS(Homebrew)
brew install jmeterインストール後、jmeter コマンドでGUIが起動する。
Linux / Windows
Apache JMeterの公式サイト(https://jmeter.apache.org/download_jmeter.cgi)からzipをダウンロードし、解凍した bin/jmeter(Linux/macOS)または bin/jmeter.bat(Windows)で起動する。
主要コンポーネント
JMeterのTest Planは複数のコンポーネントを積み重ねて作る。
| コンポーネント | 分類 | 役割 |
|---|---|---|
| Test Plan | — | テスト全体のルート。JMXファイル1つが1つのTest Plan |
| Thread Group | Threads | 仮想ユーザー数・ループ回数・Ramp-upを設定する |
| HTTP Request | Sampler | 実際にHTTPリクエストを送る要素 |
| HTTP Request Defaults | Config Element | Thread Group内の全Samplerに共通するホスト・ポートを一括設定する |
| Counter | Config Element | テストごとに連番を生成する(ユニークなデータを作るときに使う) |
| HTTP Header Manager | Config Element | リクエストヘッダー(Content-Type 等)を設定する |
| Summary Report | Listener | 集計結果をテーブル表示する(CLIでは標準出力に出る) |
| View Results Tree | Listener | リクエスト・レスポンスの詳細を1件ずつ確認できる(デバッグ用) |
| Constant Timer | Timer | 各リクエストの前に一定の待機時間を挟む |
Thread Groupの3つの設定
| 設定名 | 意味 |
|---|---|
| Number of Threads (users) | 並行して動かす仮想ユーザー数 |
| Ramp-up Period (seconds) | 全スレッドを起動し終えるまでの秒数。10スレッド / 2秒 なら0.2秒ごとに1スレッドずつ立ち上がる |
| Loop Count | 1スレッドが何回ループするか。10スレッド × 10ループ = 100リクエスト |
テスト対象サーバーを用意する
JMeterのテストはHTTPを返すサーバーであれば何でもよい。ここではNode.js組み込みの http モジュールだけで動く最小サーバーを使う。
// test-server.js
const http = require('http');
const server = http.createServer((req, res) => {
res.writeHead(200, { 'Content-Type': 'application/json' });
res.end(JSON.stringify({ ok: true, path: req.url }));
});
server.listen(3000, () => {
console.log('http://localhost:3000 で起動中');
});node test-server.jsこれで http://localhost:3000 がJSONを返すようになる。JMeterを動かす間はこのターミナルを残しておく。
GUIでTest Planを作る
jmeter # GUIが起動する手順
① Thread Groupを追加する
左ペインの「Test Plan」を右クリック → Add → Threads (Users) → Thread Group
- Number of Threads:
10 - Ramp-up Period:
1 - Loop Count:
10
→ 10スレッド × 10ループ = 100リクエスト
② HTTP Request Defaultsを追加する(省略可)
「Thread Group」を右クリック → Add → Config Element → HTTP Request Defaults
- Server Name or IP:
localhost - Port Number:
3000
これを入れておくと、HTTP Requestサンプラーにホストとポートを毎回書かずに済む。
③ HTTP Requestを追加する
「Thread Group」を右クリック → Add → Sampler → HTTP Request
- HTTP Request Defaultsを使う場合: Server Name、Port はデフォルトのままでよい
- Method:
GET - Path:
/
④ Listenerを追加する
「Thread Group」を右クリック → Add → Listener → Summary Report
デバッグ時は同じく → Add → Listener → View Results Tree も追加する
⑤ 保存して実行する
File → Save(test-plan.jmx など任意の名前で保存)
Ctrl + R(またはRun → Start)で実行
View Results Treeで確認できること
実行後、各行をクリックすると詳細を確認できる。
- 緑 → 成功(2xx)
- 赤 → 失敗(エラーや 4xx/5xx)
- 「Request」タブで送ったリクエスト、「Response」タブでレスポンスボディを確認できる
デバッグが終わったら View Results Tree を右クリックして「Disable」にする。全レスポンスをメモリに溜めるため、大量リクエスト時にJMeter自体が重くなる原因になる。
JMXファイルのサンプル
GUIを使わずに手元にJMXファイルを置きたい場合は、次のXMLをそのまま使える。test-plan.jmx などの名前で保存する。
<?xml version="1.0" encoding="UTF-8"?>
<jmeterTestPlan version="1.2" properties="5.0">
<hashTree>
<TestPlan guiclass="TestPlanGui" testclass="TestPlan" testname="Sample Test Plan">
<elementProp name="TestPlan.user_defined_variables" elementType="Arguments">
<collectionProp name="Arguments.arguments"/>
</elementProp>
</TestPlan>
<hashTree>
<ThreadGroup guiclass="ThreadGroupGui" testclass="ThreadGroup" testname="Thread Group">
<intProp name="ThreadGroup.num_threads">10</intProp>
<intProp name="ThreadGroup.ramp_time">1</intProp>
<stringProp name="ThreadGroup.on_sample_error">continue</stringProp>
<elementProp name="ThreadGroup.main_controller" elementType="LoopController">
<boolProp name="LoopController.continue_forever">false</boolProp>
<intProp name="LoopController.loops">10</intProp>
</elementProp>
</ThreadGroup>
<hashTree>
<HTTPSamplerProxy guiclass="HttpTestSampleGui" testclass="HTTPSamplerProxy" testname="GET /">
<stringProp name="HTTPSampler.domain">localhost</stringProp>
<intProp name="HTTPSampler.port">3000</intProp>
<stringProp name="HTTPSampler.path">/</stringProp>
<stringProp name="HTTPSampler.method">GET</stringProp>
<boolProp name="HTTPSampler.follow_redirects">true</boolProp>
<boolProp name="HTTPSampler.use_keepalive">true</boolProp>
</HTTPSamplerProxy>
<hashTree/>
<ResultCollector guiclass="SummaryReport" testclass="ResultCollector" testname="Summary Report">
<boolProp name="ResultCollector.error_logging">false</boolProp>
<objProp>
<name>saveConfig</name>
<value class="SampleSaveConfiguration">
<time>true</time>
<latency>true</latency>
<timestamp>true</timestamp>
<success>true</success>
<label>true</label>
<code>true</code>
<message>true</message>
<threadName>true</threadName>
<dataType>true</dataType>
<encoding>false</encoding>
<assertions>true</assertions>
<subresults>true</subresults>
<responseData>false</responseData>
<samplerData>false</samplerData>
<xml>false</xml>
<fieldNames>true</fieldNames>
<responseHeaders>false</responseHeaders>
<requestHeaders>false</requestHeaders>
<responseDataOnError>false</responseDataOnError>
<saveAssertionResultsFailureMessage>true</saveAssertionResultsFailureMessage>
<bytes>true</bytes>
<sentBytes>true</sentBytes>
<url>true</url>
<threadCounts>true</threadCounts>
<idleTime>true</idleTime>
<connectTime>true</connectTime>
</value>
</objProp>
<stringProp name="filename"></stringProp>
</ResultCollector>
<hashTree/>
</hashTree>
</hashTree>
</hashTree>
</jmeterTestPlan>CLIで実行する
GUIは設定確認に便利だが、CIに組み込んだり繰り返し実行するにはCLIが適している。
# 実行のみ(結果をJTLファイルに出力)
jmeter -n -t test-plan.jmx -l results.jtl
# 実行 + HTMLレポートも同時に生成
jmeter -n -t test-plan.jmx -l results.jtl -e -o ./report| オプション | 意味 |
|---|---|
-n | non-GUIモード(CLIで実行) |
-t | 使用するJMXファイルを指定する |
-l | 結果をJTLファイルに書き出す |
-e | テスト終了後にHTMLレポートを生成する |
-o | HTMLレポートの出力先ディレクトリ |
./report が既に存在するとエラーになる。再実行するときは先に削除する。
rm -rf ./report && jmeter -n -t test-plan.jmx -l results.jtl -e -o ./report結果の読み方
CLIの標準出力やGUIのSummary Reportに表示されるカラムの意味。
| カラム | 単位 | 意味 |
|---|---|---|
| # Samples | 件 | 送ったリクエストの総数 |
| Average | ms | 平均レスポンスタイム |
| Min / Max | ms | 最小 / 最大レスポンスタイム |
| 90th pct | ms | 90パーセンタイル(100件中90件がこの時間以内に完了) |
| Throughput | req/s | 1秒あたりの処理件数 |
| Received KB/s | KB/s | 受信データ量 |
| Error % | % | エラーになったリクエストの割合 |
見るべき指標
Error % が 0 であることをまず確認する。エラーがあれば View Results Tree で原因(ステータスコード・レスポンスボディ)を確認する。
Throughput(req/s) が高いほど処理能力が高い。ただし、ローカルでのループバック接続はネットワーク遅延がほぼ0のため、実際の本番環境とは数値が異なる。「同じ環境での設定変更前後の比較」や「ボトルネックの相対的な特定」に使うイメージが正しい。
90th pct が Average よりはるかに大きい 場合、一部のリクエストだけ極端に遅い(外れ値がある)ことを示す。全体の平均が良くても90th pctが大きければ、一部のユーザーが遅延を体験していることになる。
HTMLレポートを確認する
open ./report/index.html # macOSStatistics タブにSummary Reportと同じ集計値が表示される。
Charts タブにレスポンスタイムの時系列グラフが表示される。スループットが途中から落ちている、レスポンスタイムが後半に悪化しているといった傾向を視覚的に確認しやすい。
実装チェックリスト
- JDKのバージョンを確認する(11以上)
- JMeterをインストールし
jmeterコマンドでGUI起動を確認する -
test-server.jsを起動してレスポンスを確認する - GUIでTest Plan(Thread Group + HTTP Request + Summary Report)を作成する
- GUIで実行し、Summary Report の Error % が 0 になることを確認する
- JMXファイルを保存してCLIで実行する(
-n -t -l -e -oオプション) -
./report/index.htmlでHTMLレポートを確認する