Skip to content

Benchmarks

Recached publishes no cross-project performance comparison. Everything below measures Recached alone, and says nothing about how any other cache performs on this or any other host.

The supported claim is narrower: Recached schedules command execution across worker threads. Measure throughput, latency, and memory again for the exact commit, images, host, and workload you plan to deploy.

Thread-scaling evidence

Measured 2026-09-13 with redis-benchmark 8.10.1 via scripts/bench-scaling.sh. Only RECACHED_WORKER_THREADS varies: one binary, one workload, one fixed four-core server CPU set.

Conditions

CPUIntel i5-9400F, 6 cores, no SMT, powersave governor
PlacementPIN=1 SERVER_CPUS=0-3 BENCH_CPUS=4-5
PersistenceRECACHED_SAVE_INTERVAL=0, no AOF, no replicas
Workload-n 1000000 -c 50 -d 64 -r 100000 -P 16

The governor is powersave and could not be changed on the test host, so absolute figures are conservative. The ratios between columns are unaffected, which is the point of holding everything but the worker count fixed.

Scaling depends on key distribution

This is the result worth internalising, and it is not visible in an aggregate number.

Command1 thread2 threads4 threads4-thread change
GET819,6721,689,1891,658,375+102%
SET316,857580,720769,823+143%
INCR330,688602,047761,615+130%
Key-distributed total1,467,2172,871,9563,189,812+117%
SADD474,608331,455333,778−30%
LPUSH397,772282,885291,630−27%
HSET345,185248,818258,799−25%
ZADD333,000241,196250,564−25%
Single-key total1,550,5661,104,3551,134,772−27%

The first three tests spread writes over 100,000 keys (-r 100000) and scale with worker count. The last four are redis-benchmark's collection tests, which push every operation into one key — mylist, myset, myhash, myzset. A single key lives on a single shard, so extra workers cannot execute those commands in parallel; they only add contention and cache-line traffic, and throughput drops by about a quarter before flattening.

Neither half is the "real" number. Which one describes your deployment depends entirely on whether your writes are spread across keys or concentrated on a few hot ones. If you have one hot key, adding cores will not help it, and this table shows roughly what it costs.

GET also stops improving between two and four threads. At 1.7M requests/s the load generator has only two cores to the server's four, so that plateau is the harness, not the server.

Latency, unpipelined

-P 1 -c 16, where each request is a full round trip. Throughput here is bounded by client concurrency rather than by the server, so read the latency column, not the rate.

Command1 thread2 threads4 threads
SET p50183 µs95 µs135 µs
GET p5095 µs87 µs95 µs
INCR p50183 µs95 µs127 µs

Browser push latency

The tables above measure the RESP port. The sync path was measured separately, over a real WebSocket, on the same host: a SET on the RESP port arriving at a subscribed browser client as a keychange.

p50p90p99max
151 µs261 µs698 µs2.5 ms

redis-benchmark cannot measure this path, so it comes from the project's own WebSocket harness. It is the push path — the server telling a browser something changed — not what a browser read costs, which is a local WebAssembly memory lookup with no server involved.

A note on collection sizes

Before 0.3.4, every write to a collection key recomputed that key's memory footprint by walking it, which made building an N-element collection O(N²). HSET into a 100k-field hash ran at 2,838 ops/s where SET managed 349,650, and halved again with every doubling of the field count. Collections now maintain their size incrementally, and the same test runs at 380,228 ops/s and stays flat as the hash grows.

If you are benchmarking a release before 0.3.4, or comparing against published numbers from one, this is the difference.

Run the current suite

Thread scaling

Use the same release binary while changing only the worker count:

bash
cargo build --release --package recached
THREADS="1 2 4 8" scripts/bench-scaling.sh

On Linux, isolate the server and load generator when the host has enough cores:

bash
PIN=1 SERVER_CPUS=0-3 BENCH_CPUS=4-7 scripts/bench-scaling.sh

The script verifies the worker count reported by the server. Compare columns within one run; do not combine absolute numbers from different machines.

A server already running

scripts/benchmark.sh measures whichever RESP server is listening at the selected host and port:

bash
RECACHED_BIND=127.0.0.1 RECACHED_SAVE_INTERVAL=0 ./target/release/recached-server
scripts/benchmark.sh

Repeat with identical settings for each server. Record binary versions, configuration, CPU placement, persistence mode, request count, concurrency, value size, key distribution, and pipeline depth.

Memory

Recached reports a logical key/value estimate through INFO used_memory and the recached_memory_bytes metric. That is not process RSS: it excludes allocator overhead, internal indexes and fragmentation, so it is the right number for reasoning about a configured eviction threshold and the wrong one for sizing a host.

For host sizing, measure RSS of the server process against a known DBSIZE, using a fresh process per data shape. Use enough keys that the delta dwarfs the baseline, repeat the run, and report medians — short runs contain lazy initialisation and allocator noise. Do not turn one result into a universal "times more memory" claim.

Interpreting results

  • Compare medians across repeated runs, not one best result.
  • Separate pipelined throughput from single-request latency.
  • Treat a benchmark as evidence only for the tested commands and data shapes.
  • Run with production persistence, replication, TLS, and value sizes before capacity planning.
  • Use process RSS for host sizing; use Recached's logical memory counter to understand its configured eviction threshold.

Recached's product distinction is the shared server-and-browser engine. The RESP benchmarks above do not measure the browser read path at all: those reads come from local WebAssembly memory and never leave the tab. The only browser-side number here is push latency, which measures how quickly a server-side write reaches a subscribed client — a different question from how fast that client can read.

Released under the Apache License 2.0.