セッション管理があるWebアプリのJMeter負荷テスト:sessionKey動的化のハマりどころ

Development
スポンサーリンク
スポンサーリンク

はじめに

JMeterでシナリオを記録し、実行ボタンを押したらいきなりConnection resetや500エラーで止まった——セッション管理のあるJavaのWebアプリを対象に負荷テストを組んだことがある人なら、一度は経験する壁だと思います。

筆者は実務でJavaアプリの画面負荷テストにJMeterを使った際、まさにこの壁にぶつかりました。原因は、ログインのたびにサーバーが発行するsessionKey(セッション識別用のパラメータ)が、シナリオ記録時の値のままJMXファイルに固定値として書き込まれてしまうことでした。この記事は、その実体験をベースにしたJMeter実務体験記シリーズの4本目として、sessionKeyの動的化(パラメータ化)を深掘りします。

JMeterの基本操作がまだの方は、まず基本編(JMeterとは?基本概念とインストール)と、ブラウザ操作をそのまま記録する方法を扱ったシナリオ記録実践ガイドを先に読んでおくことをおすすめします。この記事は「シナリオの記録は終わっているが、再生すると途中でエラーになる」という状態から話を始めます。


スポンサーリンク

この記事で分かること

  • セッション管理があるWebアプリで、記録したシナリオをそのまま再生できない理由
  • 正規表現抽出器(Regular Expression Extractor)を使ったsessionKeyの動的取得手順
  • 抽出した値をJMXファイル内の後続リクエストへ反映させる方法(一括置換の実践)
  • 一括置換で実際にハマったポイントと回避策
  • 動的化が正しくできているかを検証する具体的な手順

スポンサーリンク

なぜ「記録したシナリオをそのまま再生」が通用しないのか

JMeterのHTTP(S) Test Script Recorderでブラウザ操作を記録すると、その時にブラウザとサーバーの間でやり取りされたすべてのパラメータがそのままJMXファイルに書き込まれます。ログインID・パスワードのような固定値なら問題ありませんが、厄介なのはログインのたびにサーバーが動的に発行する値です。

多くのJava系Webアプリ(Spring Boot・Struts系フレームワークなど)では、セッションを以下の2つの仕組みで二重に管理しています。

仕組み内容
Cookie(JSESSIONIDJMeterのHTTPクッキーマネージャが自動的に管理・引き継いでくれる
URLパラメータ/POSTパラメータのsessionKey(アプリ独自の命名の場合もある)JMeterが自動では面倒を見てくれない。記録時の値がJMXにハードコードされる

再生時、HTTPクッキーマネージャのおかげで新しいJSESSIONIDは正しく発行されるのですが、URLパラメータのsessionKeyは記録時の固定値のまま送信されてしまいます。サーバー側がこの2つの整合性をチェックしている場合、「Cookieは新しいセッションなのに、sessionKeyは古い記録時の値」という矛盾した状態になり、サーバーがリクエストを拒否します。

実際に発生する症状はアプリの実装によってさまざまですが、代表的なものは以下の通りです。

  • Connection reset(コネクション強制切断)
  • 500 Internal Server Error
  • ログイン直後の画面(初期表示リクエスト)だけは成功し、その次のリクエストから失敗し始める(セッション確立自体は成功しているため)

この最後の特徴は原因の切り分けに役立ちます。「最初の1〜2リクエストだけ緑(成功)で、その後が軒並み赤(失敗)」というパターンが出たら、まずsessionKey系のパラメータを疑うというのが実務での経験則です。


正規表現抽出器でsessionKeyを動的に取得する

対処法は、ログイン直後のレスポンスからsessionKeyの値を毎回自動で読み取り、後続のリクエストに動的に渡すことです。JMeterではこれを「後処理(Post Processor)」の一つである**正規表現抽出器(Regular Expression Extractor)**で実現します。

Step 1: レスポンスの中身を確認する

まず、ログイン直後の画面初期表示リクエスト(記録時に最初に成功しているリクエスト)を「結果をツリーで表示」リスナーで選択し、「応答データ」タブでHTMLの中身を確認します。多くの場合、以下のようなhidden inputフィールドとしてsessionKeyの値が埋め込まれています。

<input type="hidden" id="sessionKey" name="sessionKey" value="1406005051" />

このvalue属性の値が、リクエストのたびに変わる動的な値です。フィールド名やid属性の付け方はアプリのフレームワークによって異なるため、まずは自分の対象システムでどう埋め込まれているかを確認するのが最初のステップになります。

Step 2: 正規表現抽出器を追加する

ログイン直後のリクエスト(初期表示リクエスト)を左ペインで選択し、右クリック→追加→後処理→正規表現抽出器を追加します。

設定項目設定値の例補足
参照名sessionKey以降${sessionKey}という変数名で参照できるようになる
正規表現id="sessionKey" value="(.+?)"実際のHTML構造に合わせて調整する。(.+?)が値をキャプチャする部分
テンプレート$1$1つ目のキャプチャグループを使う、という意味
一致番号(0でランダム)1複数マッチした場合に何番目を使うか。1件目でよければ1
初期値NOT_FOUND抽出に失敗した場合の値。失敗時にすぐ気づけるようにしておく

NOT_FOUNDを初期値にしておくと、抽出がうまくいかなかった場合にリクエストのパラメータにNOT_FOUNDという文字列がそのまま入るため、失敗に気づきやすくなります(数値が入るはずの場所に文字列が入っていれば一目瞭然です)。

設定後は必ずJMeterで保存し、この時点で一度1スレッドだけデバッグ実行して、変数${sessionKey}に実際の値が格納されているか(「結果をツリーで表示」の該当リクエストで、後処理タブや変数を確認)をチェックしておくと、次のステップで問題を切り分けやすくなります。


抽出した値を後続リクエストに反映させる(JMXファイルの一括置換)

正規表現抽出器を追加しただけでは、まだ何も変わりません。後続のすべてのリクエストで、記録時に固定値として埋め込まれたsessionKeyを${sessionKey}という変数参照に書き換える作業が必要です。

リクエスト数が数個であればJMeterのGUI上で1つずつ書き換えても構いませんが、実際の業務システムのシナリオでは数十〜数百箇所に同じ固定値が出現することも珍しくありません。この場合は、JMXファイル(実体はXML)をテキストエディタ・スクリプトで一括置換するのが現実的です。

一括置換の基本の流れ

  1. JMeterを閉じた状態でJMXファイルを開く(JMeterが開いたまま編集すると、保存時に上書きされてしまう)
  2. 記録時のsessionKey固定値(何箇所出現するか事前に検索して確認)を特定する
  3. 検索: [固定値の数値] → 置換: ${sessionKey} で一括置換する
  4. JMeterを再起動してJMXファイルを開き直し、デバッグ実行で確認する

以下はPowerShellでの置換スクリプトの例です(実際に使う際はファイルパス・置換対象の値を自分のJMXに合わせて書き換えてください)。

$file = 'jmx\scenario.jmx'
$bytes = [System.IO.File]::ReadAllBytes($file)
$text = [System.Text.Encoding]::UTF8.GetString($bytes)

# 記録時のsessionKey固定値を指定(記録ごとに値が変わるので事前に確認する)
$keys = @('-715584741', '-411593308')

foreach ($key in $keys) {
    $text = $text.Replace($key, '${sessionKey}')
}

$utf8NoBom = New-Object System.Text.UTF8Encoding $false
[System.IO.File]::WriteAllText($file, $text, $utf8NoBom)

Write-Host "置換完了"

JMXファイルはUTF-8のXMLなので、書き戻す際はBOMなしUTF-8で保存することを意識しておくと、後々の文字コード絡みのトラブルを避けられます。


一括置換で実際にハマったポイント

ここからが、実務でこの作業をやってみて実際につまずいた点です。単純な文字列置換に見えて、いくつか見落としやすい罠がありました。

1. sessionKeyの値が途中で複数存在するケース

一つのシナリオの中で、ログイン直後に発行される値と、別の画面に遷移した後に再発行される値の2種類が混在していることがありました。片方だけ置換して満足していると、後半のリクエストだけ失敗し続けるという状態になります。置換前に、JMXファイル内でそれらしき数値パターンが何種類・何箇所出現するかを必ず確認してから作業する習慣をつけておくと安全です。

2. 置換後に余分な数字が残ってしまうケース

JMeterのHTTPプロキシサーバーには、記録したリクエストの名前に連番を自動付与する機能があります。この連番がたまたまパラメータの値の末尾にくっついて記録されてしまうことがあり、単純な文字列置換をすると${sessionKey}-261のように変数の後ろに余計な数字が残るケースがありました。この場合は、置換後にさらに正規表現で末尾の余分な数字を除去する処理を挟む必要があります。

# ${sessionKey}-261 のような連番の残骸を除去
$text = [regex]::Replace($text, '\$\{sessionKey\}-\d+', '${sessionKey}')

3. コマンドプロンプト経由のPowerShell実行でのエスケープ文字混入

cmd.exe経由でPowerShellのワンライナーを実行した際、${sessionKey}$記号がPowerShell側の変数展開と解釈されないようにバッククォート(`)でエスケープしたところ、**そのバッククォート自体が文字としてファイルに書き込まれてしまい**、`${sessionKey}という壊れた変数参照になっていたことがありました。JMeterはこの状態でも変数を正しく解決できず、リクエストのパラメータに~(チルダ)を含む不正な値が展開されてURLとして無効になる、という分かりにくいエラーにつながりました。

対策は、cmd経由のワンライナーではなく.ps1ファイルとして保存してから実行することです。ファイルとして実行すればエスケープの問題が発生しません。

4. JMeterの「保存しますか?」に「はい」と答えると変数が巻き戻る

一括置換が完了してJMeterで開き直したところ、一見正しく動いたように見えたのに、次にJMeterを終了する際「変更を保存しますか?」と聞かれて保存を選んだところ、なぜか置換前の状態(バッククォート付き)に巻き戻ってしまったことがありました。JMeterが内部的に変数表記を再解釈してファイルに書き戻す挙動が影響していたようです。

これを踏まえた運用ルールとして、以下を徹底するようにしました。

JMXファイルの一括置換後、JMeterで開き直した際に「保存しますか?」と聞かれても、正規表現抽出器の追加などGUI上での変更を行っていない限りは「保存しない」を選ぶ。
一括置換とJMeter GUI上での編集を同じタイミングで混在させないのが安全です。


動作確認:正しく動的化できているかの検証手順

一括置換が終わったら、以下の手順で検証します。

1. 結果をツリーで表示でリクエストの色を確認する

1スレッド×1回のループでデバッグ実行し、「結果をツリーで表示」リスナーで全リクエストが緑(成功)になっているかを確認します。途中から赤(失敗)が続く場合は、その直前のリクエストの「リクエスト」タブで実際に送信されたパラメータの値を確認し、${sessionKey}が数値に正しく解決されているかをチェックします。

2. 実際に送信された値を目視で確認する

「結果をツリーで表示」の該当リクエストの「リクエスト」タブを開き、URLやPOSTデータの中のsessionKeyパラメータが実際のセッションに対応した数値になっているかを確認します。ここでNOT_FOUNDという文字列や、記録時のまま変化しない固定値が見えている場合は、正規表現抽出器の設定(正規表現のパターンや抽出対象のリクエスト)を見直します。

3. JMXファイル内を機械的にチェックする

目視だけでなく、置換後のJMXファイルに対して以下のような機械的なチェックを行うと確実です。

  • ${sessionKey}という文字列が期待した箇所数だけ出現しているか(置換前に数えた固定値の出現数と一致するか)
  • 記録時の固定値(元の数値パターン)がまだ残っていないか(置換漏れの検出)
  • バッククォートなど、意図しない文字が変数表記の前後に混入していないか
# 置換後の検証例
$text = Get-Content 'jmx\scenario.jmx' -Raw
([regex]::Matches($text, '\$\{sessionKey\}')).Count   # ${sessionKey}の出現数を確認

この一連の確認をしてから複数スレッドでの実行に進むことで、「スレッド数を増やしてから初めてsessionKey絡みのエラーに気づく」という手戻りを防げます。


応用:CSRFトークンなど他の動的値にも同じ考え方が使える

sessionKey以外にも、Spring Bootなどのフレームワークが持つCSRFトークンや、画面遷移のたびにサーバーが発行する遷移シーケンス番号のような値も、同じ「正規表現抽出器で前の画面のレスポンスから取得し、${変数名}として後続に渡す」というアプローチで対応できます。

考え方はいずれも共通です。

  1. 固定値のままだと再生時にエラーになる値を特定する
  2. その値がどのレスポンスに含まれているかを確認する
  3. 正規表現抽出器で変数化する
  4. 後続リクエストの固定値を変数参照に置き換える
  5. 動作確認する

一つのシナリオの中に動的化が必要な値が複数ある場合は、焦って全部一度に対応しようとせず、1つずつ動的化→動作確認のサイクルを回す方が、結果的に原因の切り分けが早くなります。


この記事のハマりどころまとめ

症状原因対処
最初の1〜2リクエストは成功、その後が軒並みConnection reset/500sessionKeyが記録時の固定値のまま送信されている正規表現抽出器で動的取得し${sessionKey}に置換
一部のリクエストだけ置換後も失敗するシナリオ内に複数種類のsessionKey値が混在している置換対象の値を事前に全種類洗い出す
${sessionKey}-261のような余分な数字が残るJMeterのリクエスト連番がパラメータ値に混入していた置換後に正規表現で連番の残骸を除去
パラメータに~を含む不正な値が展開されるcmd経由のPowerShell実行でバッククォートが混入した.ps1ファイルとして実行する
置換したはずが元に戻っているJMeterの「保存しますか?」で保存を選んでしまった一括置換後は原則「保存しない」を選ぶ

Udemy講座で「相関(Correlation)」の理解を深めたい方へ

sessionKeyの動的化は、JMeterの世界では一般的に**「相関(Correlation)」**と呼ばれるテクニックの一種です。この記事の内容を実際に手を動かしながらもう一段体系立てて学びたい場合、以下の講座が候補になります。

JMeter — Complete Performance & Load Testing Bootcamp

👉 講座の詳細を見る(Udemyで確認)

講師Vishwanatha Hebbar氏による講座で、評価4.3・レビュー1,144件、受講者数10,624名です。カリキュラムの中に「Correlation in JMeter」という独立した講義や、HTTPクッキーマネージャ・パラメータ化(Parameterisation)を扱う講義が含まれており、この記事で扱った内容と直接重なる構成になっています。

メリット

  • 「相関(Correlation)」というJMeterの重要概念が独立した講義として用意されており、この記事の内容を体系的な位置付けで復習できる
  • パラメータ化・クッキーマネージャなど、動的値の扱いに関連する周辺トピックもまとめてカバーしている
  • 分散テストやCI/CD連携など、この記事の範囲を超えた発展的な内容も含む

正直なデメリット

  • 講義は英語(自動翻訳字幕での視聴が前提になる)
  • 実際の業務アプリ特有の実装(フレームワークごとのフィールド命名など)はカバーされないため、応用は結局自分のアプリのレスポンスを見ながら試行錯誤する必要がある

こんな人におすすめ:この記事でsessionKey動的化の考え方は掴めたので、「相関」という概念そのものをJMeterの体系の中で位置付けて理解し直したい人。


このシリーズの構成

本記事はJMeter実務体験記シリーズの4本目(sessionKey動的化編)です。


まとめ

セッション管理があるWebアプリでは、JMeterのHTTPクッキーマネージャに任せておくだけでは不十分で、**URLパラメータやPOSTパラメータに含まれる独自のセッション識別値(sessionKey)**を正規表現抽出器で動的に取得し、後続リクエストに引き継ぐ作業が必須になります。この作業自体はシンプルですが、一括置換の副作用(余分な文字の混入、変数表記の巻き戻りなど)でハマりやすいポイントがいくつもあるため、動作確認を1つずつ丁寧に積み重ねることが結果的に一番の近道でした。

次のステップとして、この動的化作業も含めてAIエージェントと一緒にトラブルシューティングを進めた実際のやり取りをシリーズ⑤で紹介しています。あわせて参考にしてください。

👉 AIエージェントとのトラブルシューティング体験記

コメント