Benchmarking Methodology
How VeltrixDB's benchmark numbers are produced: the harness, the hardware, the pass/fail gates, and the raw results — so you can reproduce them or run the same harness against your own workload shape.
The harness
scripts/bench.sh runs a 6-phase sequenced workload and reports go/no-go on two hard gates: packing density and GC emergency runs. The project re-runs it after any storage engine change.
# macOS / Linux dev (uses /tmp, 1M keys)
./scripts/bench.sh
# Linux production-class (n2-highmem-64, 8 NVMe disks)
DATA_DIRS=/mnt/nvme0,...,/mnt/nvme7 \
RAW_VLOGS=/dev/nvme0n1,...,/dev/nvme7n1 \
CACHE_MB=409600 NUM_KEYS=10000000 \
CONCURRENCY=512 BULK_DUR=120 STRESS_DUR=300 \
./scripts/bench.sh
Key environment variables
| Var | Default | Notes |
|---|---|---|
VALUE_SIZE | 128 | Match your real value distribution |
NUM_KEYS | 1,000,000 | Use 10M for production-scale runs |
BATCH_SIZE | 1024 | Higher = better packing density |
CONCURRENCY | 64 | Use 512 on multi-core hosts |
BULK_DUR | 30 s | 120–300 s for production verification |
STRESS_DUR | 60 s | 600 s to detect GC pressure |
WAL_WINDOW_MS | 5 | 10 for default, 2 for low latency |
CACHE_MB | 1024 | 409600 on n2-highmem-64 |
RAW_VLOGS | — | Raw block-device VLog (Linux + CAP_SYS_RAWIO) |
Pass criteria
The harness enforces two hard gates. A benchmark run that fails either gate is not representative of the storage engine operating correctly.
| Gate | Condition | What failure means |
|---|---|---|
| Density | bytes/record ≤ 1.2 × (24 + value_size) | Packing not engaged — use --batch-size > 1 |
| GC emergency | vlog_gc_emergency_runs delta == 0 | Write rate exceeds GC throughput |
Reference numbers (BENCHMARKING.md)
macOS M-series (dev)
| Metric | Value |
|---|---|
| MPut throughput (1024 batch) | ~360K writes/s |
| Bytes/record at 128 B | ~160 B (25× density) |
| Single-Put P99 (5 ms window) | ~8 ms |
Linux n2-highmem-64 (8 NVMe) — projected
| Metric | Value |
|---|---|
| MPut throughput (1024 batch) | ~3M writes/s |
| Single-Put P99 (5 ms window) | ~5.2 ms |
| GET P99 cache-hit | ~52 µs |
| 1B keys × 128B disk total | ~149 GB (vs 4 TB unpacked) |
3-node GKE cluster benchmark
Reported in the README as the headline cluster numbers: 3-node GKE cluster · n2-highmem-64 · 8×375 GB NVMe per node · 1 billion keys · 80R/20W · 30 minutes sustained.
| Metric | Value |
|---|---|
| Reads/s (internal GKE run — unverified) | 7,200,000 |
| Writes/s (internal GKE run — unverified) | 1,800,000 |
| P50 (80R/20W blended) | ~220 ns |
| P99 (80R/20W blended) | ~510 µs |
| GC emergency events | 0 |
| Errors | 0 |
| Storage density | ~160 GB for 1B × 128 B values |
Verified vs unverified: the measured, reproducible numbers are the YCSB single-node results (427,697 reads/s · 18,064 durable writes/s · AWS EC2, 4×NVMe, 100M keys). The 3-node GKE figures (7.2M reads/s / 1.8M writes/s) come from an internal run without a published harness — treat them as unverified until reproduced.
Single node (Linux NVMe)
| Operation | P50 | P99 |
|---|---|---|
| GET — cache hit | 0.05 ms | 0.28 ms (~1.4M reads/s) |
| PUT — 10 ms flush window | 5 ms | 10.2 ms |
| PUT — 5 ms window, 512 workers | 2.6 ms | 5.2 ms (~102K writes/s) |
| MultiPut 1024 entries | — | ~9.5 ms (~426K entries/s) |
YCSB benchmark results (100M keys)
Published in BENCHMARK_RESULTS.md, dated June 9, 2026. Test environment: AWS EC2 high-memory instance, 495 GB total RAM (488 GB available), 4× NVMe SSD at 873 GB each (3.5 TB total), raw block-device VLog (/dev/nvmeXn1p2), 400 GB LIRS cache, 200 client threads, 100,000,000 keys, ~100-byte values, benchmark tool YCSB 0.17.0.
Write benchmark (100M key load)
Configuration: 5 ms WAL flush window, 5 ms VLog flush window, 200 threads, 4× NVMe striped.
| Metric | Value |
|---|---|
| Total keys written | 100,000,000 |
| Throughput | 18,064 ops/sec |
| Total runtime | 92.3 minutes |
| Avg write latency | 11.06 ms |
| Min latency | 413 µs |
| P95 latency | 30.8 ms |
| P99 latency | 47.3 ms |
| Failures | 0 (100% success) |
| Durability | WAL + fdatasync on every write |
Read benchmark (10M reads on 100M key dataset)
Configuration: 400 GB cache (entire dataset fits in RAM), 200 threads, 10,000,000 operations, 100% reads (YCSB workload_c).
| Metric | Value |
|---|---|
| Throughput | 427,697 ops/sec |
| Total runtime | 23.4 seconds for 10M reads |
| Avg read latency | 461 µs |
| Min latency | 10 µs |
| P95 latency | 2,069 µs |
| P99 latency | 2,771 µs |
| Max latency | 53.6 ms |
| Hit rate | 100% (0 NOT_FOUND) |
Progression across runs
BENCHMARK_RESULTS.md tracks how throughput and hit rate changed as the dataset and tuning scaled up:
| Run | Write speed | Read speed | Read hit rate |
|---|---|---|---|
| 1M keys · 50 threads · 10ms WAL | 2,036 ops/sec | 4,000 ops/sec | 48.5% |
| 10M keys · 50 threads · 10ms WAL | 3,164 ops/sec | 301,386 ops/sec | 79% |
| 100M keys · 200 threads · 5ms WAL | 18,064 ops/sec | 427,697 ops/sec | 100% |
VeltrixDB vs. Redis, head to head
From the same YCSB run, compared against publicly documented Redis behavior at equivalent durability settings.
| Mode | VeltrixDB | Redis |
|---|---|---|
| Durable writes (fsync every write) | 18,064 ops/sec | 10,000–30,000 ops/sec |
| Non-durable writes (no fsync) | N/A — always durable | 100,000–200,000 ops/sec |
VeltrixDB always writes durably. Redis requires appendfsync always for an equivalent guarantee, which reduces Redis to 10K–30K ops/sec — comparable to or slower than VeltrixDB at that durability level.
| Resource | VeltrixDB (100M keys) | Redis (100M keys) |
|---|---|---|
| RAM required | 15 GB (400 GB provisioned as cache) | 30–45 GB (data lives in RAM) |
| Disk required | ~25 GB per NVMe | Swap/RDB snapshots only |
| Max dataset size | 3.5 TB (NVMe) | Limited by RAM |
| Dataset > RAM | Works (reads from NVMe) | Evicts or crashes |
Key takeaways
- Writes: 18,064 durable writes/sec across 4 NVMe disks, zero failures across 100M operations — comparable to Redis with
appendfsync always. - Reads: 427,697 reads/sec at 461 µs average latency, 2–4× faster than a single Redis instance without pipelining, while data lives on NVMe rather than RAM.
- Scalability: 100M keys used only ~25 GB per disk out of 873 GB available; the same machine can hold 1 billion+ keys with no RAM constraint, where Redis would need 300–450 GB RAM for an equivalent dataset.
- Durability: every write is crash-safe (WAL +
fdatasync). Redis needs special configuration for the same guarantee and pays a similar performance cost when enabled. - Read hit rate: 100% with proper dataset sizing (
recordcountmatchingoperationcount), zeroNOT_FOUNDacross 10 million reads.
scripts/bench.sh and YCSB 0.17.0 runs against VeltrixDB v1.0, dated June 2026. Re-run the harness against your own key/value shape rather than assuming these numbers transfer directly — see VeltrixDB vs. Redis for how to interpret the results relative to your workload.