Blog
When a high-throughput transactional system like Redis approaches its limits
How does Redis behave as it approaches its limits? Latency and throughput stay fast but begin to swing from window to window. See the full picture.
Blog
How does Redis behave as it approaches its limits? Latency and throughput stay fast but begin to swing from window to window. See the full picture.
Performance numbers are easy to trust when they look good. For a high-throughput transactional system, the most dangerous number may be the one that looks reassuring. A low median latency and a high throughput figure can make a system appear to have plenty of headroom, until you look at how consistently it delivers those numbers under sustained load.
A benchmark conducted by McKnight Consulting Group put Redis and Aerospike through a series of high-throughput tests on identical hardware, dataset, and workload, measuring not just how fast each ran, but how reliably each sustained its target rate and how its latency behaved from one measurement window to the next. The findings are unexpected, emphasizing the importance of looking beyond peak performance when evaluating transactional systems under heavy loads. And because both engines were measured under the same conditions, it's possible to see not just where one system starts to strain, but what the same test looks like on a system that doesn't.
In practice, this means asking two separate questions about any headline number. First, which part of the distribution are you actually looking at? With most user-facing operations relying on multiple backend calls, it's the slow tail of the latency distribution (p99, p99.9, or p99.99) that can shape the user experience, not the average. The second question is easier to overlook: even if you're watching the right percentile, does it remain stable or fluctuate?
Redis Open Source 8.8.0 was tested on four AWS r6g.8xlarge nodes, with 32 Redis processes per node, 128 processes across the cluster. The configuration used replication factor 2, appendonly no, save "", and io-threads 2. Aerospike was tested on the same four r6g.8xlarge nodes, at a replication factor of 2, and run entirely in memory to match Redis's own configuration. Both engines served the same dataset: 500 million 325-byte records under a uniform 90/10 read/update YCSB workload, with no hot set, so every key was equally likely to be requested, and neither system had a favorable subset to lean on.
Each of the three throughput targets was measured over a full one-hour run, in successive 10-second windows, for both engines. The benchmark authors caution that at this level of precision, where measurements are taken in fractions of a millisecond, individual results can be sensitive to ordinary environmental noise. The results are therefore best interpreted in terms of their overall direction and shape rather than as precise absolute values.
The first signs of trouble show up in throughput. Instead of simply measuring the peak rate each target can reach, the benchmark asks how consistently it can sustain the requested rate across measurement windows.
Dependable rate is the rate a system sustained for at least 95% of the measurement windows, applying percentile thinking to throughput rather than latency. Rate jitter measures how much the delivered rate varied from the target between windows.
Target | Redis dependable rate | Redis rate jitter | Aerospike dependable rate | Aerospike rate jitter |
|---|---|---|---|---|
1.6M ops/s | 1.60M | 0.0% | 1.60M | ≤0.2% |
2.0M ops/s | 1.99M | 1.8% | 2.00M | ≤0.2% |
2.4M ops/s | 2.10M | 4.4% | 2.39M | ≤0.2% |
At 2.0 million operations per second, Redis still lands almost exactly on target 95% of the time. But the swing goes from zero to 1.8%. By 2.4 million operations per second, this swing more than doubles to 4.4%, and the rate you can actually count on slips to 2.10 million, a substantial gap from the 2.4 million requested. Aerospike, measured on the same hardware and workload, maintained its dependable rate within a hair of the target at every level and never showed rate jitter above 0.2% across all targets tested (Aerospike vs. Redis benchmark). The two systems aren't just different in degree here: Redis's swing widened as load rose; Aerospike's didn't move.
Latency follows the same pattern as throughput, with two things to watch: where each percentile lands over the full run and how much it varies from one 10-second window to the next. In the tables below, each figure represents the percentile value across the full run. The value after ± is the standard deviation across the 10-second windows, showing how much latency varied over time.
Load | Median | p99 | p99.99 | |
|---|---|---|---|---|
Redis | 1.6M ops/s | 0.46 ms (± 0.00) | — | 2.01 ms (± 0.31) |
2.4M ops/s | 0.66 ms (± 0.71) | 2.77 ms (± 1.37) | 9.19 ms (± 8.53) | |
Aerospike | 1.6M ops/s | 0.23 ms | — | 1.55 ms (± ~0.21) |
2.4M ops/s | 0.28 ms (± 0.00) | 0.84 ms | 2.88 ms (± 0.52) |
The Redis median rises from 0.46 ms to 0.66 ms (about 1.4x), and its swing rises right along with it, ending up almost as large as the median itself. Its P99.99 rises from 2.01 ms to 9.19 ms (about 4.6x), while its swing grows roughly 27-fold, from 0.31 ms to 8.53 ms. The typical request remains comfortably sub-millisecond, but its predictability changes significantly. Aerospike's numbers over the same range move by comparison: median from 0.23 ms to 0.28 ms, p99.99 from 1.55 ms to 2.88 ms, with the p99.99 standard deviation rising from roughly 0.21 ms to 0.52 ms, a fraction of Redis's swing at the same load.
The swing matters not because it's a target in its own right. Picking a percentile to watch (p99, p99.9, whatever your SLA uses) already means accepting some fraction of requests will be slower than the rest. What the swing tells you is how much margin you have below that threshold, and whether that margin is stable or about to run out. A p99.99 that reliably sits at 9 ms is a known, bookable cost. One that pools to 9 ms over the whole run, but is really bouncing between 2 ms and 20 ms window to window, will still trip an SLA evaluated on any shorter window. This is the kind of alert that can clear before anyone gets a chance to investigate, because the long-run number may never move. Think of it as an early-warning gauge on your SLA margin, not a second SLA of its own.
The most striking figure is Redis's median row at 2.4 million operations per second. A swing of 0.71 ms, compared with a median of only 0.66 ms, means that the typical request's latency is now moving by more than its own value from one window to the next, as instability originating in the deep tail has reached the request every user hits. Aerospike's median swing at the same load was effectively zero. Average and minimum tell you where a system was; the swing tells you how much it moved.
p99.99 represents the slowest 0.01% of requests, a measure easy enough to write off. But at 2.4 million operations per second, that "rare" event occurs roughly 240 times per second. A real user interaction rarely consists of a single database call, often involving several operations, from permission checks and lookups to recommendations, and the overall experience is ultimately limited by the slowest dependency in the request path.
If a single call meets a given percentile threshold 99.99% of the time, the probability that all N independent calls
meet it is 0.9999^N. At five calls, that's about 0.05% of interactions carrying a deep-tail hit, five times the per-call rate. At fifty, it's about 0.5%. At five hundred (think fraud check or a recommendation engine fanning out into hundreds of lookups), it's about 5%, which is nearly one interaction in twenty. The per-call rarity remained unchanged; what changed was the fan-out. The p99.99 latency of the system handling those calls determines how much that tail latency affects the overall interaction.
Instability shows up in at least two concrete ways. The first is over-provisioning. At the highest tested load, the target was 2.4 million operations per second, but the rate Redis actually delivered 95% of the time was 2.10 million, a capacity gap of roughly 0.3 million you can't treat as usable. Aerospike's dependable rate at the same target, 2.39 million, left a gap of roughly 0.01 million (Aerospike vs. Redis benchmark). Sizing for the peak means sizing for a number the system can't reliably hold; sizing for the dependable rate means paying for headroom you may rarely
need. A system with a tighter margin between "peak" and "dependable" is cheaper to plan around, whichever system turns out to be for a given workload.
The second is harder to put a number on: incidents that appear and vanish before anyone can investigate. A tail that spikes for one window and settles back down can trip a user complaint or a page, and by the time an engineer checks the dashboard, the long-run average looks fine. When the underlying system fluctuates from window to window, as Redis did at 2.4 million operations per second, that variability reflects the normal behavior of a system operating near its limit.
This leaves a short list of things worth checking in any system carrying a latency-sensitive workload. What rate does it actually hold in at least 95% of measurement windows, not just on average? How much does your SLA percentile move from one window to the next, and how much margin does that leave you? And how many dependent calls does a single user-facing request actually make, since this is what turns a rare per-call event into a routine per-interaction one? Run those three questions against both sets of figures above, and the difference between "approaching its limit" and "still comfortably inside it" becomes concrete rather than a matter of impression.
None of this means Redis is slow. At 2.4 million operations per second, it still typically responds in well under a millisecond. The important point is what happens as a system approaches its limits: the first symptom is often variability, and the same benchmark that shows it in Redis also shows what the same test looks like when a system isn't approaching its limit at that load. The numbers you trust can start to obscure what the system is actually doing from one moment to the next, making it important to understand what is happening beneath the headline metrics.
For a deeper understanding and more insights, explore these additional resources.
See moreBlog
Blog
Blog
Blog