Skip to content

Performance

Three tools dominate, they are all capable, and the choice matters less than the workload model fed into them. What differs is the authoring experience, and that is what decides whether the scripts are still correct a year later.

JavaScript, single binary, no JVM, results to Prometheus or InfluxDB. The default for most teams starting now.

Why. The script is a small JavaScript file in the repository, reviewable in a pull request. It runs in a container in the pipeline with no infrastructure. Its thresholds are declarative and they fail the run:

thresholds: { http_req_duration: ['p(95)<300'], http_req_failed: ['rate<0.001'] }

That block is the SLO, expressed where the run can enforce it, which is the property that turns a performance test into a gate rather than a report.

Limits. The runtime is a Go-embedded JavaScript engine, not Node — some libraries do not work. A single instance saturates before very large loads, so distributed runs mean k6 Operator or the hosted service.

Scala, Java or Kotlin DSL, high concurrency per node, detailed HTML reports.

Why. For a JVM team, the scripts are code in the same language as the application, with the same IDE, the same review, the same refactoring tools. Its DSL is the most expressive of the three at describing a scenario — during, rampUsers, pace, injection profiles as first-class values — and the reports are the best of the three out of the box.

Limits. JVM footprint. The DSL is expressive and the learning curve is real if the team is not already a JVM team.

Java, GUI-authored XML, huge plugin ecosystem, and the one most organisations already have.

Why. Protocol coverage nothing else matches — JDBC, JMS, LDAP, FTP, SOAP and the rest. If the thing under test is not HTTP, this is frequently the only option.

Limits, and they are the reason it is not the default. The .jmx file is generated XML: it cannot be reviewed in a pull request in any meaningful sense, it merges badly, and it fails criterion 3 in how a tool gets chosen. The GUI is for authoring only — running a load test from it distorts the results.

JMeter DSL (a Java library that produces the same test plans in code) is worth knowing about: it keeps the protocol coverage and makes the artefact reviewable.

Two problems, and neither is solved by switching between them.

The scripts rot. They encode endpoints, payloads, authentication flows and data assumptions; they are written in a tool nobody uses daily, reviewed by nobody in particular, and touched twice a year. When they break, the fastest fix is to comment out the failing scenario, and that is how a suite becomes a formality.

The workload model is buried in the script. The interesting content — which journeys, in what proportion, at what arrival rate, with what think time — is mixed into HTTP mechanics, correlation logic and data feeders. A reviewer cannot see whether the model is right, which is the only thing worth reviewing.

That is the problem the research section is investigating: a domain-specific language for the workload, compiled to whichever of these tools executes it. It is an open question, not a recommendation — the section is honest about what it does not know yet.

Resilience tests usually run under load, since a circuit breaker’s behaviour with one request in flight tells you very little.

WireMock at integration level — delays, resets, error rates. Cheap, and where most timeout and retry defects are found. See API and contract tooling.

Toxiproxy for network-level faults — latency, bandwidth limits, connection drops — between a service and its real dependency, without changing either.

The service mesh at environment level, where one exists: fault injection is usually configuration rather than a new tool.

Correlate with traces. A percentile says the p99 is four seconds; a trace says which span it was spent in. Without the second, the result is a fact rather than an action.

Watch saturation, not only latency. CPU, memory, connection pools, thread pools, queue depth. Latency says it broke; saturation says what to fix.

Keep the history. The comparison against the previous release is more informative than the comparison against the threshold. See reporting.