Skip to content

JMeter Distributed Testing Guide

Scale JMeter with distributed testing: controller and workers, RMI SSL, ports, -R CLI, data files on each engine, and result aggregation pitfalls.

Difficulty
advanced
Guide type
how-to
Estimated read time
13 min read
Last verified version
Verified JMeter 5.6

When a single injector cannot generate enough load - or is limited by network or CPU - JMeter can drive multiple remote engines from one client. This guide explains the controller-worker model, setup steps, CLI usage, SSL/RMI, data files, result collection, limits, and troubleshooting, grounded in the official Remote Testing manual and the step-by-step tutorial.

JMeter uses a controller (client) + workers (servers) architecture (historically called master/slave):

RoleResponsibility
Controller / clientHolds the test plan start command, sends the plan to workers, starts/stops the test, collects sample results, writes the combined result file locally
Worker / serverRuns jmeter-server, executes the full test plan, streams results back

Documented features of remote mode:

  • Saving of test samples to the local (controller) machine
  • Management of multiple JMeter engines from one machine
  • No need to copy the test plan to each server - the client sends it

From the official remote testing chapter:

The same test plan is run by all the servers. JMeter does not distribute the load between servers; each runs the full test plan. So if you set 1000 Threads and have 6 JMeter servers, you end up injecting 6000 Threads.

Plan thread counts per worker, not as a global pool that JMeter will shard for you.

The manual notes that remote mode uses more resources than running the same number of independent CLI tests. With many servers, the client and its network can become overloaded even though workers still run. Always verify the controller is healthy.

Also: do not run the JMeter engine on the application server under test if you can avoid it - the engine steals CPU and taints results. Prefer injectors on the same Ethernet segment as the app tier without sharing the app hosts.

Official checklist - every client and server must:

  1. Run exactly the same version of JMeter.
  2. Use the same Java version on all systems (mixed versions may work but are discouraged).
  3. Have a valid keystore for RMI over SSL, or SSL explicitly disabled in a controlled lab.
  4. Be reachable on the RMI ports you configure (firewalls allowing client→server and reverse result channels).

If the plan uses CSV files, plugins JARs, or other external resources:

these are not sent across by the client - make sure they are available in the appropriate directory on each server.

You may use different user.properties / system.properties per server (for example unique data partitions or different backend targets). Properties are picked up when the server starts.

DirectionPurposeNotes from docs
Client → serverControl / RMIDefault registry port 1099 (typical)
Server → clientSample resultsHigh-numbered ports; control with client.rmi.localport base
Server local engine portRMI engineDynamic by default; set server.rmi.localport for firewall-friendly fixed ports

If firewalls exist between client and servers, allow the chosen ports both ways as required for RMI. The manual suggests monitoring traffic if connections fail.

There can be only one JMeter server per node unless you use different RMI ports.

Follow the Distributed Testing Step-by-Step tutorial for screenshots, or the full Remote Testing reference.

  • Identical JMeter + Java
  • SSL keystore distributed or intentional SSL disable for lab only
  • CSV/plugin files present on workers
  • Optional: set server.rmi.localport on servers for fixed ports

On each worker machine:

Terminal window
# Unix
jmeter-server
# Windows
jmeter-server.bat

The server application starts the RMI registry itself; you normally do not start rmiregistry separately. (Older manual mode with server.rmi.create=false exists for special cases - see remote testing “Doing it Manually”.)

Optional: server.exitaftertest=true so the server exits after one test. The client -X flag also requests remote servers to exit at end of test.

Option A - properties file on the controller: set remote_hosts in jmeter.properties / overrides to a comma-separated list of worker hosts.

Option B - CLI (preferred for automation):

Terminal window
jmeter -n -t script.jmx -R host1,host2,host3 -l results.jtl

Documented equivalence: -R has the same effect as using -r with -Jremote_hosts={serverlist}.

Terminal window
jmeter -n -t script.jmx -r

uses whatever is already in remote_hosts.

Start the controller GUI; Run menu includes Remote Start / Remote Stop for configured hosts. Use this only to validate connectivity - not for real load.

Terminal window
jmeter -n -t script.jmx -R server1,server2 -l results.jtl -e -o report/

Useful flags from the manual:

FlagMeaning
-Gproperty=valueDefine a property on all servers (repeatable)
-XExit remote servers at the end of the test
-Jproperty=valueProperty on the client (and as usual for plan \${__P})

The command-line client exits when remote servers have stopped.

Since JMeter 4.0 the default RMI transport uses SSL. You must create keys/certificates.

JMeter ships:

  • bin/create-rmi-keystore.sh
  • bin/create-rmi-keystore.bat

Run from bin; the script generates a keystore with a key named rmi (default alias), valid seven days in the documented sample flow, default passphrase changeit. Answer the keytool prompts (CN should align with alias expectations; docs show using rmi as the name).

Then:

  1. Ensure rmi_keystore.jks is in jmeter/bin or referenced by server.rmi.ssl.keystore.file.
  2. Copy the same keystore to every server and client in the farm.

Default RMI SSL-related properties are described under the properties reference remote section.

Some teams temporarily set server.rmi.ssl.disable=true in user.properties on all nodes for isolated labs. Treat that as non-production only; prefer proper keystores for any shared or long-lived environment.

Workers execute samples; results stream back so the controller can:

  • Write a combined result file (-l)
  • Drive listeners in GUI (not recommended under load)
  • Produce one HTML dashboard from the combined log

The dashboard docs note a limitation on the “times vs threads” graph in distributed mode (axis reflects threads for one server - see generating-dashboard notes).

The remote testing manual mentions improvements via Stripped sample sending modes to reduce client overload. Prefer current defaults for your version, and still watch controller CPU, disk, and network when many workers send high-rate results.

  1. Decide total target concurrency or RPS.
  2. Decide how many injectors you have.
  3. Set Thread Group threads ≈ total / workers (plus headroom), remembering each worker runs the full group.
  4. Size heap per worker for its local thread count (Heap Estimator).
  5. Size the controller for result aggregation, not only for zero local threads.
  6. Use the Thread Calculator for per-engine starting points; validate with pilots.

Best practices also allow multiple autonomous CLI instances without remote mode: run N independent jmeter -n processes and merge sample result files later for analysis. That avoids RMI complexity when you do not need centralized start/stop.

Configure overrides in user.properties (recommended pattern: copy from jmeter.properties, do not edit only the stock file long-term):

AreaExamples (see properties reference for exact names)
Host listremote_hosts
Server RMI portserver.rmi.localport
Client reverse portsclient.rmi.localport
SSL keystoreserver.rmi.ssl.keystore.file, alias, password props
SSL disableserver.rmi.ssl.disable (lab)
Exit after testserver.exitaftertest

Unsure which knobs matter? Use the Properties Cheat Sheet and the full Properties Reference.

  1. Deploy identical JMeter/Java to all nodes.
  2. Deploy keystore + data files to workers.
  3. Start jmeter-server on each worker; confirm logs show RMI up.
  4. From controller, start CLI with -R and a small thread count.
  5. Confirm samples arrive in the result file.
  6. Scale threads/workers gradually.
  • Watch worker CPU, network, GC.
  • Watch controller disk I/O for the JTL.
  • Prefer Backend Listener for live metrics if you need dashboards mid-test.
  • Avoid View Results Tree on the controller under load.
  • Generate dashboard from the controller’s result file.
  • Use -X or server.exitaftertest if you want workers to shut down.
  • Collect jmeter-server logs from workers if anything failed.
ProblemWhat to check
Connection refusedjmeter-server running? host/IP correct? firewall on 1099 / server.rmi.localport?
Workers not listed / not startingremote_hosts / -R list; DNS resolution; ping/route
Serialization / class errorsIdentical JMeter versions; same plugins on all nodes
SSL handshake failuresKeystore present on all nodes; alias/password; clocks; or lab SSL disable consistently
No samples / incomplete resultsReverse ports blocked (client.rmi.localport range); client overloaded
Different behaviour per workerMissing CSV on some nodes; different user.properties
Controller overloadedToo many workers/high sample rate; use stripped modes; fewer result fields; autonomous CLI merge strategy
“Unknown host” / wrong interfaceBind addresses, multi-homed hosts, VPN interfaces

Debugging tips from the manual include RMI-related system properties for verbose RMI logs when diagnosing refused connections.

ApproachProsCons
Remote mode (-R)One start/stop; combined results; plan pushed to workersRMI/SSL complexity; client bottleneck
Independent CLI enginesSimple; no RMIManual start; merge JTLs yourself
Single powerful injectorSimplestHardware/network ceiling
CI single containerEasy automationLimited scale (CI guide)

Choose remote mode when you need central coordination and many injectors; choose autonomous CLIs when you want operational simplicity.

  1. Trusted network or strict firewall allowlists only.
  2. SSL keystores with controlled distribution; rotate when using short-lived certs (documented sample validity is short - regenerate for real use).
  3. No jmeter-server exposed to the public internet.
  4. Test plans treated as code - remote start executes what the client sends.
  5. Disable experimental SSL-off settings outside labs.

Under load, workers generate samples quickly. The controller must:

  1. Receive sample events over RMI.
  2. Write them to the local result file if -l is set.
  3. Optionally feed listeners or Backend Listener exporters.

That is why the remote testing chapter warns that the client can become the bottleneck. Mitigations aligned with official guidance and lean-run practice:

  • Prefer CLI controller with listeners disabled.
  • Save only required fields (jmeter.save.saveservice.*) so each sample is smaller.
  • Prefer CSV over XML results.
  • Avoid functional mode and full response data on every sample.
  • Use current stripped sample sending modes when available for your version.
  • Cap how many workers report to one controller; split farms if needed.
  • Consider autonomous CLI engines plus offline merge when coordination is not required.

If you need live charts without overloading the controller GUI, use the Backend Listener path so metrics stream to InfluxDB/Grafana from the engines or controller according to your plan design - still validate that the extra exporter CPU is acceptable.

A minimal two-worker lab that matches the docs:

HostRoleSoftware
controller.labClientSame JMeter + Java; has .jmx; runs CLI
worker1.labServerSame JMeter + Java; jmeter-server; CSV data present
worker2.labServerSame as worker1
Terminal window
# on each worker
cd $JMETER_HOME/bin
./jmeter-server
# on controller
./jmeter -n -t /plans/api.jmx \
-R worker1.lab,worker2.lab \
-Jthreads=50 \
-Ghost=app.lab \
-l /tmp/results.jtl \
-e -o /tmp/report \
-X

If the plan uses \${__P(threads,)} for the Thread Group, remember: each worker applies that property independently. -Jthreads=50 sets the client property; workers need the same value via -Gthreads=50 if they evaluate __P for thread count when the engine starts the plan. Match where the property is read - when in doubt, bake conservative defaults into the plan and override consistently with -G for remote engines.

Checklist before first production-scale distributed run

Section titled “Checklist before first production-scale distributed run”
  1. Versions identical (JMeter + Java) on all nodes.
  2. Keystore distributed; SSL smoke-tested.
  3. Firewall rules include control and reverse ports.
  4. CSV, keystores for the app under test, and plugin JARs on every worker.
  5. Small pilot with 1-2 threads per worker succeeds end-to-end.
  6. Controller disk has space for the full combined JTL.
  7. Heap sized per worker for planned local threads.
  8. Runbook includes who starts workers, who starts the client, and how to stop (shutdown/stop scripts or remote stop).
  9. Success criteria defined (error %, latency) before you stare at six worker CPU graphs.
  10. Rollback: how to halt generation if the app tier melts down.

Does JMeter split 1000 threads across 4 workers?

Section titled “Does JMeter split 1000 threads across 4 workers?”

No. Each worker runs the full test plan. Four workers with 1000 threads configured means about 4000 threads total.

Do I need to copy the JMX to every worker?

Section titled “Do I need to copy the JMX to every worker?”

No. The client sends the test plan to the servers. You do need to copy external data files and ensure plugins match.

CLI. The manual recommends starting remote tests from a non-GUI client for real load; GUI is for checking configuration.

JMeter/RMI commonly uses 1099 for the server registry connection; result channels use additional ports. Fix ports with server.rmi.localport and client.rmi.localport when firewalls require it.

Why did SSL start matter after JMeter 4.0?

Section titled “Why did SSL start matter after JMeter 4.0?”

Since JMeter 4.0, default RMI transport uses SSL and needs a keystore. Use create-rmi-keystore scripts and distribute rmi_keystore.jks.

It may work but is discouraged. Use the same Java and JMeter versions everywhere.

Is distributed mode always better than one machine?

Section titled “Is distributed mode always better than one machine?”

No. Remote mode adds overhead and can overload the client. Sometimes one large injector or several independent CLI runs is simpler and more reliable.

On this page