Redis protocol server, written in Rust · v0.3.2
One process instead of a cache, a lock service and a delay queue.
Ruvio speaks RESP, so redis-cli and your existing clients connect. Each shard owns its keys: no lock on the hot path, and the durability you choose at startup.
- 287 commands
- 6 first-party clients
- Linux, macOS and Windows builds
$ docker run -d -p 6379:6379 \
-e RUVIO_REQUIREPASS=change-me \
salihcantekin/ruvio:linux
$ redis-cli -a change-me
6379> LEASE job:nightly 30000
(integer) 1
6379> LIMIT api:key:42 100 60000
(integer) 99Product
Coordination work, finished on the shard that owns the key
The jobs teams usually spread over several services are single commands in Ruvio, next to the strings, hashes, lists, sets, sorted sets, streams and JSON you already use.
Caches without stampedes
When a hot key expires, one caller refills it while the others wait or get the stale copy.
Locks and leases
A named lease returns a fencing token; a semaphore caps holders, each with its own expiry.
Conditional writes
Versioned writes, stock that cannot go negative, and request replays that return the stored answer.
Rate limits
A fixed window per key in one call, returning what is left of the allowance.
Change feeds
Read the writes on a shard from a cursor instead of polling keys.
Delayed jobs
A stream entry stays hidden from consumer groups until its delay passes.
Performance
Faster than Redis on the commands you run every day
Each bar is one command measured against Redis 8.10.2 on the same machine. Bars outside the dashed ring are faster than Redis; bars inside it are slower.
Largest gains
- GEOSEARCH (radius 50 km, COUNT 10)2.48×44K vs 18K ops/s
- SETEX2.00×2.50M vs 1.25M ops/s
- MSET (3 keys)2.00×2.20M vs 1.10M ops/s
- GEOADD1.74×1.94M vs 1.11M ops/s
- GETEX (set a 100 s deadline)1.71×2.37M vs 1.38M ops/s
Still behind Redis (3)
- HGETALL (10-field hash)0.97×763K vs 789K ops/s
- TOUCH0.92×2.31M vs 2.50M ops/s
- FILLGET (value present)0.85×1.96M vs 2.31M ops/s
Source: benchmark/records/mac-2026-10-14.json · Apple M4 Pro, 12 cores, 24 GiB, macOS 26.6.2 arm64 · 50 clients, pipeline 16 · in-memory profile, 1 shard · all results
Largest gains
- DUMP (64 B string)2.15×726K vs 338K ops/s
- LINSERT (pivot missing, scans 100)1.88×789K vs 421K ops/s
- LREM (value missing, scans 100)1.67×789K vs 474K ops/s
- LPOS (100 elements, hit in the middle)1.41×643K vs 457K ops/s
- GEOSEARCH (radius 50 km, COUNT 10)1.40×15K vs 11K ops/s
Still behind Redis (11)
- GETEX (set a 100 s deadline)0.96×634K vs 657K ops/s
- PUBLISH (no subscribers)0.96×738K vs 769K ops/s
- MEMORY USAGE0.95×709K vs 744K ops/s
- PFADD0.95×703K vs 744K ops/s
- TTL0.94×750K vs 796K ops/s
- FILLGET (value present)0.93×672K vs 720K ops/s
- EXISTS0.92×738K vs 804K ops/s
- DEL (missing key)0.92×756K vs 826K ops/s
- GETBIT (1 KiB bitmap)0.90×763K vs 849K ops/s
- TOUCH0.89×709K vs 796K ops/s
- HGETALL (10-field hash)0.87×398K vs 457K ops/s
Source: benchmark/records/linux-hostinger-2026-10-14.json · AMD EPYC 9354P 32-Core Processor (KVM guest), 2 vCPU, Linux 6.8.0-146-generic x86_64 · 50 clients, pipeline 16 · in-memory profile, 1 shard · all results
Memory
Less memory for the same data
Memory added by loading each data shape, Ruvio next to Redis on the same machine. Left is less; the axis is logarithmic, so the same saving has the same length at any size.
Source: benchmark/records/mac-2026-10-14.json · Apple M4 Pro, 12 cores, 24 GiB, macOS 26.6.2 arm64
Source: benchmark/records/linux-hostinger-2026-10-14.json · AMD EPYC 9354P 32-Core Processor (KVM guest), 2 vCPU, Linux 6.8.0-146-generic x86_64
Whole machine
8 shards in one process against Redis on 8 cores
Redis uses one core per process, so a whole machine means a Redis Cluster. Here Ruvio runs 8 shards in one process on 8 cores, against a Redis Cluster of 8 nodes on the same cores and against a single Redis process on one core. Each shard gets the same load as each Redis node.
Source: benchmark/records/x86-azure-2026-10-16-8-shards-final.json, pipeline 64 and everysec · Azure F16as_v6, AMD EPYC 9V74, 16 cores · 50 clients per shard, 3 alternating rounds · how it is measured
Architecture
One owner per shard
The shard that owns a key parses, records, applies and replies. The hot path takes no lock and does not hop to another thread, and a feature allocates only when a key uses it.
Durability
Choose how much you can afford to lose
Pick a profile at startup. A write is checked, appended, then applied; if the log cannot take the record, the key stays as it was and later writes are refused.
alwaysfdatasync before the replyOnly a write that was never acknowledged (a torn final record).
everysecsync_interval_ms = 1000Writes the kernel accepted but had not synced yet.
snapshotsnapshot_interval_ms = 60000Writes after the last durable checkpoint.
memoryno disk writesAll in-memory state when the process stops.
Bounds from docs/RECOVERY.md; intervals are the defaults in ruvio.example.toml.
Compatibility
287 commands in 21 families, one square each
The command list is checked in CI. Every command has a typed method in all 6 first-party clients, with cluster routing from one seed address.
Run it next to your app in a minute
One binary or one container. Your Redis client already knows how to talk to it.