Ruvio.

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
CommandRuvioRedis 8.10.2Ruvio / Redis
PING (bulk)2.93M req/s3.05M req/s0.96×
SET2.73M req/s2.17M req/s1.26×
GET2.90M req/s2.65M req/s1.09×
INCR2.99M req/s2.51M req/s1.19×
LPUSH2.30M req/s1.82M req/s1.26×
RPUSH2.32M req/s2.01M req/s1.16×
LPOP2.09M req/s1.80M req/s1.16×
RPOP2.08M req/s1.95M req/s1.07×
SADD2.40M req/s2.38M req/s1.01×
HSET2.27M req/s1.85M req/s1.23×
SPOP2.56M req/s2.65M req/s0.97×
ZADD2.38M req/s1.90M req/s1.25×
LRANGE 1000.22M req/s0.22M req/s1.00×
LRANGE 3000.08M req/s0.08M req/s1.01×
LRANGE 5000.05M req/s0.04M req/s1.04×
LRANGE 6000.04M req/s0.03M req/s1.12×
MSET1.39M req/s0.43M req/s3.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.

RuvioRedis 8.10.2
Idle RSS9,360 KiB7,200 KiB
After 1,000,000 strings94,128 KiB139,472 KiB
Delta82.8 MiB129.2 MiB
Ruvio / Redis0.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
CommandMedian req/sSamples
SET2,444,9882,444,988 / 2,409,639 / 2,617,801
GET3,154,5743,154,574 / 2,881,844 / 3,344,482
INCR2,631,5792,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.

CommandRuvioRedis 8.10.2Ruvio / Redis
PING (bulk)1.92M req/s1.97M req/s0.97×
SET2.01M req/s1.72M req/s1.17×
GET2.02M req/s2.03M req/s1.00×
INCR2.14M req/s1.97M req/s1.09×
LPUSH1.55M req/s1.56M req/s0.99×
RPUSH1.55M req/s1.49M req/s1.04×
LPOP1.60M req/s1.49M req/s1.08×
RPOP1.61M req/s1.64M req/s0.98×
SADD1.64M req/s1.86M req/s0.88×
HSET1.59M req/s1.55M req/s1.02×
SPOP2.02M req/s2.07M req/s0.97×
ZADD1.75M req/s1.59M req/s1.10×
LRANGE 1001.44M req/s1.54M req/s0.93×
LRANGE 3001.59M req/s1.40M req/s1.14×
LRANGE 5001.54M req/s1.55M req/s0.99×
LRANGE 6001.63M req/s1.28M req/s1.27×
MSET0.55M req/s0.37M req/s1.46×

Memory is macOS ps RSS. Fresh processes, then 1,000,000 explicit keys k0…k999999, 64-byte values, pipeline 200.

RuvioRedis 8.10.2
Idle RSS9,200 KiB7,344 KiB
After 1,000,000 strings93,872 KiB137,776 KiB
Delta82.7 MiB127.4 MiB
Ruvio / Redis0.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.

CommandRuvioRedis 8.10.2Ruvio / Redis
PING (bulk)1,129,944 req/s991,080 req/s1.14×
SET1,033,058 req/s961,539 req/s1.07×
GET1,088,139 req/s882,613 req/s1.23×
INCR885,740 req/s992,064 req/s0.89×
LPUSH933,707 req/s534,188 req/s1.75×
RPUSH980,392 req/s824,402 req/s1.19×
LPOP998,004 req/s529,101 req/s1.89×
RPOP1,017,294 req/s964,320 req/s1.05×
SADD1,023,541 req/s928,505 req/s1.10×
HSET965,251 req/s884,956 req/s1.09×
SPOP906,618 req/s1,014,199 req/s0.89×
ZADD965,251 req/s943,396 req/s1.02×
LRANGE 100967,118 req/s531,915 req/s1.82×
LRANGE 3001,013,171 req/s519,481 req/s1.95×
LRANGE 500977,517 req/s512,558 req/s1.91×
LRANGE 600971,817 req/s526,316 req/s1.85×
MSET383,730 req/s458,295 req/s0.84×

Memory is container VmRSS for 1,000,000 live 64-byte strings, measured from an empty process.

RuvioRedis 8.10.2
Idle VmRSS11,796 KiB27,916 KiB
After 1,000,000 strings103,436 KiB156,268 KiB
Delta89.5 MiB125.3 MiB
Ruvio / Redis0.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.

CommandRuvioRedis 8.10.2Ruvio / Redis
SET719,424 req/s680,272 req/s1.06×
GET746,269 req/s746,269 req/s1.00×
INCR826,446 req/s800,000 req/s1.03×
SADD95,077 req/s97,472 req/s0.98×
ZADD90,211 req/s92,135 req/s0.98×
GEOADD84,007 req/s84,130 req/s1.00×
GEOSEARCH5,664 req/s3,937 req/s1.44×
SET, 1,000,000 keys+86.3 MiB+120.6 MiB0.72×
INCR, 1,000,000 keys+24.3 MiB+43.9 MiB0.55×
SADD, 80,000 × 4+6.5 MiB+7.1 MiB0.92×
ZADD, 80,000 × 4+9.4 MiB+8.0 MiB1.18×
GEOADD, 80,000 × 4+9.2 MiB+10.4 MiB0.88×
SUBSCRIBE, 2,000 connections+10.1 MiB+10.5 MiB0.96×

This is a Docker Desktop table, not bare metal. The same table and method are in docs/BENCHMARK_RESULTS.md.

Still open

The workflow .github/workflows/pages.yml publishes the site/ directory from main.