基本
1本のリクエストを送るところから始めて、人数を増やし、ログインを突破し、テストデータを散らします。 STEP 3 の「相関」が JMeter 学習の最大の山場です。ここを越えれば大半のサイトを相手にできます。
STEP 1 ・ 最初の1本を自分で作る
完成品を開くのは後にします。まず自分でゼロから組んでください。 最小構成は「スレッドグループ・HTTPリクエスト・リスナー」の3つだけです。
操作
- JMeter を起動し、左の Test Plan を右クリック → 追加 → Threads(Users) → スレッドグループ
- できたスレッドグループを右クリック → 追加 → サンプラー → HTTPリクエスト
- HTTPリクエストの設定パネルに、次を入力する
| 項目 | 入れる値 |
|---|---|
| プロトコル | http |
| サーバ名またはIP | localhost |
| ポート番号 | 8080 |
| メソッド | GET |
| パス | /api/products |
- もう一度スレッドグループを右クリック → 追加 → リスナー → 結果を表示(ツリー)
- Ctrl+S で保存(名前は
my-first.jmxなど) - 上部の緑の ▶ を押す
期待値
「結果を表示(ツリー)」に緑色の三角が1件現れます。 クリックすると右側にタブが3つ出ます。
- サンプラー結果 … 応答コード
200、Load time が数ms〜数十ms - リクエスト … 実際に送った内容
- 応答データ …
{"items":[{"id":1,"name":"...という JSON が返っている
赤くなったら
Connection refused … 練習台が起動していません。docker compose ps で確認。
404 … パスの綴りミス。/api/products です。
502 … アプリがまだ起動中。30秒待ってもう一度。
結果の読み方 — 3つの時間の違い
「サンプラー結果」タブには時間が3つ出ます。この違いが分からないと原因分析ができません。
| 名前 | 意味 | ここが大きいときに疑うもの |
|---|---|---|
| Connect Time | 接続が確立するまで | ネットワーク、TCPの詰まり、サーバーの接続数上限 |
| Latency | 最初の1バイトが返ってくるまで | サーバー側の処理時間(DBが遅い、CPUが忙しい) |
| Load time | 全部受け取り終わるまで | Latency との差が大きいならデータ量が多い・回線が細い |
読み分けの例
Latency 20ms / Load time 800ms → サーバーの処理は速いが、データが重い。
画像やJSONを削る方向で改善する。
Latency 800ms / Load time 810ms → サーバーが遅い。DBやアプリを疑う。
やってみる:データ量を増やすと何が変わるか
HTTPリクエストのパスを /api/products?size=100 に変えて実行してください
(1ページ20件→100件になります)。
期待値
Load time と受信バイト数が増えます。一方 Latency はさほど変わりません。 「重いのは処理ではなく転送量だ」ということが数字で見える、という体験がここでの目的です。
STEP 2 ・ 人数を増やす
操作
スレッドグループを選び、次のように変えます。
| 項目 | 値 | 意味 |
|---|---|---|
| スレッド数 | 10 | 10人が同時に使う |
| Ramp-up期間(秒) | 10 | 10秒かけて1人ずつ増える |
| ループ回数 | 5 | 1人あたり5回繰り返す |
さらにスレッドグループを右クリック → 追加 → リスナー → 集計レポート を足して実行します。
期待値
集計レポートに サンプル数 50(10人 × 5回)と表示されます。 エラー% は 0.00%、平均は数ms〜数十msのはずです。
実行中に「結果を表示(ツリー)」を見ていると、 最初はぽつぽつ、10秒後には一気に結果が増えていくのが分かります。これが Ramp-up です。
つまずきポイント
Ramp-up を 0 にすると10人が同時に殺到します。試してみると応答時間が跳ね上がりますが、
これは現実の利用者の動きではありません。
「開店直後の殺到」を再現したいとき以外は、数十秒かけるのが基本です。
平均値は嘘をつく
集計レポートには数字がたくさん並んでいますが、見るべきものは決まっています。
| 列 | 見るべきか | 理由 |
|---|---|---|
| Average(平均) | 参考程度 | 1件だけ10秒かかっても、他が速ければ平均は小さいまま |
| Median(中央値) | 参考程度 | 半分の人の体感。悪い方の半分が見えない |
| 90% Line | 見る | 10人に1人がこれ以上待たされる。実務の合格基準に使う |
| 95% Line / 99% Line | 見る | 厳しい基準。SLAを決めるときはこちら |
| Max | 見る | 最悪ケース。ここが極端なら何かが詰まっている |
| Error % | 必ず見る | 速くても失敗していたら意味がない |
| Throughput | 見る | システムの処理能力そのもの |
なぜ平均を見てはいけないのか
100人のうち99人が 50ms、1人が 10秒かかったとします。平均は 149ms で「速い」ように見えますが、 実際には10秒待たされて離脱した人が確実に存在します。 90%Line と Max を見れば、この1人を見逃しません。
コマンドで実行する
ここまでは GUI で実行してきましたが、本当の計測は必ずコマンドで行います。 GUI は画面描画に CPU を使うため、負荷をかけると JMeter 自身が遅くなり、測定値が汚れます。
この教材では JMeter も Docker で用意してあるので、次の1行で実行できます。
cd M:\html\jmetertest
docker compose run --rm jmeter 01_smoke.jmx
期待値(実測値)
=== JMeter 実行: 01_smoke.jmx ===
対象 : http://nginx:80
結果 : jmeter/results/01_smoke-20260908-211011/
Created the tree successfully using /tests/01_smoke.jmx
Starting standalone test
summary = 9 in 00:00:00 = 25.9/s Avg: 11 Min: 2 Max: 42 Err: 0 (0.00%)
=== 完了 ===
HTMLレポート: jmeter/results/01_smoke-20260908-211011/report/index.html
Err: 0 (0.00%) であることが最重要です。
最後に出るパスの report/index.html をブラウザで開くと、
グラフ付きの正式なレポートが見られます。
summary 行の読み方
9 in 00:00:00 = 25.9/s → 9件を0秒台で処理、毎秒25.9件
Avg: 11 Min: 2 Max: 42 → 平均11ms、最速2ms、最遅42ms
Err: 0 (0.00%) → エラー0件
自分で作ったプランをコマンドで動かす
ローカルに JMeter を入れた場合は、次の形が基本形です。
C:\jmeter\apache-jmeter-5.6.3\bin\jmeter.bat -n -t my-first.jmx -l result.jtl -e -o report
| オプション | 意味 |
|---|---|
-n | GUIを使わない(これが本番モード) |
-t | 実行するテストプラン(.jmx) |
-l | 生の結果の出力先(.jtl。中身はCSV) |
-e -o | 終了後にHTMLレポートを指定フォルダに生成する |
つまずきポイント
-o で指定するフォルダは空でなければエラーになります。
毎回別の名前にするか、実行前に消してください。
STEP 3 ・ 相関 — 最大の山場
ここが JMeter で最初にして最大の壁です。実際のサイトは、 ログイン画面に毎回変わる隠しトークン(CSRFトークン)を埋め込んでいます。 これを送らないと弾かれるので、先に画面を1回取得して、そこから値を抜き出して次のリクエストに渡す 必要があります。これを相関(correlation)と呼びます。
① GET /login → HTMLが返る
<input type="hidden" name="_csrf" value="4f72294ca6ef0e4b...">
↑ここを正規表現で抜き出す
② POST /login → 抜き出した値を一緒に送る
_csrf=4f72294ca6ef0e4b... & email=... & password=...
→ 成功。ログイン後の画面が返る
操作
用意されたプラン 02_login_html.jmx を JMeter で開いてください
(ファイル → 開く → M:\html\jmetertest\jmeter\testplans\02_login_html.jmx)。
ツリーの中の GET /login(フォーム表示) の子に 正規表現抽出 があります。中身はこうなっています。
| 項目 | 値 | 意味 |
|---|---|---|
| 参照名 | csrf | 抜いた値を ${csrf} という名前で使えるようにする |
| 正規表現 | name="_csrf" value="([0-9a-f]+)" | 丸カッコの中が抜き出される部分 |
| テンプレート | $1$ | 1個目の丸カッコを使う、という意味 |
| 一致番号 | 1 | 複数見つかったら1個目 |
| デフォルト値 | CSRF_NOT_FOUND | 抜けなかったときに入る値。必ず設定する |
次に POST /login(認証) のパラメータを見てください。${csrf} が使われています。
docker compose run --rm jmeter 02_login_html.jmx
期待値(実測値)
summary = 40 in 00:00:13 = 3.0/s Avg: 8 Min: 2 Max: 51 Err: 0 (0.00%)
Err: 0 (0.00%) なら相関が成功しています。 エラーが出る場合はトークンの抽出に失敗しています。
わざと壊してみる — 相関の失敗を体験する
うまくいく状態だけ見ても身につきません。失敗した状態を自分の目で見てください。
操作
- JMeter の GUI で
02_login_html.jmxを開く - 正規表現抽出 を選び、正規表現を次のように書き換える
value="([0-9]+)"
- スレッド数を
1、ループ回数を1にして GUI で実行 - 「結果を表示(ツリー)」で POST /login を見る
期待値 — 失敗の見え方
- POST /login が赤い三角になる
- 応答コードが
403 - 応答データに「CSRFトークンが不正です」という文字列が入っている
- アサーションのメッセージに 「ログインに失敗しています。CSRFトークンの抽出を確認してください。」と出る
ここで覚えること
実務でテストが通らないとき、原因の大半はこの相関の失敗です。 調べ方は決まっています。
- 抽出元のレスポンス(応答データタブ)に、狙った文字列が本当に存在するか目視する
- デバッグサンプラー(追加 → サンプラー → デバッグサンプラー)を置いて、変数に何が入っているか見る
- デフォルト値(
CSRF_NOT_FOUND)がそのまま入っていたら、抽出が失敗している証拠
確認できたら、正規表現を元に戻してください。
name="_csrf" value="([0-9a-f]+)"
相関でよく使う3つの道具
| 道具 | 使う場面 | 指定するもの |
|---|---|---|
| 正規表現抽出 | HTMLから値を抜く | 正規表現(丸カッコで囲った部分が抜ける) |
| JSON抽出 | JSON APIから値を抜く | JSONPath(例 $.token) |
| 境界抽出 | 前後の文字列で挟んで抜く | 左境界と右境界(正規表現が苦手な人向け) |
Cookieマネージャを忘れずに
ログインの成功はCookie(セッションID)で維持されます。
HTTPクッキーマネージャをスレッドグループの直下に置いていないと、
ログインした直後から「ログインしていない人」に戻ります。
02_login_html.jmx には入っているので、外して実行すると挙動の違いが確認できます。
STEP 4 ・ データを散らす
ここまでのテストは、全スレッドが同じユーザーでログインしていました。 これは負荷試験で最もよくある嘘です。同じデータばかり触ると データベースのキャッシュに乗りっぱなしになり、本番ではありえない速度が出ます。
対策が CSV Data Set Config です。用意されたファイルを使って、 2,000人のユーザーを各スレッドに配ります。
email,password
user0001@example.com,pass1234
user0002@example.com,pass1234
02_login_html.jmx のスレッドグループ直下にある users.csv を読む の設定を見てください。
| 項目 | 値 | 意味 |
|---|---|---|
| ファイル名 | ../data/users.csv | jmxファイルからの相対パス |
| 変数名 | email,password | ${email} ${password} で使える |
| 最初の行を無視 | true | 見出し行を読み飛ばす |
| EOFでリサイクル | true | 末尾まで行ったら先頭に戻る |
| 共有モード | すべてのスレッド | 全員で1本のファイルを共有し、1行ずつ配る |
共有モードの落とし穴
共有モードを「現在のスレッド」にすると、各スレッドが独立してファイルの先頭から読みます。 つまり全員が user0001 でログインします。 データを散らすつもりが散っていない、という事故が起きるので、 迷ったら「すべてのスレッド」を選んでください。
確認
GUI でスレッド数を 5 にして実行し、「結果を表示(ツリー)」で POST /login の リクエストタブを何件か見比べてください。
期待値
送信内容の email= が
user0001@example.com、user0002@example.com、user0003@example.com…
と1件ずつ違うユーザーになっていること。
全部同じなら共有モードの設定を見直してください。
STEP 1-4 完了の判定
- 自分でゼロからプランを作って実行できた
- Latency と Load time の違いを説明できる
- 90%Line を見る理由を説明できる
- コマンド(
-n)で実行して HTML レポートを開けた - 相関をわざと失敗させて、403 になるのを確認した
- CSV でユーザーが1件ずつ違うことを確認した