JMeterのリモート実行機能をNAT環境で使う

JMeterをNAT環境で使う機会があったので設定方法まとめた。というかほぼ以下のサイトに書いてあった通りにした。*1

今回は接続周りの設定の話しかしないので、インストール方法、テスト計画の設定方法、サーバ上でのCUIによるテスト実行などについては解説ありません。

使用するソフトウェア

今回使用したソフトウェアは以下の通り

JMeterのサーバクライアント間の通信

Apache JMeterは、クライアントアプリケーション(GUI)上で入力したテスト計画を実行するだけではなく、出力したテスト計画をコマンドラインから実行することもできる。さらに、クライアントアプリケーションからサーバにリモート接続し、テスト計画を実行し、その実行結果を表示することもできる。

テスト計画のリモート実行は、テスト実行用のサーバ上でjmeter-serverを起動し、そのサーバのポートにクライアントアプリケーションからソケット接続することでおこなう。さらにjmeter-server上で実行されたテスト計画の実行結果をクライアントアプリケーション上で表示するためには、jmeter-serverからクライアントアプリケーションのポートへの接続が必要になる。

上の図は、それぞれポート一つずつだが、実際にはrmiregistry用のポートも使用する。

SSHによるポート転送

さて、上記の図での「クライアントPC」がNAT環境にあるなどの理由で、サーバから直接接続できない場合について考える。今回は、SSHによるポート転送を使用する。

まず、サーバ・クライアントのどちらからも接続可能な中継サーバを用意する。サーバが中継サーバを兼ねても構わないが、ここでは一応別サーバということにする。

クライアントPCから中継サーバに、以下のようなssh接続をおこなうことでトンネリングをおこなう。(ここでは、クライアントアプリケーションが使用するポート番号を30000、サーバのアドレスを192.0.2.1としている。JMeterにおける設定方法などについては後述)

ssh -R 30000:localhost:30000 192.0.2.1

JMeter(GUI)を実行しているPCから中継サーバに接続をおこない、中継サーバ上でソケットにポート30000番を割り付けて接続を受け付けるようになる。

JMeter Serverでテストが開始されると、結果を送信する為にクライアントへの接続をおこなおうとする。設定(後述)を工夫することで、クライアントPCへ接続する代わりに、中継サーバに接続をおこなうように仕向けることができ、中継サーバ上で先ほどSSHが用意したポートに接続がおこなわれる。中継サーバ上の30000番ポートへの接続は、SSHのポート転送機能によって接続元であるクライアントPCの30000番ポートに転送され、クライアントPC上のJMeterに接続がおこなわれるようにできる。

中継サーバでポート転送をおこなうには、中継サーバのsshdの設定が必要な場合がある。OpenSSHでは、sshd_configで「GatewayPorts yes」を指定する必要があった。

上の例では、テスト実行サーバからクライアントPCへの接続ができない場合の説明であったが、クライアントからサーバへの接続ができない場合も同じようにポート転送で接続を確保できる。

JMeterの設定内容

クライアント、サーバのどちらも相互に接続できないような場合を考える。どちらからも、中継サーバには接続できるとする。中継サーバは下の図のようにインターネット上にあるかもしれないし、サーバ側のDMZ上などにあるかもしれない。

それぞれのIPアドレスを以下のようにする。

中継サーバ 192.0.2.1(グローバル)
クライアントPC 192.168.0.3(プライベート)
JMeter実行サーバ 192.168.1.5(プライベート)

今回使用するポートを以下のように決める。ポート番号は何でも良いが転送できるように固定は必要。

rmiregistryポート 31099 デフォルトは1099
JMeter サーバが使用するポート 40000 デフォルトは不定
JMeter クライアントが使用するポート 30000 デフォルトは不定
クライアントの設定

サーバへの接続を中継サーバに振り替えるために、/etc/hostsに以下の記述をおこなう。

127.0.0.1	localhost jmeter-client
192.0.2.1	jmeter-server

bin/jmeter.properiesの以下の項目を設定する。

remote_hosts=jmeter-server:31099
client.rmi.localport=30000

remote_hostsにはサーバ名とrmiregistryポートを指定する。指定したホスト名がメニューから選択できるようになる。

bin/jmeter.shでJVM_ARGSに以下の引数を追加し、システムプロパティにjava.rmi.server.hostnameを設定する。

JVM_ARGS="-Djava.rmi.server.hostname=jmeter-client"
サーバの設定

クライアントへの接続を中継サーバに振り替えるために、/etc/hostsに以下の記述をおこなう。

192.168.1.5    jmeter-server
192.0.2.1      jmeter-client

bin/jmeter.properiesの以下の項目を設定する。

client.rmi.localport=30000
server.rmi.port=31099
server.rmi.localport=40000

bin/jmeter-serverでRMI_HOST_DEFに以下の引数を追加し、システムプロパティにjava.rmi.server.hostnameを設定する。

RMI_HOST_DEF=-Djava.rmi.server.hostname=jmeter-server
トンネリング設定

サーバから中継サーバに対して、以下のようにSSH接続をおこなう

ssh -ladmin -R 31099:localhost:31099 jmeter-client
ssh -ladmin -R 40000:localhost:40000 jmeter-client

クライアントPCから中継サーバに対して、以下のようにSSH接続をおこなう

ssh -ladmin -R 30000:localhost:30000 jmeter-server

必要であれば、サーバ、クライアントPCから上記のポートへの接続をそれぞれFWで許可する。

プログラムの起動

サーバ側でjmeter-serverを起動する

[apache-jmeter-2.9]$ bin/jmeter-server
Using local port: 40000
Created remote object: UnicastServerRef [liveRef: [endpoint:[jmeter-server:40000](local),objID:...

クライアント側で、jmeter.shを起動する

[apache-jmeter-2.9]$ bin/jmeter.sh
処理の流れの説明

多分以下の理解であっていると思う。

  • サーバ上でjmeter-serverを起動
    • server.rmi.localportで指定したポート(40000)で接続の受け付けを開始する
    • サーバ上のserver.rmi.portで指定したrmiregistryポートに接続情報を登録する
      • rmiregistryが起動されていなければ、server.rmi.portで指定したポートでrmiregistry開始
  • クライアントPCで、メニューから「実行」>「開始(リモート)」でjmeter-server:31099を指定し、テストを実行
    • 実行結果を取得できるように、client.rmi.localportで指定したポート(30000)で接続の受け付けを開始する
    • クライアントから、jmeter-server:31099に接続し、サーバの接続情報を取得
      • クライアントPC上の/etc/hostsでは、jmeter-serverには中継サーバのIPアドレスを指定していたので、中継サーバの接続31099番ポートに接続
      • ポート転送され、サーバ上のrmiregistryに接続
      • rmiregistryは、接続情報として、ポート番号40000と、java.rmi.server.hostnameシステムプロパティで指定したホスト名jmeter-serverを戻す
    • クライアントから、jmeter-server:40000に接続する
      • クライアントPC上の/etc/hostsではjmeter-serverには中継サーバのIPアドレスを指定していたので、中継サーバの接続40000番ポートに接続
      • ポート転送され、サーバ上のJMeterサーバ(40000番ポート)に接続
      • JMeterクライアントはサーバに対して、自分の接続情報としてjava.rmi.server.hostnameシステムプロパティで指定したホスト名jmeter-clientと、ポート番号30000を送る
    • JMeterサーバから、jmeter-client:30000に接続する
      • サーバ上の/etc/hostsではjmeter-clientには中継サーバのIPアドレスを指定していたので、中継サーバの接続30000番ポートに接続
      • ポート転送され、ローカルPCのJMeterクライアント(30000番ポート)に接続

その他補足

元々クライアント→サーバ間の回線が細かったのでサーバ側で実行しようとして始めたんだけど、リスナー「結果をツリーで表示」などを使用している場合、レスポンスの内容が転送されるので転送量は減らない。「ログエラーのみ」にチェックするか、ネタ元サイト様のようにmode=Asynch設定した方がいいかも。

*1:サーバ側もNATというのは今回追加した条件だけど。