Skip to main content
Swytch Documentation
Toggle Dark/Light/Auto mode Toggle Dark/Light/Auto mode Toggle Dark/Light/Auto mode Back to homepage

Benchmarks

The short version: on production traces with values above a few hundred bytes, Swytch beats Redis Cluster on throughput and tail latency at matched topology and matched durability settings, while moving one to four orders of magnitude less data over the network. On traces with tiny values (under ~200 bytes), Redis wins on raw speed: its per-key overhead is smaller than ours, and at that value size per-key overhead dominates total cost. The shape of your data decides which regime you’re in. Both are shown below.

Every number below comes from trace-bench, an internal harness (not yet open source) that replays real production traces against Redis and Swytch in turn, on identical hardware, with identical operations in identical order. Runs marked verified execute with --verify: every read is checked against the last acknowledged write, and any wrong answer is counted. Traces are real production captures from the CMU PDL twemcache workload dataset.


What we measure

Beyond the usual throughput/latency/hit-rate numbers, the harness tracks two counters most benchmarks don’t:

  • Invalid: a read returned a wrong value; something other than the last acknowledged write (or a legal concurrent write). This is a consistency violation.
  • Vanished: a key was written, acknowledged, and later read back as a miss while the cache was under its memory budget. The data was silently dropped. This is a durability violation.

Both are zero for both systems on every run below: neither system dropped or corrupted data in these benchmarks. Behavior under failure injection (node kills, crash recovery) will be published separately.


The traces

trace-bench --calculate profiles a trace before running it. These four span the space:

TraceSourceValue p50Unique keysWrite ratioPerfect hit rateLive data50% of traffic from
alibabaBlock_277Alibaba block I/O16 KB17.6k0.5%99.5%402 MB1.9% of keys
cluster17Twitter646 B75.4k2.3%97.7%31.8 MB0.14% of keys
cluster44Twitter46 B1.65M2.7%97.4%65.3 MB0.08% of keys
w01CloudPhysics4 KB686k77%23.1%5.34 GB35% of keys

“Perfect hit rate” is the ceiling any cache can reach on the trace: the fraction of reads whose key was ever written. Misses beyond that are requests for keys that don’t exist; no cache of any size can serve them. When both systems sit at this ceiling, neither is losing data.


Head-to-head: 4-node Swytch (sharded, cloud-backed) vs 4-node Redis Cluster (AOF always)

The closest to a like-for-like comparison we can construct: both systems sharded across 4 nodes, both persistent (Swytch Cloud enabled; Redis appendfsync always), same trace, same 100-way concurrency, verified. ~650 million operations over a 7-day cluster17 replay.

Chart

Redis ClusterSwytch
Operations649.5M649.5M
Hit rate99.89%99.90%
Throughput188,519/s266,198/s (+41%)
GET p50895.9 µs396.7 µs
GET p991.9 ms4.7 ms
SET p50894.1 µs665.9 µs
SET p992.0 ms20.8 ms
Invalid / Vanished0 / 00 / 0
Network total454.2 GB642.3 MB (47× less at peak)
Peak RSS231 MB2.15 GB
Peak CPU390%936%

Swytch is 41% faster in aggregate and 2.3× faster at the median read, at matched topology and durability. The costs are equally real: Swytch’s SET tail is where synchronous replication and the cloud send path show up (p99 20.8 ms vs 2.0 ms), and it spends more CPU and RAM doing causal-consistency work Redis doesn’t do. The 47× network difference is architectural: Swytch replicates ~100-byte effect metadata, not values.

On Redis memory: the RSS above is what Redis used, not what it needs provisioned. AOF persistence rewrites via fork(), which under write load can double resident memory (copy-on-write touches every modified page). You must reserve roughly 2× Redis’s working RSS or persistence fails (see the w01 section below for what happens when it can’t). Swytch persists by streaming an append-only effect log; there is no fork and no 2× reservation.


Full-trace endurance runs

Same 4-node sharded + cloud configuration, full traces end-to-end, no failure injection, verified.

cluster17 (Twitter, 646 B values): 8 sim-days

Chart

RedisSwytch
Throughput (steady state)165k/s256k/s (+55%)
GET p50841 µs377 µs
Hit rate99.89%99.90%
Invalid / Vanished0 / 00 / 0
Network (sustained)~980 Mbps~0

alibabaBlock_277 (16 KB values): 14 sim-days

Chart

RedisSwytch
Throughput (steady state)152k/s203k/s (+34%)
GET p501,525 µs720 µs
Hit rate99.926%99.925%
Invalid / Vanished0 / 00 / 0
Network (sustained)~25 Gbps~0

Note the network line. Serving 16 KB values at 150k ops/s pushes 25 Gbps out of Redis, sustained, for two simulated weeks. If those bytes cross an availability-zone boundary, they’re a line item on your cloud bill. Swytch’s line is flat zero: values never cross the wire.

cluster44 (Twitter, 46 B values), 7 sim-days: Redis wins this one

Chart

RedisSwytch
Throughput211k/s173k/s (−18%)
GET p50688 µs578 µs
Hit rate98.43%98.66%
Invalid / Vanished0 / 00 / 0
Total RSS (4 nodes)0.73 GB18.9 GB

At 46-byte values, Swytch’s per-key structures (causal DAG, key index, effect headers) are larger than the values they manage, and Redis’s minimal per-key overhead wins. This workload favors Redis’s design and the results reflect that. If your values are this small and this cheap to regenerate, a durable cache is likely the wrong tool entirely; the source of truth can answer faster than any cloud tier can. Swytch earns its overhead when the data is expensive to lose, expensive to fetch, or expensive to get wrong.


Cost at equal work: throttled to 100k ops/s

Saturation benchmarks measure ceilings. Nobody runs production at their ceiling. These runs pin both systems to an identical 100,000 ops/s and measure what each costs to deliver the same work: the number that actually matters for capacity planning.

cluster17 @ 100k ops/s

Chart

RedisSwytch
GET p5035.3 µs51.1 µs
GET p95521.8 µs193.9 µs
GET p991.07 ms24.1 ms
SET p5044.1 µs94.2 µs
SET p991.05 ms679.5 µs
Peak CPU164%648%
Peak RSS124 MB606 MB

alibabaBlock_277 @ 100k ops/s

Chart

RedisSwytch
GET p5042.5 µs58.0 µs
GET p95313.6 µs198.7 µs
GET p991.32 ms1.10 ms
SET p952.21 ms1.28 ms
Network (sustained)15.9 Gbps0
Peak CPU215%448%

cluster44 @ 100k ops/s: Redis wins again

Chart

RedisSwytch
GET p5033.4 µs76.3 µs
GET p9555.3 µs23.5 ms
GETs under 100 µs99.2%62.0%
Peak CPU178%908%

The pattern across all three: at matched load, the median-latency gap nearly closes (35 vs 51 µs on cluster17; both are “fast”), Swytch wins the p95 mid-tail on medium and large values, and Swytch’s p99+ carries a cloud-fetch tail on the small fraction of reads that reconstruct from the durable tier. The bill is CPU: roughly 2–5× Redis’s, scaling inversely with value size. On an application server with idle cores, that’s capacity you already own. On tiny values, it’s the reason to use Redis instead.

Swytch’s latency distribution is bimodal by design: a read is either resident (memory-speed) or it reconstructs from cloud (bounded, ~10–25 ms). There is no smeared middle. Writes are the opposite story: Swytch appends an immutable effect and wins SET tails even while synchronously replicating, because there is no read-modify-write and no fsync stall on the write path. It’s a write-optimized store that happens to read at cache speed when the working set is resident.


w01: write-heavy stress test

CloudPhysics w01 is 77% writes, 686k unique keys, and 5.34 GB of live data: the most write-intensive trace in the set.

With appendfsync always, Redis did not complete the run. Under sustained write load, the AOF rewrite fork() needed to double Redis’s resident memory; the box didn’t have it; Redis crashed, restarted, and came back missing data: 39 acknowledged writes were gone (verified), 1.5M client errors during the outage, and a cold cache afterward. The persistence mechanism caused the failure it exists to prevent. To an uptime monitor this appears as a brief restart. The verifier recorded it as silent data loss.

With appendfsync everysec (and 1 Redis node vs 2 Swytch nodes at the same per-node RAM, because Redis Cluster refuses to form with fewer than 3 masters):

Chart

Redis (1 node, everysec)Swytch (2 nodes, cloud)
Hit rate23.60%23.71% (trace ceiling: 23.73%)
Invalid / Vanished0 / 00 / 0
SET p991.53 ms1.10 ms
SET p99.946.4 ms31.7 ms
GET p5051 µs25.2 ms
Peak RSS11.57 GB8.44 GB

Two results stand out. First, Redis used more memory than Swytch; the one workload where memory pressure actually bites inverts the usual RSS comparison, before even counting the 2× fork reservation. Second, both systems sit exactly at the trace’s computed hit ceiling: every miss is a request for a key that was never written. Swytch’s 25 ms GET p50 is the cost of an undersized cache serving most reads from the durable tier. Size the cache to the working set and those reads return to microseconds. That’s the knob: perfect hit rate, paid for in tail latency, at whatever RAM budget you choose.


Methodology

ServerHetzner dedicated, 64 GB RAM, 6 CPUs for the system under test
Topology4-node Swytch sharded + Swytch Cloud vs 4-node Redis Cluster, unless noted
PersistenceSwytch Cloud (durable tier) vs Redis AOF (always unless noted)
Concurrency100 workers
ReplaySequential mode: each system sees identical operations in identical order
Verification--verify: every read checked against last acknowledged write; invalid and vanished counted
ChartsPer-second samples, resampled onto uniform sim-time bins (median per bin; max per bin for spike series), final partial second dropped

Sequential replay is the control that makes cross-system comparison fair, with one known artifact: a slow request briefly gates the trace behind it, so saturation throughput on cloud-heavy runs understates what a concurrent production workload would see. The throttled runs do not have this artifact: both systems comfortably deliver the pinned rate, so the measured latency and CPU reflect service cost rather than queueing.


Running your own benchmarks

The internal trace-bench harness isn’t open source yet, but Swytch ships with built-in micro-benchmarks and speaks the standard tooling.

Trace profiling

Everything in “The traces” table above comes from the calculator. When trace-bench is released you’ll be able to profile your own captures the same way:

./trace-bench --trace your-trace.zst --calculate

It reports value-size distribution, unique keys, write ratio, the perfect-hit-rate ceiling, live data size (what you’d be billed for on Swytch Cloud), key hotness, and peak write rate: enough to predict which regime you’re in before running anything.

Cache engine

go test -bench=. -benchmem ./cache/
BenchmarkDescription
BenchmarkCloxCacheGetParallel GET on 10k keys
BenchmarkCloxCachePutParallel PUT operations
BenchmarkCloxCacheMixed80% read / 20% write, reports hit rate and evictions
BenchmarkCloxCacheZipfZipf distribution (theta=0.99), realistic hotspots
BenchmarkCloxCacheContentionHigh contention on 100 hot keys
BenchmarkCloxCacheSizesSmall → XLarge cache scaling
BenchmarkCloxCachePointersPointer-type values

Each has a sync.Map variant for comparison.

Redis commands

go test -bench=. -benchmem ./redis/

Exercises the full Redis command pipeline: parsing, execution, response writing. Covers SET/GET, INCR, list ops (LPUSH/RPUSH/LPOP/RPOP/LRANGE/LINDEX), hash ops (HSET/HGET/HGETALL/HINCRBY), mixed and parallel workloads, 10 KB values, and LPUSH scaling from 1k to 10M elements.

Effects engine

go test -bench=. -benchmem ./effects/

Benchmarks for the causal effect resolution layer.

redis-benchmark

Swytch is wire-compatible with the standard tool:

redis-benchmark -p 6379 -n 100000 -c 50
redis-benchmark -p 6379 -t set,get -n 1000000 -c 100
redis-benchmark -p 6379 -t set,get -n 1000000 -P 16
redis-benchmark -p 6379 -t set,get -d 256 -r 1000000

Trace datasets

Real production traces used above are available from the CMU PDL twemcache workload dataset.