STEP 1-4 ・ 所要 90分

基本

1本のリクエストを送るところから始めて、人数を増やし、ログインを突破し、テストデータを散らします。 STEP 3 の「相関」が JMeter 学習の最大の山場です。ここを越えれば大半のサイトを相手にできます。

STEP 1 ・ 最初の1本を自分で作る

観点 JMeter の最小構成を体で覚える 時間 20分

完成品を開くのは後にします。まず自分でゼロから組んでください。 最小構成は「スレッドグループ・HTTPリクエスト・リスナー」の3つだけです。

操作

  1. JMeter を起動し、左の Test Plan を右クリック → 追加 → Threads(Users) → スレッドグループ
  2. できたスレッドグループを右クリック → 追加 → サンプラー → HTTPリクエスト
  3. HTTPリクエストの設定パネルに、次を入力する
項目入れる値
プロトコルhttp
サーバ名またはIPlocalhost
ポート番号8080
メソッドGET
パス/api/products
  1. もう一度スレッドグループを右クリック → 追加 → リスナー → 結果を表示(ツリー)
  2. Ctrl+S で保存(名前は my-first.jmx など)
  3. 上部の緑の を押す

期待値

「結果を表示(ツリー)」に緑色の三角が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 ・ 人数を増やす

観点 スレッド数と Ramp-up の意味を体で覚える 時間 20分

操作

スレッドグループを選び、次のように変えます。

項目意味
スレッド数1010人が同時に使う
Ramp-up期間(秒)1010秒かけて1人ずつ増える
ループ回数51人あたり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行で実行できます。

PowerShell — 用意されたプランをコマンド実行
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 を入れた場合は、次の形が基本形です。

PowerShell — 素の JMeter で実行
C:\jmeter\apache-jmeter-5.6.3\bin\jmeter.bat -n -t my-first.jmx -l result.jtl -e -o report
オプション意味
-nGUIを使わない(これが本番モード
-t実行するテストプラン(.jmx)
-l生の結果の出力先(.jtl。中身はCSV)
-e -o終了後にHTMLレポートを指定フォルダに生成する

つまずきポイント

-o で指定するフォルダは空でなければエラーになります。 毎回別の名前にするか、実行前に消してください。

STEP 3 ・ 相関 — 最大の山場

観点 ログインが必要なサイトにテストを通す 時間 30分

ここが 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%) なら相関が成功しています。 エラーが出る場合はトークンの抽出に失敗しています。

わざと壊してみる — 相関の失敗を体験する

うまくいく状態だけ見ても身につきません。失敗した状態を自分の目で見てください。

操作

  1. JMeter の GUI で 02_login_html.jmx を開く
  2. 正規表現抽出 を選び、正規表現を次のように書き換える
わざと間違える(16進数ではなく数字だけを探す)
value="([0-9]+)"
  1. スレッド数を 1、ループ回数を 1 にして GUI で実行
  2. 「結果を表示(ツリー)」で POST /login を見る

期待値 — 失敗の見え方

  • POST /login が赤い三角になる
  • 応答コードが 403
  • 応答データに「CSRFトークンが不正です」という文字列が入っている
  • アサーションのメッセージに 「ログインに失敗しています。CSRFトークンの抽出を確認してください。」と出る

ここで覚えること

実務でテストが通らないとき、原因の大半はこの相関の失敗です。 調べ方は決まっています。

  1. 抽出元のレスポンス(応答データタブ)に、狙った文字列が本当に存在するか目視する
  2. デバッグサンプラー(追加 → サンプラー → デバッグサンプラー)を置いて、変数に何が入っているか見る
  3. デフォルト値(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 ・ データを散らす

観点 全員が同じデータを使うと、本番より速い嘘の数字が出る 時間 20分

ここまでのテストは、全スレッドが同じユーザーでログインしていました。 これは負荷試験で最もよくある嘘です。同じデータばかり触ると データベースのキャッシュに乗りっぱなしになり、本番ではありえない速度が出ます。

対策が CSV Data Set Config です。用意されたファイルを使って、 2,000人のユーザーを各スレッドに配ります。

jmeter/data/users.csv (先頭3行)
email,password
user0001@example.com,pass1234
user0002@example.com,pass1234

02_login_html.jmx のスレッドグループ直下にある users.csv を読む の設定を見てください。

項目意味
ファイル名../data/users.csvjmxファイルからの相対パス
変数名email,password${email} ${password} で使える
最初の行を無視true見出し行を読み飛ばす
EOFでリサイクルtrue末尾まで行ったら先頭に戻る
共有モードすべてのスレッド全員で1本のファイルを共有し、1行ずつ配る

共有モードの落とし穴

共有モードを「現在のスレッド」にすると、各スレッドが独立してファイルの先頭から読みます。 つまり全員が user0001 でログインします。 データを散らすつもりが散っていない、という事故が起きるので、 迷ったら「すべてのスレッド」を選んでください。

確認

GUI でスレッド数を 5 にして実行し、「結果を表示(ツリー)」で POST /login の リクエストタブを何件か見比べてください。

期待値

送信内容の email=user0001@example.comuser0002@example.comuser0003@example.com… と1件ずつ違うユーザーになっていること。 全部同じなら共有モードの設定を見直してください。

STEP 1-4 完了の判定

  • 自分でゼロからプランを作って実行できた
  • Latency と Load time の違いを説明できる
  • 90%Line を見る理由を説明できる
  • コマンド(-n)で実行して HTML レポートを開けた
  • 相関をわざと失敗させて、403 になるのを確認した
  • CSV でユーザーが1件ずつ違うことを確認した