Redis Stack's vector search sits behind the same core Redis has always had: mostly single-threaded, with I/O threading bolted on top. On a modern cloud box with dozens of cores, that means one core does the work while the rest sit idle, no matter how many concurrent clients are hammering the index.
We build KiviDB, a Redis-compatible in-memory database written in Rust, on a shard-per-core architecture instead. I wanted to see what that buys you in practice, so we reran our HNSW vector search benchmarks against Redis Stack under real concurrency, across the full recall curve, not just one cherry-picked operating point.
Setup
-
Hardware: AWS Graviton,
c7gn.12xlarge- a dedicated server instance plus a separate client instance in the same placement group. - Dataset: glove-25-angular, 1,183,514 vectors, cosine distance.
- Index: HNSW, M=16.
- Versions: KiviDB v1.0.3 vs. Redis Stack 7.4.7.
-
Harness: the
vector-db-benchmarkfork we maintain, itself based on Qdrant's original tooling. - Load: 100 concurrent clients, best of 3 repetitions. ## Precision vs. throughput, across every tier
Most vector database comparisons quote one QPS number at one precision target, which tells you almost nothing about how the system behaves outside that exact point. So here's the full sweep, from the high-throughput end to max recall:
| Tier | KiviDB precision | KiviDB QPS | KiviDB p50 | KiviDB p99 | Redis Stack precision | Redis Stack QPS | Redis Stack p50 | Redis Stack p99 |
|---|---|---|---|---|---|---|---|---|
| High throughput | 0.942 | 42,360 | 1.91ms | 4.52ms | 0.912 | 2,508 | 30.40ms | 59.68ms |
| Mid recall | 0.961 | 36,023 | 2.38ms | 4.92ms | 0.937 | 2,265 | 34.12ms | 67.25ms |
| High recall | 0.989 | 23,409 | 3.82ms | 7.66ms | 0.979 | 1,563 | 49.84ms | 98.67ms |
| Max recall | 0.998 | 13,229 | 6.56ms | 14.91ms | 0.995 | 988 | 80.27ms | 159.44ms |
A few things stand out here beyond the headline multiplier:
- KiviDB wins on precision at every tier too, not just throughput. At the "high throughput" tier, KiviDB is running at 0.942 precision while Redis Stack is at 0.912, so the QPS gap isn't a recall-for-speed trade.
- Even at KiviDB's max recall setting (0.998), it still out-throughputs Redis Stack's best result anywhere on the curve, 13,229 QPS at 0.998 precision vs. Redis Stack's peak of 2,508 QPS at 0.912. That's the whole curve, not one point.
- Latency scales far more gently for KiviDB. Going from the fastest tier to max recall, KiviDB's p50 grows about 3.4x (1.91ms → 6.56ms). Redis Stack's p50 grows about 2.6x over the same range (30.40ms → 80.27ms), but it's starting from a p50 that's already 16x higher than KiviDB's at the fast end. Summed up: at 100 concurrent clients, EF 64, KiviDB serves up to 16.9x the search QPS of Redis Stack, with higher recall at every EF tier in the sweep.
Ingest: no background phase
This is the part that doesn't show up in a QPS table but matters just as much operationally. Redis Stack builds its HNSW index asynchronously, the upload finishes, and then there's a separate indexing phase before the data is actually searchable. KiviDB indexes synchronously: when a write returns, that vector is already in the graph.
For the full 1.18M-vector dataset on the same uncontended hardware:
| KiviDB | Redis Stack | |
|---|---|---|
| Upload throughput | 5,262 vec/s | 2,606 vec/s |
| Time-to-queryable | 225s (synchronous) | 455s + ~8s index wait |
That's 2.0x faster wall-clock ingest, and the difference compounds if your workload ingests continuously rather than loading once and querying forever, there's no separate "wait for the index to catch up" step to reason about.
Write latency, and how it compares beyond Redis Stack
Vector search aside, here's how the core write/read path compares against Redis 8.4 and Dragonfly, using memtier_benchmark on the same hardware and flags:
| KiviDB | Dragonfly | Redis 8.4 | |
|---|---|---|---|
| Write avg / p99 | 0.17ms / 0.35ms | 0.52ms / 3.71ms | 4.93ms / 20.22ms |
| Read avg / p99 | 0.16ms / 0.32ms | 0.36ms / 0.74ms | 2.72ms / 4.70ms |
| Mixed 1:1 avg / p99 | 0.17ms / 0.34ms | 0.37ms / 0.79ms | 3.27ms / 5.59ms |
Why the gap is this large
Redis Stack's vector index inherits Redis's execution model, so query fan-out across concurrent clients is bottlenecked by however much of one core is left over. KiviDB shards the keyspace, including vector indexes, across cores, so 100 concurrent clients aren't queuing behind the same execution thread, they're spread across shards that run genuinely in parallel.
The trade-off is complexity we had to solve as builders, not something you have to think about as a user: cross-shard query coordination, consistent hashing for shard assignment, and making sure HNSW graph updates stay correct under concurrent writes landing on different shards. Happy to go deeper on the shard-coordination internals in a follow-up if there's interest.
Worth being upfront about what this benchmark doesn't tell you: it's a single dataset (glove-25-angular, 25 dimensions) at one vector count. If your workload is higher-dimensional or much larger, run it yourself before trusting these numbers for capacity planning.
Try it
Same Redis protocol on the vector search commands, so if you've already got Redis client code, it mostly just works:
docker run -p 6379:6379 quay.io/kividbio/kividb:latest
Full benchmark report and reproduction steps: kividb.io/vector-database. Command reference and docs at kividb.io/docs. If you run this on your own hardware and get different numbers, I'd genuinely like to hear about it.

Top comments (0)