Benchmarks

Measured against Redis, on the same machine, from the records in the repository

Each run starts both servers on one host, drives them with the same load generator in alternating rounds, and stores the raw numbers in a JSON file next to the site. The charts below are drawn from those files when the site is built.

Apple M4 Pro1.25×geometric mean over 60 commands; 57 at 0.97× or faster; memory −26%
AMD EPYC, 2 vCPU1.09×geometric mean over 60 commands; 49 at 0.97× or faster; memory −19%

Two machines

Where each command lands on both machines

Each dot is one command: its ratio to Redis on Apple M4 Pro across, on AMD EPYC, 2 vCPU up. The shaded corner holds the commands that are faster than Redis on both. Dots near the faint diagonal behave the same on ARM and x86.

0.7×1×1.5×2×2.5×0.7×1×1.5×2×2.5×Apple M4 Pro: Ruvio ÷ RedisAMD EPYC, 2 vCPU: Ruvio ÷ Redis41 faster on both14 on Apple M4 Pro only2 on AMD EPYC (x86) only3 behind on both

Reading it

The two machines are very different: a 12-core laptop chip with no pinning, and a 2 vCPU cloud guest with the server and the load generator pinned to separate CPUs. A command that stays top-right on both is fast because of how Ruvio runs it, not because of the hardware.

faster on bothfaster on onebehind on both

Sources: benchmark/records/mac-2026-10-14.json, benchmark/records/linux-hostinger-2026-10-14.json

Distribution

All 60 commands on one axis

The same results as a swarm: one dot per command, stacked where they crowd. Most of the mass sits right of the dashed Redis line on both machines.

0.7×0.8×Redis 1×1.25×1.5×2×2.5×Apple M4 Promedian 1.20×AMD EPYC (x86)median 1.05×

Under load

Throughput and tail latency together

Each line joins Redis (hollow) to Ruvio (filled). In the first column further right is more requests per second; in the second, further left is a lower p99. Rows cover client counts, pipelining, fsync on every write, and more Ruvio shards.

RedisRuvio
ScenarioRequests per second → betterp99 latency ← better

No pipelining

SET · 50 clients, no pipeline
1.05×
0.49 ms
GET · 50 clients, no pipeline
1.00×
0.46 ms
SET · 200 clients, no pipeline
1.05×
1.8 ms
GET · 200 clients, no pipeline
1.00×
1.7 ms

Pipeline 16

SET · 200 clients, pipeline 16
1.43×
3.1 ms
HSET · 200 clients, pipeline 16
1.11×
4.1 ms
SET · 200 clients, pipeline 16 · Ruvio 2 shards
1.67×
3.1 ms
SET · 200 clients, pipeline 16 · Ruvio 4 shards
1.66×
1.3 ms
GET · 200 clients, pipeline 16 · Ruvio 2 shards
1.17×
2.7 ms

fsync on every write (always)

SET · 50 clients
2.67×
3.3 ms
SET · 200 clients
1.50×
5.4 ms
SET · 50 clients, pipeline 16
2.33×
5.4 ms
SET · 200 clients, pipeline 16 · Ruvio 2 shards
1.00×
15.2 ms

Source: benchmark/records/x86-azure-2026-10-11.json · AMD EPYC 7763, 8 vCPU (Azure VM) · 2026-10-11, commit 5520164 · server and load generator share the VM, so compare the two servers with each other, not with other hosts. Un-pipelined rows are limited by the load generator.

Whole machine

8 shards against a Redis Cluster of 8 and a single Redis

One redis-benchmark per shard, pinned to its own core, sends each command to that shard's port with the keys inside a hash tag the shard owns, so nothing crosses shards. The same load goes to each node of a Redis Cluster on the same 8 cores, and to one Redis process on one core. Rates are summed over the shards.

In-memory, pipeline 161.13×geometric mean against the cluster over 59 commands; 56 of 60 at 0.97× or faster; per core 1.09× of one Redis
In-memory, pipeline 641.23×geometric mean against the cluster over 59 commands; 56 of 60 at 0.97× or faster; per core 1.17× of one Redis
everysec against Redis AOF everysec1.14×geometric mean against the cluster over 59 commands; 55 of 60 at 0.97× or faster; per core 1.10× of one Redis
Memory0.96×per shard against one Redis over 12 data shapes (0.94× against the cluster's total)
Command
500K1.00M2.00M5.00M10.00M
vs cluster
GET
0.96×
SET
1.09×
DEL (missing key)
0.96×
SETEX
1.40×
HSET (existing field)
1.14×
HGET
1.05×
LPUSH
1.02×
ZADD (existing member, same score)
1.16×
EXPIRE (key with TTL)
1.24×
PUBLISH (no subscribers)
1.36×
Ruvio, 8 shards, one processRedis Cluster, 8 nodes, same coresone Redis process, one core
CommandRuvio 8 shardsRedis Cluster 8One Redisvs clusterper core vs one Redis
DUMP (64 B string)6.97M2.92M372K2.39×2.34×
LINSERT (pivot missing, scans 100)7.05M4.67M593K1.51×1.49×
HGET (10-field hash)4.81M3.24M538K1.48×1.12×
LREM (value missing, scans 100)7.04M4.77M607K1.48×1.45×
COPY ... REPLACE (64 B string)9.20M6.31M877K1.46×1.31×
GEOSEARCH (radius 50 km, COUNT 10)151K105K13K1.44×1.44×
SETEX8.89M6.33M840K1.40×1.32×
HSET (10-field hash, existing field)4.32M3.14M500K1.37×1.08×
GEOADD8.14M5.96M772K1.37×1.32×
MSET (3 keys)8.14M5.97M787K1.36×1.29×
PUBLISH (no subscribers)2.98M2.19M630K1.36×0.59×
HDEL (10-field hash, missing field)4.35M3.28M549K1.33×0.99×
LMOVE (rotate a 100-element list)8.54M6.53M843K1.31×1.27×
LPOS (100 elements, hit in the middle)6.56M5.17M661K1.27×1.24×
HGETALL (10-field hash)3.12M2.48M314K1.26×1.24×
GETEX (set a 100 s deadline)8.91M7.14M952K1.25×1.17×
INCRBYFLOAT5.72M4.62M613K1.24×1.17×
EXPIRE (key with TTL)9.13M7.38M977K1.24×1.17×
ZADD (existing member, same score)9.07M7.82M1.04M1.16×1.09×
BITFIELD INCRBY u8 (always writes)8.26M7.20M958K1.15×1.08×
HSET (existing field)9.13M8.00M1.05M1.14×1.08×
LINDEX (20-item list)8.30M7.47M568K1.11×1.83×
LSET (20-item list)9.05M8.16M1.07M1.11×1.06×
MGET (3 keys)7.74M7.00M943K1.11×1.03×
BITFIELD GET u88.76M7.99M1.06M1.10×1.03×
SET8.78M8.06M1.07M1.09×1.02×
RENAME (same key)9.19M8.59M1.17M1.07×0.98×
SETRANGE9.20M8.60M1.14M1.07×1.01×
ZSCORE9.14M8.56M1.12M1.07×1.02×
SETBIT (1 KiB bitmap, same bit)9.29M8.76M1.16M1.06×1.00×
SADD (existing member)9.32M8.85M1.17M1.05×0.99×
HSTRLEN9.19M8.74M1.15M1.05×1.00×
SRANDMEMBER9.24M8.80M1.17M1.05×0.99×
HGET9.10M8.68M1.15M1.05×0.99×
HMGET (2 fields)8.31M7.95M1.03M1.05×1.00×
PFADD9.11M8.72M1.15M1.04×0.99×
GETRANGE9.07M8.69M1.15M1.04×0.99×
LSET (100 elements)7.84M7.54M968K1.04×1.01×
SISMEMBER9.19M8.90M1.19M1.03×0.97×
MEMORY USAGE9.28M9.00M1.19M1.03×0.97×
PFCOUNT9.29M9.02M1.17M1.03×1.00×
OBJECT ENCODING9.16M8.94M1.20M1.03×0.95×
LPUSH8.28M8.07M1.06M1.02×0.98×
GETBIT (1 KiB bitmap)9.29M9.14M1.17M1.02×1.00×
PERSIST (key without TTL)9.24M9.13M1.18M1.01×0.98×
BITCOUNT (1 KiB bitmap)8.99M8.89M1.18M1.01×0.95×
APPEND (1 byte)8.70M8.71M1.15M1.00×0.95×
ZINCRBY5.99M6.00M783K1.00×0.96×
TOUCH9.34M9.37M1.16M1.00×1.00×
TTL9.25M9.29M1.21M0.99×0.96×
LLEN9.25M9.32M1.18M0.99×0.98×
EXISTS9.25M9.32M1.17M0.99×0.99×
PTTL9.20M9.28M1.18M0.99×0.97×
TYPE9.03M9.16M1.16M0.99×0.97×
EXPIRETIME9.23M9.39M1.16M0.98×0.99×
LRANGE 0 27.89M8.02M1.03M0.98×0.95×
GET8.68M9.02M1.13M0.96×0.96×
DEL (missing key)8.89M9.31M1.18M0.96×0.94×
LRANGE 0 9 (20-item list)5.56M5.82M407K0.96×1.71×
FILLGET (value present)8.49M9.29M1.15M0.91×0.92×
Data shape (8 copies on the 8-shard systems)Ruvio 8 shardsRedis Cluster 8One Redis, one copyper shard vs one Redis
20,000 lists of 20 elements46.6 MiB42.3 MiB5.2 MiB1.13×
5,000 HyperLogLogs of 100 elements15.9 MiB14.3 MiB2.0 MiB1.01×
20,000 bitmaps of 128 B (SETBIT)31.4 MiB27.4 MiB3.4 MiB1.14×
100,000 BITFIELD counters (u16)27.6 MiB41.6 MiB5.1 MiB0.67×
100,000 geo points in one key47.8 MiB47.7 MiB5.7 MiB1.04×
100,000 strings of 16 B45.0 MiB54.0 MiB6.7 MiB0.84×
100,000 strings of 128 B139.3 MiB157.6 MiB19.6 MiB0.89×
100,000 strings of 16 B with TTL79.2 MiB77.6 MiB9.9 MiB1.00×
100,000 one-element lists42.2 MiB53.4 MiB6.7 MiB0.79×
50,000 small hashes (3 fields)27.1 MiB28.3 MiB3.2 MiB1.07×
50,000 small sets (4 members)24.6 MiB25.3 MiB3.0 MiB1.01×
50,000 small sorted sets (3 members)23.7 MiB24.6 MiB2.8 MiB1.07×

Sources: benchmark/records/x86-azure-2026-10-16-8-shards-final.json · benchmark/records/x86-azure-2026-10-16-8-shards-p64-after.json · benchmark/records/x86-azure-2026-10-16-8-shards-everysec-after.json · Azure F16as_v6, AMD EPYC 9V74 (virtualized), 16 cores without SMT; servers on cpus 8-15, load generators on cpus 0-7, loopback · 2026-10-16, Ruvio per-shard forwarding branch at 7376885: lean dispatch in per-shard mode, non-blocking PUBLISH, cycle-counter SLOWLOG timing, six more commands in the WAL group, no record for a no-op SADD · the record with the one-shard control run and the profiles is in the docs.

Every row

Full results

Median requests per second over the rounds, Ruvio and Redis side by side. The whisker spans the worst and best pairing of rounds, so a wide whisker means a noisy row.

CommandRuvio ops/sRedis ops/s
0.5×1×2.5×
Ratio
GEOSEARCH (radius 50 km, COUNT 10)44K18K
2.48×
SETEX2.50M1.25M
2.00×
MSET (3 keys)2.20M1.10M
2.00×
GEOADD1.94M1.11M
1.74×
GETEX (set a 100 s deadline)2.37M1.38M
1.71×
LINSERT (pivot missing, scans 100)1.29M841K
1.53×
COPY ... REPLACE (64 B string)2.09M1.38M
1.51×
LMOVE (rotate a 100-element list)2.05M1.36M
1.50×
SET2.81M1.88M
1.50×
LREM (value missing, scans 100)1.30M874K
1.49×
LPOS (100 elements, hit in the middle)1.58M1.07M
1.47×
ZADD (existing member, same score)2.14M1.53M
1.40×
SETBIT (1 KiB bitmap, same bit)2.57M1.84M
1.40×
GETRANGE2.57M1.88M
1.37×
BITFIELD GET u82.20M1.61M
1.37×
HSET (existing field)2.50M1.84M
1.36×
EXPIRE (key with TTL)2.31M1.70M
1.36×
BITFIELD INCRBY u8 (always writes)1.88M1.38M
1.35×
HGET2.57M1.91M
1.34×
HGET (10-field hash)2.31M1.73M
1.33×
LSET (20-item list)2.20M1.67M
1.32×
OBJECT ENCODING2.73M2.09M
1.30×
HSET (10-field hash, existing field)1.91M1.48M
1.30×
HSTRLEN2.50M1.96M
1.28×
RENAME (same key)2.50M1.96M
1.28×
SETRANGE2.43M1.91M
1.27×
ZSCORE2.25M1.80M
1.25×
DUMP (64 B string)1.96M1.61M
1.22×
SRANDMEMBER2.43M2.00M
1.22×
MGET (3 keys)1.84M1.53M
1.20×
HMGET (2 fields)2.00M1.67M
1.20×
PFADD2.43M2.05M
1.19×
LPUSH2.09M1.76M
1.19×
HDEL (10-field hash, missing field)1.96M1.67M
1.17×
PERSIST (key without TTL)2.50M2.14M
1.17×
MEMORY USAGE2.43M2.09M
1.16×
APPEND (1 byte)2.43M2.09M
1.16×
LSET (100 elements)1.88M1.64M
1.15×
PUBLISH (no subscribers)2.57M2.25M
1.14×
ZINCRBY1.58M1.38M
1.14×
EXISTS2.50M2.20M
1.14×
SADD (existing member)2.37M2.09M
1.13×
LRANGE 0 21.88M1.67M
1.13×
INCRBYFLOAT1.34M1.20M
1.12×
LINDEX (20-item list)2.14M1.91M
1.12×
SISMEMBER2.50M2.25M
1.11×
TTL2.37M2.14M
1.11×
GETBIT (1 KiB bitmap)2.25M2.09M
1.08×
EXPIRETIME2.50M2.37M
1.06×
PFCOUNT2.43M2.31M
1.05×
DEL (missing key)2.37M2.25M
1.05×
PTTL2.25M2.14M
1.05×
TYPE2.37M2.31M
1.03×
LLEN2.31M2.31M
1.00×
LRANGE 0 9 (20-item list)1.18M1.18M
1.00×
GET2.14M2.20M
0.98×
BITCOUNT (1 KiB bitmap)2.25M2.31M
0.98×
HGETALL (10-field hash)763K789K
0.97×
TOUCH2.31M2.50M
0.92×
FILLGET (value present)1.96M2.31M
0.85×

Source: benchmark/records/mac-2026-10-14.json · 2026-10-14, commit eb1281c

Memory

Memory added per data shape

Resident memory after loading minus resident memory at idle, for each server. Left is less, on a log axis.

RuvioRedis
Data shape
2 MiB51020
Saved
100,000 BITFIELD counters (u16)
−51%
100,000 one-element lists
−44%
100,000 strings of 16 B
−42%
50,000 small sets (4 members)
−40%
50,000 small sorted sets (3 members)
−39%
50,000 small hashes (3 fields)
−30%
100,000 geo points in one key
−21%
5,000 HyperLogLogs of 100 elements
−18%
20,000 bitmaps of 128 B (SETBIT)
−16%
100,000 strings of 128 B
−16%
100,000 strings of 16 B with TTL
−12%
20,000 lists of 20 elements
−8%

12 of 12 shapes below Redis · total 67.6 MiB against 91.6 MiB · benchmark/records/mac-2026-10-14.json

Method

How the numbers are made

Apple M4 Pro
Machine
Apple M4 Pro, 12 cores, 24 GiB, macOS 26.6.2 arm64
Redis
8.10.2
Load
50 clients, pipeline 16, 3 alternating rounds, median
Ruvio
memory profile, 1 shard, release build, commit eb1281c
Pinning
none
AMD EPYC, 2 vCPU
Machine
AMD EPYC 9354P 32-Core Processor (KVM guest), 2 vCPU, Linux 6.8.0-146-generic x86_64
Redis
8.10.2
Load
50 clients, pipeline 16, 3 alternating rounds, median
Ruvio
memory profile, 1 shard, release build, commit eb1281c
Pinning
server cpu 0, client cpu 1

The whole-machine grids come from scripts/shard_compare.py: 8 shards in one Ruvio process (port_mode = "per-shard"), a Redis Cluster of 8 masters created with redis-cli --cluster create, and one Redis process, each driven by one redis-benchmark per shard with hash-tagged keys. The 8-shard systems hold 8 copies of each data shape, so a shard holds what the single process holds.

The single-machine rows come from scripts/redis_compare_features.py, which runs redis-benchmark against each server in turn. Absolute numbers describe one host; the ratio between the two servers is the result. Shared cloud machines vary from run to run, so a row within a few percent of 1× is a tie.

Benchmarking guide All records