--- title: "MockServer Performance Benchmarks: Throughput & Latency" shortTitle: "Scalability & Latency" description: "MockServer performance benchmarks: one instance serves 32,000+ req/sec at sub-millisecond median latency, with flat request matching as expectations scale." layout: page pageOrder: 3 section: 'Performance Testing' subsection: true sitemap: priority: 0.8 changefreq: 'monthly' lastmod: 2026-06-24T08:00:00+01:00 keywords: mockserver performance, mockserver benchmark, mock server throughput, api mock latency schema_faq: - question: "How fast is MockServer?" answer: "On six CPU cores a single instance holds sub-millisecond median latency up to 32,000 requests/sec, saturating near 36,000 req/s. Latency stays flat until that knee — p50 is 0.19 ms, p95 around 4 ms — then degrades predictably rather than collapsing." - question: "How many requests per second can MockServer handle?" answer: "A single six-core instance sustains up to 32,000 requests/sec at sub-millisecond median latency, saturating near 36,000 req/s. Beyond one instance, run several instances behind a load balancer — serving capacity scales horizontally." - question: "Does MockServer slow down with many expectations?" answer: "No. MockServer indexes expectations so each request is compared only against a small candidate set rather than scanning every expectation. At 5,000 expectations matching is up to 177× faster than a naive linear scan, keeping matching cost nearly flat as expectations grow." - question: "How do I tune MockServer for high throughput?" answer: "The most impactful lever is the in-memory request log: set maxLogEntries lower or disable logging (disableLogging=true) to free heap and reduce GC pressure. Additional levers include the native epoll transport on Linux, thread-pool sizes, and forward-proxy connection pooling. See the Scalability Configuration section for details." ---
A single MockServer instance holds sub-millisecond median latency up to 32,000 requests/sec on six CPU cores, and request matching stays flat — up to 177× faster than a linear scan — as you scale to thousands of expectations.
| Page | Question it answers |
|---|---|
| Scalability & Latency | How much traffic can one instance serve as a mock? |
| Load Injection | How do I drive load from MockServer? |
| Load Injection Performance | How much load can MockServer inject, and how does it scale? |
MockServer is built for high throughput and low, predictable latency from a single instance. The figures below come from an automated performance suite that runs on a dedicated, core-pinned CI machine; every chart is regenerated from the measured data on each run, so what you see is reproducible rather than cherry-picked. Jump to how MockServer is performance tested for the methodology, or run the suite yourself from mockserver-performance-test/.
As offered load increases, achieved throughput tracks it almost exactly while latency percentiles stay flat — right up to the point the single instance saturates. That flat region is the headroom you can rely on; beyond it, latency rises predictably rather than collapsing.
Mock servers are often run with hundreds or thousands of expectations. MockServer keeps matching cheap at scale by narrowing each request to a small set of candidate expectations instead of testing every one. The difference grows with the number of expectations:
Even at the knee — around 32,000 requests/sec — the latency tail stays tight: a 0.19 ms median, a p95 of about 4 ms and a p99 under 10 ms.
The same actions measured over HTTP/1.1 and over HTTPS with HTTP/2 show that TLS and HTTP/2 add only a fraction of a millisecond — even a forwarded request or a large templated response stays within single-digit milliseconds:
The throughput and latency above come from a few deliberate design choices:
Most of these are configurable — thread-pool sizes, native transport, and matcher behaviour are covered under scalability configuration below.
The numbers on this page are produced by a performance suite (mockserver-performance-test/) built around k6 for load generation and the JMH microbenchmark harness for component-level measurement. A few principles make the results trustworthy:
Measurement environment for the figures on this page: a single MockServer instance (current snapshot build) pinned to six CPU cores on a dedicated CI host, running the low-pause ZGC garbage collector with an 8 GB heap and full request logging enabled (the default — every request is recorded for later verification). The load generator runs on separate cores so it never steals cycles from the server. Real-world throughput and latency depend on your hardware, core count, payload size, expectation complexity and JVM/configuration tuning — more CPU cores and disabling request logging both raise peak throughput — so treat these as a solid reference and benchmark your own workload.
Offered request rate against achieved throughput and response-latency percentiles for a single instance matching a simple expectation:
| offered req/s | achieved req/s | p50 | p95 | p99 | errors |
| 2,000 | 1,995 | 0.17 | 0.26 | 0.39 | 0% |
| 4,000 | 3,991 | 0.18 | 0.29 | 0.40 | 0% |
| 8,000 | 8,000 | 0.15 | 0.22 | 0.29 | 0% |
| 16,000 | 16,000 | 0.16 | 0.28 | 0.50 | 0% |
| 32,000 | 31,751 | 0.19 | 4.14 | 9.62 | 0% |
| 48,000 | 36,324 | 23.12 | 125.14 | 195.66 | 0% |
| 64,000 | 30,871 | 97.36 | 170.66 | 230.51 | 0% |
| 80,000 | 33,041 | 112.65 | 181.17 | 262.94 | 0% |
Latencies are in milliseconds. Achieved throughput tracks the offered rate up to about 32,000 req/s; beyond that the six-core instance saturates near 36,000 req/s and latency climbs predictably rather than collapsing. (More CPU cores raise the ceiling; this run pins the server to six.)
These figures are per instance. The ~36,000 req/s saturation point is the throughput of a single six-core instance — you scale beyond it by adding instances. Scaling beyond one instance: for more serving capacity (handling more inbound mock traffic) or high availability, run several instances as a cluster behind a load balancer — see Centralised Deployment. To drive more load injection (generating more outbound traffic with Load Scenarios), run injector instances in parallel — see Load Injection Performance, which measures how injected throughput scales near-linearly with the number of instances.
Microbenchmark of a single request match against a growing set of literal expectations, worst case (no match, so every candidate is examined): MockServer's candidate index versus a naive linear scan.
| expectations | linear scan | candidate index (default) | speed-up |
| 1 | 0.34 µs | 0.35 µs | — |
| 10 | 2.3 µs | 0.21 µs | ~11× |
| 100 | 21 µs | 0.32 µs | ~67× |
| 1,000 | 218 µs | 1.5 µs | ~147× |
| 5,000 | 1,378 µs | 7.8 µs | ~177× |
Times are microseconds per match. At one expectation the index adds negligible overhead; as expectations grow it keeps matching cheap where a linear scan grows roughly linearly with the number of expectations.
The defaults are tuned for general use. For sustained high throughput, large payloads, or long-running instances, the most effective levers are memory/log sizing and a few scalability settings — covered in detail below. The single most common cause of an instance slowing down over time is the in-memory request log filling the heap; see memory & troubleshooting.
{% include_subpage _includes/clustering.html %} {% include_subpage _includes/performance_configuration.html %}The results below are from an earlier benchmarking exercise and are kept for reference. They are historical and indicative — measured on an older Java 13 JVM on specific hardware using a closed-model client-count load (which is subject to coordinated omission), so they are not directly comparable with the open-model figures above. They showed an average of 1.58 ms and a p99 of 4 ms for 150 parallel clients sending 95,228 requests per second.
The scenario was four basic expectations (method, path and headers), with a GET request matching the third expectation. MockServer was run on a Java 13 JVM with:
java -Xmx500m -Dmockserver.logLevel=WARN -Dmockserver.disableLogging=true -jar ~/.m2/repository/org/mock-server/mockserver-netty/{{ site.mockserver_version }}/mockserver-netty-{{ site.mockserver_version }}-no-dependencies.jar -serverPort 1080
Note: the benchmark used -Dmockserver.disableLogging=true to disable all logging and log event processing, with -Dmockserver.logLevel=WARN as a safeguard. To suppress only system-out while still recording log events for verification, use -Dmockserver.disableSystemOut=true instead.
Apache Benchmark was executed as:
ab -k -n 10000000 -c <parallel clients> http://127.0.0.1:1080/simple
| parallel clients | 50% | 66% | 75% | 80% | 90% | 95% | 98% | 99% | requests/s | mean |
| 10 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 77,122 | 0.13 |
| 50 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 85,765 | 0.58 |
| 100 | 1 | 1 | 1 | 1 | 1 | 2 | 2 | 3 | 92,846 | 1.08 |
| 150 | 1 | 2 | 2 | 2 | 2 | 2 | 3 | 4 | 95,228 | 1.58 |
| 250 | 3 | 3 | 3 | 3 | 4 | 5 | 7 | 8 | 86,470 | 2.89 |
| 500 | 6 | 6 | 6 | 6 | 7 | 7 | 8 | 9 | 83,209 | 6.01 |
| 750 | 9 | 9 | 10 | 10 | 11 | 11 | 12 | 15 | 75,554 | 9.93 |
| 1000 | 11 | 12 | 13 | 13 | 14 | 16 | 17 | 21 | 75,423 | 13.26 |
| 2000 | 24 | 24 | 25 | 26 | 27 | 29 | 31 | 35 | 82,191 | 24.33 |
| 3000 | 37 | 39 | 40 | 40 | 43 | 46 | 51 | 58 | 78,171 | 38.38 |
| 4000 | 52 | 55 | 57 | 59 | 64 | 70 | 82 | 91 | 73,552 | 54.38 |
| 5000 | 65 | 67 | 70 | 71 | 75 | 79 | 90 | 102 | 74,065 | 67.51 |
| 6000 | 80 | 84 | 88 | 90 | 97 | 104 | 122 | 137 | 70,432 | 85.19 |
Locust was executed as:
locust --loglevel=WARNING --headless --only-summary -u <parallel clients> -r 100 -t 180 --host=http://127.0.0.1:1080
| parallel clients | 50% | 66% | 75% | 80% | 90% | 95% | 98% | 99% | 99.90% | 99.99% | requests/s | mean |
| 10 | 0 | 0 | 1 | 1 | 1 | 1 | 1 | 2 | 5 | 5 | 11 | 0 |
| 50 | 0 | 0 | 1 | 1 | 1 | 1 | 1 | 2 | 3 | 5 | 50 | 0 |
| 100 | 0 | 1 | 1 | 1 | 1 | 2 | 2 | 3 | 4 | 8 | 100 | 0 |
| 150 | 1 | 1 | 1 | 1 | 2 | 3 | 3 | 4 | 5 | 6 | 149 | 0 |
| 250 | 2 | 3 | 3 | 4 | 5 | 6 | 7 | 8 | 15 | 46 | 245 | 2 |
| 500 | 2 | 2 | 3 | 3 | 4 | 5 | 6 | 7 | 9 | 46 | 479 | 2 |
| 750 | 3 | 4 | 5 | 6 | 8 | 10 | 12 | 14 | 29 | 34 | 699 | 3 |
| 1000 | 3 | 4 | 6 | 6 | 8 | 10 | 13 | 16 | 36 | 52 | 909 | 3 |
| 2000 | 4 | 7 | 10 | 12 | 22 | 34 | 49 | 59 | 87 | 110 | 1626.14 | 8 |
| 3000 | 51 | 78 | 99 | 110 | 160 | 180 | 220 | 240 | 290 | 310 | 2629.92 | 54 |