Operations
Observe
INFO and INFO prometheus describe the shard that received the command. When metrics_address is set, that shard also serves GET /metrics on a separate port. Successful GET, SET, and INCR only move counters. Histograms are scraped, not pushed per command.
Operational lines go to a bounded background writer. A full queue drops the line and increments ruvio_log_lines_dropped_total instead of stalling the shard. RUST_LOG selects the filter at startup.
Memory and expiry
max_shard_bytes and max_process_bytes default to 0, which disables those budgets. noeviction rejects writes over the budget. Sampled policies are allkeys-lru, allkeys-lfu, volatile-lru, and volatile-ttl. Deadlines are Unix milliseconds. After recovery the clock floor is max(CLOCK, checkpoint.created_at).
Benchmarks
2026-10-04, native, against Redis 8.10.2
Apple M4 Pro, 12 cores, 24 GiB, macOS 26.6.2, arm64. No Docker. This is not bare-metal Linux. Ruvio release build of 1d7e691 with the hot-path changes from this release. Default features (evented, mimalloc), durability memory, 1 shard, port 6411. Redis 8.10.2 on port 6412, run with --save "" --appendonly no. Both are fresh processes on loopback.
The client is redis-benchmark 8.10.2: 50 clients, pipeline 16, 64-byte values, fixed key, one invocation per command. Each command runs 3 rounds and the table shows the median. The order alternates each round: Ruvio first, then Redis first. Requests per invocation are 1,000,000. The exceptions are LRANGE 100/300/500/600 (200k/100k/60k/50k) and MSET (500k).
After each LRANGE test, LLEN mylist was read on both servers and was non-zero. That check is new. The 2026-10-01 LRANGE rows below most likely read an empty list.
Rates are rounded to 0.01 million requests/s. A ratio from 0.90× to 1.10× is a tie on this laptop. The whole run took 74 s.
python3 scripts/redis_compare.py --out target/redis-compare
| Command | Ruvio | Redis 8.10.2 | Ruvio / Redis |
|---|---|---|---|
| PING (bulk) | 2.93M req/s | 3.05M req/s | 0.96× |
| SET | 2.73M req/s | 2.17M req/s | 1.26× |
| GET | 2.90M req/s | 2.65M req/s | 1.09× |
| INCR | 2.99M req/s | 2.51M req/s | 1.19× |
| LPUSH | 2.30M req/s | 1.82M req/s | 1.26× |
| RPUSH | 2.32M req/s | 2.01M req/s | 1.16× |
| LPOP | 2.09M req/s | 1.80M req/s | 1.16× |
| RPOP | 2.08M req/s | 1.95M req/s | 1.07× |
| SADD | 2.40M req/s | 2.38M req/s | 1.01× |
| HSET | 2.27M req/s | 1.85M req/s | 1.23× |
| SPOP | 2.56M req/s | 2.65M req/s | 0.97× |
| ZADD | 2.38M req/s | 1.90M req/s | 1.25× |
| LRANGE 100 | 0.22M req/s | 0.22M req/s | 1.00× |
| LRANGE 300 | 0.08M req/s | 0.08M req/s | 1.01× |
| LRANGE 500 | 0.05M req/s | 0.04M req/s | 1.04× |
| LRANGE 600 | 0.04M req/s | 0.03M req/s | 1.12× |
| MSET | 1.39M req/s | 0.43M req/s | 3.26× |
Memory is macOS ps RSS. Each server is a fresh process. The script writes 1,000,000 explicit keys k0…k999999 with 64-byte values over one connection at pipeline 200.
| Ruvio | Redis 8.10.2 | |
|---|---|---|
| Idle RSS | 9,360 KiB | 7,200 KiB |
| After 1,000,000 strings | 94,128 KiB | 139,472 KiB |
| Delta | 82.8 MiB | 129.2 MiB |
| Ruvio / Redis | 0.64× | |
The script also writes results.json with every sample, host and build details, and the LLEN checks. Method and both tables: docs/BENCHMARK_RESULTS.md.
2026-10-01, Apple M4 Pro, native
Native release binary, no Docker, no Redis comparison, not bare-metal Linux. Apple M4 Pro, 12 cores, 24 GiB, macOS 26.6.2, arm64. Build 8ffc82a, default features (evented, mimalloc), durability memory, 1 shard, loopback. redis-benchmark 8.10.2, one invocation per sample, three samples, fixed key key:__rand_int__.
redis-benchmark -h 127.0.0.1 -p 6411 -n 1000000 -c 50 -P 16 -d 64 -t set,get,incr --csv
| Command | Median req/s | Samples |
|---|---|---|
| SET | 2,444,988 | 2,444,988 / 2,409,639 / 2,617,801 |
| GET | 3,154,574 | 3,154,574 / 2,881,844 / 3,344,482 |
| INCR | 2,631,579 | 2,680,965 / 2,631,579 / 2,577,320 |
GET in this combined invocation runs higher than a GET-only invocation (-t get, same flags, same build and host): median 2,762,431 (2,762,431 / 2,638,522 / 2,785,515). Quote a GET figure together with its invocation. Samples on this laptop moved by about ±10% between runs. The same table is in docs/BENCHMARK_RESULTS.md.
2026-10-01, native, against Redis 8
Same Apple M4 Pro, no Docker, not bare-metal Linux. One sample per command, Ruvio then Redis. A ratio from 0.90× to 1.10× sits inside the ±10% movement seen on this laptop. Build 3188283, evented, mimalloc, durability memory, 1 shard, port 6411. Redis 8.10.2 on port 6412 with --save "" --appendonly no. Fixed key, 1,000,000 requests, 50 clients, pipeline 16, 64-byte values. Rates are rounded to 0.01 million requests/s. PING inline is absent: Ruvio returns ERR protocol error for that form.
| Command | Ruvio | Redis 8.10.2 | Ruvio / Redis |
|---|---|---|---|
| PING (bulk) | 1.92M req/s | 1.97M req/s | 0.97× |
| SET | 2.01M req/s | 1.72M req/s | 1.17× |
| GET | 2.02M req/s | 2.03M req/s | 1.00× |
| INCR | 2.14M req/s | 1.97M req/s | 1.09× |
| LPUSH | 1.55M req/s | 1.56M req/s | 0.99× |
| RPUSH | 1.55M req/s | 1.49M req/s | 1.04× |
| LPOP | 1.60M req/s | 1.49M req/s | 1.08× |
| RPOP | 1.61M req/s | 1.64M req/s | 0.98× |
| SADD | 1.64M req/s | 1.86M req/s | 0.88× |
| HSET | 1.59M req/s | 1.55M req/s | 1.02× |
| SPOP | 2.02M req/s | 2.07M req/s | 0.97× |
| ZADD | 1.75M req/s | 1.59M req/s | 1.10× |
| LRANGE 100 | 1.44M req/s | 1.54M req/s | 0.93× |
| LRANGE 300 | 1.59M req/s | 1.40M req/s | 1.14× |
| LRANGE 500 | 1.54M req/s | 1.55M req/s | 0.99× |
| LRANGE 600 | 1.63M req/s | 1.28M req/s | 1.27× |
| MSET | 0.55M req/s | 0.37M req/s | 1.46× |
Memory is macOS ps RSS. Fresh processes, then 1,000,000 explicit keys k0…k999999, 64-byte values, pipeline 200.
| Ruvio | Redis 8.10.2 | |
|---|---|---|
| Idle RSS | 9,200 KiB | 7,344 KiB |
| After 1,000,000 strings | 93,872 KiB | 137,776 KiB |
| Delta | 82.7 MiB | 127.4 MiB |
| Ruvio / Redis | 0.65× | |
Method and both tables: docs/BENCHMARK_RESULTS.md.
2026-10-01, Docker Desktop, equal caps
Same host, Docker Desktop Linux VM, not the native table and not bare metal. Both containers: --cpus=4 --memory=2g --memory-swap=2g. Image ruvio-cmp:20261001 from 3188283, evented, mimalloc, durability memory, 1 shard, port 6391. Redis redis:8-alpine 8.10.2, port 6392, --save "" --appendonly no. One sample, Ruvio then Redis, same benchmark flags as the native comparison. Probe containers were removed afterward.
| Command | Ruvio | Redis 8.10.2 | Ruvio / Redis |
|---|---|---|---|
| PING (bulk) | 1,129,944 req/s | 991,080 req/s | 1.14× |
| SET | 1,033,058 req/s | 961,539 req/s | 1.07× |
| GET | 1,088,139 req/s | 882,613 req/s | 1.23× |
| INCR | 885,740 req/s | 992,064 req/s | 0.89× |
| LPUSH | 933,707 req/s | 534,188 req/s | 1.75× |
| RPUSH | 980,392 req/s | 824,402 req/s | 1.19× |
| LPOP | 998,004 req/s | 529,101 req/s | 1.89× |
| RPOP | 1,017,294 req/s | 964,320 req/s | 1.05× |
| SADD | 1,023,541 req/s | 928,505 req/s | 1.10× |
| HSET | 965,251 req/s | 884,956 req/s | 1.09× |
| SPOP | 906,618 req/s | 1,014,199 req/s | 0.89× |
| ZADD | 965,251 req/s | 943,396 req/s | 1.02× |
| LRANGE 100 | 967,118 req/s | 531,915 req/s | 1.82× |
| LRANGE 300 | 1,013,171 req/s | 519,481 req/s | 1.95× |
| LRANGE 500 | 977,517 req/s | 512,558 req/s | 1.91× |
| LRANGE 600 | 971,817 req/s | 526,316 req/s | 1.85× |
| MSET | 383,730 req/s | 458,295 req/s | 0.84× |
Memory is container VmRSS for 1,000,000 live 64-byte strings, measured from an empty process.
| Ruvio | Redis 8.10.2 | |
|---|---|---|
| Idle VmRSS | 11,796 KiB | 27,916 KiB |
| After 1,000,000 strings | 103,436 KiB | 156,268 KiB |
| Delta | 89.5 MiB | 125.3 MiB |
| Ruvio / Redis | 0.71× | |
The same table is in docs/BENCHMARK_RESULTS.md.
Docker Desktop, against Redis 8
Docker Desktop numbers detect large regressions on one machine. They are not a bare-metal claim and not a Redis parity claim. Methodology and the older result files are docs/BENCHMARKING.md and docs/BENCHMARK_RESULTS.md.
CPU_LIMIT=1 ./scripts/benchmark.sh
The script needs Docker, redis-benchmark, and redis-cli. It builds a release image, runs Redis 8 and Ruvio with the same CPU and memory caps, and writes CSV plus summary.json.
2026-09-30, Apple M4 Pro, Docker Desktop
Host: Apple M4 Pro, 12 cores, 24 GiB, macOS 26.6.2, arm64, Docker Desktop 29.8.0. Containers had no CPU or memory cap. Ruvio image ruvio:hotpath, evented runtime, mimalloc, durability memory, 1 shard. Redis redis:8-alpine 8.10.2 with --save "" --appendonly no --protected-mode no. Ports 6399 and 6398. Probe containers were removed after the run.
Throughput is the median of 3 rounds, alternating which server ran first. SET, GET, and INCR: redis-benchmark, 100,000 requests, 50 clients, pipeline 16, 64-byte values, one key. SADD and ZADD: one connection, pipeline 32, 100,000 commands, key index % 1024 (about 98 members per key), ZADD score 1. GET, INCR, SADD, and ZADD are a second pass the same day. SET and the memory rows are the first pass. GEOADD uses that same pipeline shape, with longitude and latitude. GEOSEARCH loads 4,096 points into one key, then runs 20,000 searches at pipeline 16, 15 km, COUNT 10 ASC. The GEOADD memory row is 80,000 keys with 4 members. Those three rows are a later pass the same day.
Memory is one VmRSS delta: after the load, minus the empty process. SET is 1,000,000 distinct 64-byte values. INCR is 1,000,000 distinct keys. SADD, ZADD, and GEOADD are 80,000 keys with 4 members. SUBSCRIBE is 2,000 idle connections on one channel.
| Command | Ruvio | Redis 8.10.2 | Ruvio / Redis |
|---|---|---|---|
| SET | 719,424 req/s | 680,272 req/s | 1.06× |
| GET | 746,269 req/s | 746,269 req/s | 1.00× |
| INCR | 826,446 req/s | 800,000 req/s | 1.03× |
| SADD | 95,077 req/s | 97,472 req/s | 0.98× |
| ZADD | 90,211 req/s | 92,135 req/s | 0.98× |
| GEOADD | 84,007 req/s | 84,130 req/s | 1.00× |
| GEOSEARCH | 5,664 req/s | 3,937 req/s | 1.44× |
| SET, 1,000,000 keys | +86.3 MiB | +120.6 MiB | 0.72× |
| INCR, 1,000,000 keys | +24.3 MiB | +43.9 MiB | 0.55× |
| SADD, 80,000 × 4 | +6.5 MiB | +7.1 MiB | 0.92× |
| ZADD, 80,000 × 4 | +9.4 MiB | +8.0 MiB | 1.18× |
| GEOADD, 80,000 × 4 | +9.2 MiB | +10.4 MiB | 0.88× |
| SUBSCRIBE, 2,000 connections | +10.1 MiB | +10.5 MiB | 0.96× |
This is a Docker Desktop table, not bare metal. The same table and method are in docs/BENCHMARK_RESULTS.md.
Still open
- Published bare-metal latency and a 24-hour soak.
- Automatic failover and
REPLICAOF. A caught-up replica is promoted by hand. The steps are on the replication page. - A live GitHub Pages deploy until this site is on
mainand Pages is enabled for thepagesworkflow.
The workflow .github/workflows/pages.yml publishes the site/ directory from main.