JMS, FTP, LDAP, TCP, and Other Protocol Test Patterns: Configuration, Design Patterns, and Trade-Offs
Protocol sampler choice is an architecture decision. A built-in sampler is attractive when it expresses the real wire/session behavior. A custom/plugin/client implementation is justified only when the built-in model cannot represent required framing, provider APIs, security, or correlation without distortion.
Learning objectives
- Choose built-in samplers before custom/plugin implementations when semantics fit.
- Choose persistent or per-sample connections from the production client lifecycle.
- Distinguish one-way messaging from request/reply latency.
- Choose direct protocol or application-level tests from the layer under investigation.
- Choose mandatory local fixtures or optional containers based on dependency/CI cost.
- Connect configured and achieved load to generator/provider/target state.
1. Mandatory executable path remains TCP-only and local
127.0.0.1:9100, ≤2 threads,
≤10 seconds.
Broker, FTP, LDAP, Kubernetes, cloud services, public endpoints,
corporate systems, third-party plugins, and paid telemetry are
optional design contexts—not chapter requirements.
2. Built-in protocol sampler versus custom/plugin client
| Built-in sampler | Custom/plugin/client |
|---|---|
| Prefer when JMeter already models the needed connection/framing/session semantics. | Use when vendor/binary/security semantics cannot be represented correctly. |
| Lower supply-chain/classpath/maintenance cost. | Adds version/API/classloader/plugin compatibility and generator cost. |
| Primary docs define sample-result behavior. | You must define response codes/timing/correlation semantics yourself. |
| Easier portability across local/CI JMeter installs. | Every injector needs the same JARs/config/provider versions. |
For TCP, try built-in TCPClientImpl,
BinaryTCPClientImpl, or
LengthPrefixedBinaryTCPClientImpl before writing a
custom TCPClient. Custom code is justified only when
real framing/encoding cannot be expressed safely.
3. Persistent versus per-sample TCP connections
Persistent sockets match clients that establish a session/connection and perform many messages. Per-sample connections match protocols/clients that connect for one operation or when connection setup itself is the metric.
Connection reuse changes target accept/TLS/login load and generator socket lifecycle. Keep it constant when comparing payload/query behavior, or explicitly label it as the independent variable.
4. Fire-and-forget versus request/reply messaging
| Request only / fire-and-forget | Request reply |
|---|---|
| Measures producer/client send path. | Measures until a reply is received. |
| Good for broker ingress/producer throughput. | Good for request-to-reply service latency. |
| Queue depth/consumer lag must be observed separately. | Reply path/correlation and timeout become part of sample. |
| Can accumulate messages quickly if no consumer/cleanup. | Requires reply queue/consumer/session correctness. |
One-way send time can be very low while consumers are minutes behind. Always pair one-way publishing with broker depth/lag/acknowledgement telemetry appropriate to the provider.
5. JMS Subscriber receive versus listener strategy
Current JMeter JMS Subscriber supports a receive-based client that fetches messages only while the sampler is active and retains a connection between samples; this suits queues. The listener strategy remains active after the sample and stores incoming messages for later sampling; this suits topics.
That difference changes when work happens relative to sampler timing and generator memory/queue state.
6. Durable subscriptions and client IDs
Durable topic subscriptions create provider-side state. Current
JMeter docs specifically warn that Client ID must be unique when
more than one thread is used—for example by including
${__threadNum}. Reusing one durable ID/client ID can
cause provider errors or unintended shared state.
Always document deletion/cleanup of run-scoped durable subscriptions after a disposable test.
7. FTP GET versus PUT and local I/O
GET tests server read/transfer and may optionally write local files or retain response bytes. PUT tests upload and mutates server state. Saving a large downloaded file also adds generator disk I/O; that can become part of elapsed/generator bottleneck.
Use a disposable FTP root and explicitly clean only files with the current run prefix. Do not point uploads at shared/corporate FTP locations.
8. LDAP basic versus Extended
Basic LDAP Request is easier for Add/Modify/Delete/Search examples. LDAP Extended is better when session realism matters because it models thread bind/unbind and other LDAP operations more directly.
For capacity claims about an application that uses LDAP through its own pool/cache, test the application too; direct LDAP bypasses those layers.
9. Direct protocol performance versus application-level test
Direct TCP/JMS/FTP/LDAP can isolate broker/directory/file/protocol behavior. It bypasses application validation, business orchestration, caches, retry logic, connection pools, and other services. Use direct protocol tests to answer protocol-layer questions and application tests for end-to-end questions.
10. Local process versus optional container stack
The mandatory TCP server is a plain local Python process: no image downloads, container network, volume, or orchestrator state. A containerized broker/FTP/LDAP service can improve reproducibility for teams that already use containers, but adds image version, startup health, port mapping, volumes, credentials, and resource caps.
If containers are used, pin versions, bind ports only to loopback, use disposable volumes, and preserve container CPU/memory/log evidence separately from JMeter.
11. Protocol security choices
Do not assume a sampler implies secure transport. Plain FTP is not SFTP; raw TCP is not TLS; LDAP versus LDAPS/StartTLS differ; JMS security depends on provider configuration. Use the actual authorized secure protocol/client configuration required by the system.
Never disable TLS/authentication checks to make a test pass. The local mandatory fixture intentionally has no credentials/TLS so no insecure workaround is needed.
12. Provider/client dependency management
Provider JARs belong in JMeter's runtime classpath on every injector. Pin versions and restart JMeter after classpath changes. A missing JMS provider JAR is not a broker saturation symptom. A plugin upgrade can alter sample semantics, so keep JMeter/provider/plugin versions with result evidence.
For every executed non-HTTP profile, preserve the raw
JTL together with its matching
jmeter.log, the exact JMX/data/properties, generator
CPU/memory/socket state, and protocol-target evidence (for example
TCP connection IDs, broker queue depth, FTP file hashes, or LDAP
session/search evidence). Never substitute a public, corporate,
shared, or production protocol endpoint for the local/explicitly
authorized target.
13. Configuration-layer boundaries
| Layer | Examples | Do not confuse with |
|---|---|---|
| JMeter core | TCP/FTP/LDAP/JMS samplers, Config Elements, assertions, timers | Provider/broker/directory business state. |
| Java/JVM | provider JAR classpath, charset, TLS trust, heap/GC | Queue depth or server file I/O. |
| OS/network | sockets, DNS, TIME_WAIT, loopback/ports | Application message acknowledgement. |
| Target/SUT | broker queues, FTP files, LDAP entries, TCP service workers | Generator listener/save cost. |
| Plugin/provider | JMS provider JAR/custom TCP client/plugin version | JMeter core availability. |
| CI/container | image/volume/port/startup/resources/secrets | Protocol semantics themselves. |
14. Worked scenario
Requirement: “Measure order-worker request-to-reply latency over JMS and separately verify broker producer ingress.”
- Request-to-reply profile: dedicated request/reply queues, unique correlation IDs, JMS Point-to-Point Request Response, reply timeout, consumer/server telemetry.
- Producer profile: Request Only, explicit fixed message size/rate, queue-depth/consumer-lag telemetry, bounded backlog/cleanup.
- Do not quote producer-send p95 as worker end-to-end p95.
15. Decision table
| Question | Preferred pattern | Evidence |
|---|---|---|
| Text line-protocol request/reply | Built-in TCPClientImpl + explicit EOL | JTL + connection/request IDs + server timing. |
| Binary length-prefixed protocol | Built-in LengthPrefixedBinaryTCPClientImpl if compatible | Binary fixture + framing/timeouts. |
| JMS producer ingress | Request Only + broker depth/lag | Send samples + queue telemetry. |
| JMS service latency | Request Response + correlation/reply queue | Request/reply JTL + service/broker telemetry. |
| Directory session search | LDAP Extended bind/search/unbind | Session/bind/search telemetry. |
| End-user app behavior | Application/API-level test | App pool/cache/business + downstream telemetry. |
16. Configured versus achieved load
Configured TCP samples, JMS publishes, FTP transfers, or LDAP searches are only intent. Achieved valid operations depend on connection reuse, provider/session setup, reply timeouts, queue backpressure, file I/O, directory limits, generator CPU/GC, and server saturation. Report achieved operation counts and protocol-specific target state.
Knowledge check
When should a custom TCP client be considered?
Only when built-in text/binary/length-prefixed clients cannot represent the real protocol framing/encoding correctly.
What target metric must accompany JMS Request Only load?
Queue depth/consumer lag/processing evidence, because send completion does not prove consumer completion.
Why can FTP Save Local File change a performance test?
It adds generator disk I/O and file-state cleanup to the measured workflow.
Why should JMS Client ID include a thread-unique value for durable subscriptions?
Multiple threads sharing one client ID can collide or represent unintended shared provider state.
Why does a direct LDAP test not prove app-login capacity?
It bypasses application pools/caches/business logic and exercises the directory directly.
Official references and version notes
- JMeter Component Reference — TCP Sampler — built-in TCP clients, EOL/binary framing, per-thread connection reuse, timeouts, and socket lifecycle.
- JMeter Component Reference — FTP Request — upload/download behavior, login latency, binary/ASCII modes, and credential storage.
- JMeter Component Reference — JMS Publisher — provider/JNDI dependencies, destinations, persistence, message sources, and provider JAR requirements.
- JMeter Component Reference — JMS Subscriber — queue/topic clients, durable IDs, selectors, receive/listener strategies, and connection lifecycle.
- JMeter Component Reference — JMS Point-to-Point — request-only, request-reply, read, browse, and clear semantics.
- JMeter Component Reference — LDAP Request — Add/Modify/Delete/Search operations and cleanup differences.
- JMeter Component Reference — LDAP Extended Request — bind/session-oriented LDAP operations.
- JMeter Functions — __char — inserts explicit Unicode characters such as LF for TCP text framing.
- JMeter Getting Started — Java requirements and GUI authoring versus CLI execution.
- JMeter Best Practices — non-GUI execution and generator validity.
- Apache JMeter downloads — current stable release and Java requirement.
Version-sensitive statements were rechecked against current Apache
JMeter primary documentation on 2026-09-05. The course baseline
remains Apache JMeter 5.6.3 with a Java 17 JDK;
JMeter 5.6.3 requires Java 8+. TCP Sampler is built in and the
mandatory lab uses its default TCPClientImpl with
explicit LF (EOL byte=10) framing. With connection
reuse enabled, TCP connections are reused only by samplers in the
same JMeter thread that use the exact same host string and port;
different threads use different sockets. JMeter's FTP, LDAP/LDAP
Extended, JMS Publisher/Subscriber/Point-to-Point, and TCP
samplers are currently built in. JMS is different from
TCP/FTP/LDAP because JMeter does not bundle a JMS
provider implementation JAR: provider-specific client/JNDI
libraries must be supplied in JMeter's lib directory
and JMeter restarted. FTP sampler latency is the FTP login time,
not full file-transfer elapsed time. JMS request-only measures the
send-side sample; request-reply waits for a reply from the service
and is the appropriate built-in pattern when request-to-reply
latency is required. LDAP Extended models session operations such
as thread bind/unbind. Core TCP login/password fields are not used
by the supplied TCP clients and any entered password is stored
unencrypted, so the TCP lab leaves them blank.
Keep the academy open
Support free, practical DevOps education.
Every lesson is designed to remain readable in a browser, downloadable from GitHub, and usable without a paid learning platform. Contributions help expand and maintain the curriculum.
0x716c4Ab160C4B66F31a28AE2448BfF68fc3a2ef0
Send only Ethereum/ERC-20 compatible assets to this
address.