VeltrixDB Docs
v1.16 GitHub FAQ Quickstart

Benchmarking Methodology

How VeltrixDB's benchmark numbers are produced: the harness, the hardware, the pass/fail gates, and the raw results with the conditions they were measured under — 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 (build + start, MPUT bulk load, cool-down, read-only, mixed 70R/30W, sustained MPUT write stress) 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.

It builds the server and loadtest with CGO_ENABLED=0 (Go map index) unless you export CGO_ENABLED=1. The Docker image is a cgo build (native index), so set CGO_ENABLED=1 on Linux to measure what the image runs.

# 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

VarDefaultNotes
VALUE_SIZE128Match your real value distribution
NUM_KEYS1,000,000Use 10M for production-scale runs
BATCH_SIZE1024Higher = better packing density
CONCURRENCY64Use 512 on multi-core hosts
BULK_DUR30 s120–300 s for production verification
READ_DUR / MIXED_DUR30 sRead-only and mixed phases
STRESS_DUR60 s600 s to detect GC pressure
WAL_WINDOW_MS5Sets both --wal-flush-window-ms and --vlog-flush-window-ms (the server default is 15)
CACHE_MB1024409600 on n2-highmem-64
DATA_DIRS/tmp/veltrixbenchComma-separated list → --data-dirs; only paths under /tmp are wiped first
RAW_VLOGS—Raw block-device VLog (Linux, root + CAP_SYS_RAWIO)
OUT_DIR/tmp/veltrixbench-outBinaries, server.log, run.log
EXTRA_SERVER_FLAGS—Extra server flags, e.g. --disable-ordered-index
CGO_ENABLED0Build mode of the server and loadtest

Pass criteria

The harness enforces two hard gates. A benchmark run that fails either gate is not representative of the storage engine operating correctly.

GateConditionWhat failure means
Densitybytes/record ≤ 1.2 × (24 + value_size) (veltrixdb_vlog_file_bytes / Δveltrixdb_storage_writes_total after the bulk load)Packing not engaged — keep BATCH_SIZE > 1 (loadtest --batch-size)
GC emergencyveltrixdb_vlog_gc_emergency_runs_total delta == 0 during the write stressWrite rate exceeds GC throughput

The script exits non-zero if either gate fails. It also prints the read P99, but that is not a gate.

Reference numbers (BENCHMARKING.md)

Provenance Added at v1.1.0; the Linux table is a projection, not a measurement. Both tables predate the one-write(2) WAL flusher, one pwrite per VLog batch, the binary WAL, the MultiPut cache write-around, the ordered-index overwrite skip and the native index, all of which change write-path numbers. The macOS figures also sit on an fsync that does not flush the drive cache. Re-run before quoting them. The single-Put rows are fixed-window group commit; the default is now adaptive (see durable single-key writes).

macOS M-series (dev)

MetricValue
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

Labeled as projected BENCHMARKING.md marks this table explicitly as "projected" figures for the 8-NVMe production configuration, distinct from the macOS dev numbers above and the measured AWS YCSB results below.
MetricValue
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)

YCSB benchmark results (100M keys)

These are the only reproducible headline numbers. Published in BENCHMARK_RESULTS.md, dated June 9, 2026, on a historical pure-Go build (v1.0; it predates the native index, the binary WAL, the one-write(2) WAL flusher, the ordered-index fix and --net). 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. The YCSB binding used for this run is not in the repository, so it cannot be re-run from it; bench/compare (go-ycsb, below) is the reproducible YCSB path.

Write benchmark (100M key load)

Configuration: 5 ms WAL flush window, 5 ms VLog flush window (the server default is now 15 ms), 200 threads, 4× NVMe striped, every write fdatasync-durable.

MetricValue
Total keys written100,000,000
Throughput18,064 ops/sec
Total runtime92.3 minutes
Avg write latency11.06 ms
Min latency413 µs
P95 latency30.8 ms
P99 latency47.3 ms
Failures0 (100% success)
DurabilityWAL + fdatasync on every write

Read benchmark (10M reads on 100M key dataset)

Configuration: 400 GB cache, 200 threads, 10,000,000 operations, 100% reads (YCSB workload_c). The entire dataset was in cache, so every read was a cache hit — this measures the cache-hit path through the network stack, not NVMe reads.

MetricValue
Throughput427,697 ops/sec
Total runtime23.4 seconds for 10M reads
Avg read latency461 µs
Min latency10 µs
P95 latency2,069 µs
P99 latency2,771 µs
Max latency53.6 ms
Hit rate100% (0 NOT_FOUND)

Progression across runs

BENCHMARK_RESULTS.md tracks how throughput and hit rate changed as the dataset and tuning scaled up:

RunWrite speedRead speedRead hit rate
1M keys · 50 threads · 10ms WAL2,036 ops/sec4,000 ops/sec48.5%
10M keys · 50 threads · 10ms WAL3,164 ops/sec301,386 ops/sec79%
100M keys · 200 threads · 5ms WAL18,064 ops/sec427,697 ops/sec100%

Later measurements New in v1.5–v1.7

Not YCSB and not the YCSB machine; each row states its conditions. These cover the native index and binary WAL (v1.6) and the ordered-index fix and C++ front-end (v1.7).

MeasurementResultConditions
Server batch writes, 8 clients × 1024-key MPUT, 1M-key space3.54M keys/s, P99 4.2 ms (1.45M, 9.6 ms before the ordered-index fix)macOS (fsync does not flush the drive cache)
Batch writes, Go front-end, C++ storage off1.77M keys/s, P99 12.2–12.7 ms4-CPU CI runner, tmpfs, client on same host, 2026-09-25
Reads, same configuration177–182K ops/s, P99 1.8–2.0 mssame
Mixed-workload write P99, 1 ms flush window2.57 mssame
Batch writes, C++ storage layer all on (io_uring bridge + SQPOLL, batch engine, native index)1.12M keys/ssame; per-part attribution pending
C++ network front-end (--net=cpp, opt-in) vs Goread P50 154 vs 286 µs, poll read throughput 194K vs 177K ops/s; read P99 ~3.0 vs 1.8 ms, batch writes ~12% lowersame, measured before disk reads moved off the loop; not faster overall
Native index vs Go map, 5M keysfull GC 21 → 0.27 ms, settled RSS 168 → 142 B/key, ~19 ns more per cache-miss lookupengine benchmark; go test ./storage -run '^$' -bench 'Index_Footprint|Index_Get' -benchtime 1x compares the two (footprint uses 2M keys by default)
In-process cache hit~92 ns (sharded LIRS; was 711 ns)engine benchmark

Because the CI rows use tmpfs and a client on the same host, compare them with each other, not with other hardware. Reproduce them with scripts/net-bench.sh or the “Net front-end” workflow: ENGINES=nocgo NETS=go WINDOWS="5 1" for the “C++ storage off” rows, ENGINES=sqpoll for the “all on” row, NETS="go uring poll" for the front-end row. The macOS 3.54M row is the same batch phase (loadtest --mode write --concurrency 8 --batch-size 1024 --num-keys 1000000) against a local server.

Network front-ends and storage configurations (net-bench.sh) New in v1.7

scripts/net-bench.sh starts a fresh server per combination and runs batch write (8 × 1024-key MPUT, BATCH_DURATION, default 10 s), read (64 binary GET clients) and mixed (70/30) workloads, then prints one markdown table (also to $GITHUB_STEP_SUMMARY). The “Net front-end” GitHub workflow runs it on Linux, where the io_uring code exists.

# Front-ends (NET:N = N event loops for a C++ front-end)
NETS="go uring poll uring:2" ENGINES=native WINDOWS=5 ./scripts/net-bench.sh

# Storage configurations under the Go front-end
ENGINES="native bridge sqpoll map nocgo" NETS=go WINDOWS="5 1" ./scripts/net-bench.sh

Defaults: NETS="go uring", ENGINES=native, WINDOWS=5, DURATION=15 s per read/mixed workload, NET_THREADS = CPU count. The C++ front-ends need the binary protocol, so reads and mixed run with loadtest --proto=binary.

ENGINES valueConfiguration
nativeNative C++ index, io_uring VLog bridge off — the default build
inlinenative, but the C++ front-end reads disk on its loop thread (VELTRIXDB_NET_DEFER_READS=0)
bridge / sqpollnative + VELTRIXDB_URING_BRIDGE=on / sqpoll
mapGo map index, bridge off
nocgoVELTRIXDB_DISABLE_CGO_ENGINE=1: map index, no C++ storage layer

October 2026 measurements New in v1.11–v1.12

Taken while building adaptive group commit, vector / text / hybrid search, PQ and the disk graph. All on one macOS laptop (Apple silicon) unless stated, so absolute numbers do not predict a Linux NVMe server, and none of them is a comparison with another database. Each table names the test or tool that reproduces it. Source: BENCHMARK_RESULTS.md, “October 2026 measurements”.

Durable single-key writes: adaptive vs fixed group commit

--group-commit=adaptive (the default since v1.12) vs fixed. The device’s fdatasync cost is emulated (a sleep before the real sync), because macOS fsync returns at the drive cache; that is what makes the result mean the same on a laptop as on Linux. 15 ms window, 128 B values, each writer doing sequential durable Puts for 1.5 s.

VELTRIX_GC_TABLE=1 go test ./storage -run TestGroupCommit_LatencyTable -v

Emulated sync = 300 µs (NVMe-like):

WritersModeP50P99Writes/sWrites per fdatasync
1fixed16.01 ms17.76 ms631.0
1adaptive0.45 ms0.52 ms2,1861.0
8fixed16.02 ms16.39 ms5018.0
8adaptive0.96 ms1.22 ms8,2838.0
64fixed15.94 ms16.81 ms4,05364.0
64adaptive1.67 ms2.64 ms37,50463.9
256fixed16.40 ms33.15 ms15,291249.3
256adaptive3.18 ms11.54 ms73,999255.2

Emulated sync = 2 ms (slow / network disk):

WritersModeP50P99Writes/s
1fixed18.10 ms23.68 ms55
1adaptive2.41 ms2.52 ms417
64fixed18.18 ms19.12 ms3,541
64adaptive5.40 ms7.07 ms11,691
256fixed18.32 ms35.17 ms13,705
256adaptive6.96 ms18.56 ms32,277

TestGroupCommit_AdaptiveGates (every PR) fails if a lone writer waits for the window or concurrent writers stop sharing syncs. The nightly workflow prints the table in its job summary.

YCSB A–F through the server (go-ycsb, VeltrixDB only)

bench/compare/cmd/ycsb (go-ycsb core workloads) against a local server: 20,000 records × 10 fields × 100 B, 20,000 operations, 16 threads, zipfian, whole-record writes. Client and server on the same laptop; macOS fsync does not reach the platter, so write latency here is a lower bound. Not comparable with the June YCSB 0.17.0 run.

cd bench/compare && START=0 DBS=veltrixdb RECORDS=20000 OPS=20000 THREADS=16 WORKLOADS="a b c d e f" ./compare.sh
WorkloadOpOps/sAvgP99P99.9
loadINSERT37,495419 µs1.29 ms2.04 ms
A (50/50 read/update)total34,640453 µs1.30 ms2.98 ms
READ17,230262 µs0.77 ms1.55 ms
UPDATE17,434642 µs1.63 ms3.14 ms
B (95/5)total52,255303 µs0.65 ms0.74 ms
C (read only)READ55,287287 µs0.39 ms0.53 ms
D (read latest)total55,163288 µs0.39 ms0.59 ms
E (short scans)SCAN23,651638 µs1.43 ms1.97 ms
F (read-modify-write)total40,067392 µs0.81 ms0.98 ms
READ_MODIFY_WRITE13,397915 µs1.22 ms1.49 ms

compare.sh defaults: DBS="veltrixdb aerospike scylla", WORKLOADS="a b c f", RECORDS=1000000, OPS=1000000, THREADS=64, START=1 (docker compose up / stop each database in turn). With START=0 it uses databases already running at VELTRIX_ADDR (default 127.0.0.1:9000), AEROSPIKE_HOST and SCYLLA_HOSTS. bench/compare is a separate Go module (Go ≥ 1.25).

Real embeddings. First 100,000 words of GloVe-100 (angular), 100 dimensions, 500 queries, exact cosine ground truth. In-process, one query at a time, macOS (Apple silicon, GOMAXPROCS = 18). Build = 18 parallel durable PutVector writers.

scripts/ann-dataset.py glove-100-angular /tmp/ann --train 100000 --test 500
VELTRIX_ANN_DIR=/tmp/ann go test ./storage -run TestRealEmbeddings -v -timeout 30m
LayoutBuildefrecall@10p50p99QPS (1 thread)
float3257 s640.8420.25 ms0.41 ms3,933
1280.9060.42 ms0.63 ms2,351
2560.9530.77 ms1.12 ms1,307
5120.9831.43 ms1.95 ms712
int850 s640.8390.61 ms0.81 ms1,655
1280.9050.55 ms0.80 ms1,905
2560.9520.72 ms1.08 ms1,356
5120.9831.18 ms1.84 ms834
pq (m = 25)42 s640.7970.56 ms0.90 ms1,771
1280.8700.72 ms1.06 ms1,367
2560.9271.17 ms2.91 ms780
5120.9691.56 ms3.44 ms604
pq + disk graph45 s640.7880.55 ms0.79 ms1,811
1280.8750.66 ms0.99 ms1,506
2560.9311.06 ms2.18 ms907
5120.9661.60 ms2.97 ms613

The quantized layouts are slower per query than float32 at this size because they re-rank from the VLog (one parallel MultiGet; before that change int8 at ef = 64 was p50 1.9 ms / p99 13.8 ms). Their point is RAM: at 100 dimensions the vectors are small and graph edges dominate. scripts/ann-dataset.py needs h5py and numpy.

Over the network (vecbench). GloVe-100, first 20,000 words, 300 queries, int8, 8 concurrent clients, server and client on one macOS machine. Load: 6.4 s (3,146 durable vector writes/s).

cd bench/compare && go run ./cmd/vecbench -data /tmp/ann -train 20000 -quant int8 -threads 8
# flags: -addr (default 127.0.0.1:9000) -efs (default 64,128,256,512) -queries -pqm -graph memory|disk -out results/
efrecall@10QPSp50p99
640.89424,6370.28 ms0.68 ms
2560.98515,6290.48 ms0.91 ms

RAM per vector, 768 dimensions. 10,000 synthetic clustered vectors, Go heap per vector, macOS.

VELTRIX_VECTOR_MEMORY=1 go test ./storage -run TestVectorMemoryTable -v
LayoutHeap / vectorMapped file / vectorvs float32
float323,383 B—1×
int81,078 B—3.1× less
pq, m = 96493 B—6.9× less
pq, m = 96 + disk graph378 B216 B8.9× less heap
Other vector measurementResultReproduce
CI quality gate, 5K × 64-dim clustered, recall@10f32 0.927, ef 256 0.998, int8 0.923, pq 0.882, pq + disk 0.881, filtered 0.994, after 40% deletes ~0.96every PR (node-7-search): go test ./storage -run TestSearchQualityGate -v
HNSW rework, 20K × 128 random, index onlysearch 240 → 99 µs (853 → 6 allocs); with 50% deleted 6.56 ms → 190 µs; insert 349 → 209 µsgo test ./storage -run '^$' -bench 'HNSW_(Search|Search_Deleted50pct|Insert)$'

Tested up to 100K real vectors and 10K at 768 dimensions; nothing at 10M+ yet.

Search soak and crash chaos

TestResult (macOS)Reproduce
Soak, 60 s: 4 writers + 4 searchers, 5K-id space, upserts / deletes / searches against an oracle of acknowledged writes201,573 writes, 292,079 searches, 0 results outside the oracle, 288,025 self-queries with 0 misses, RSS flat at ~1.0 GB, exact oracle match before and after restartVELTRIX_SOAK_DURATION=60s go test ./tests/integration -run TestSearchSoak -v
Crash chaos: SIGKILL mid-write, restart, rebuild3 cycles, 8,524 / 8,380 / 11,851 acknowledged writes, all visible after restart + rebuild, no deleted id returnedVELTRIX_CHAOS_CYCLES=3 go test ./tests/integration -run TestSearchCrashRecovery -v
Raft failover read barrierwithout it a new leader missed the acknowledged write in 20 / 20 test rounds; with it 0 / 20go test ./consensus -run TestWaitLeaderApplied_FailoverVisibility -v

The nightly workflow runs a 20-minute soak and 10 crash cycles on Linux:

VELTRIX_SOAK_DURATION=20m go test ./tests/integration/ -run TestSearchSoak -v -timeout 40m
VELTRIX_CHAOS_CYCLES=10 go test ./tests/integration/ -run TestSearchCrashRecovery -v -timeout 25m

Writes in flight at the kill are not checked. After each crash cycle the test rewrites every id whose write had an unknown outcome to a fresh, fully acknowledged version, so later cycles check those ids too.

Consistency and rolling-upgrade tests New on main after v1.16 — ships in the next release

Jepsen-style harness (tests/jepsen, Go standard library only, all in _test.go files): 3-node raft and replicated clusters of real server processes, 8 clients on the text protocol (GET, PUT, CAS, INCR, set adds), and a nemesis that SIGKILLs or SIGSTOPs the leader or a random node, crashes a follower mid-InstallSnapshot, and — through an iptables hook on Linux as root — partitions it. Checkers: per-key linearizability (Wing & Gong search with memoisation, shrunk to a minimal failing history), counters, sets, read validity and copy counts. A negative control must find stale reads.

TestConfigurationChecked
TestJepsenRaftLinearizableraft, --linearizable-readsEvery key linearizable including reads; counters; sets
TestJepsenRaftLocalReadsraft, local reads on random nodesWrites, CAS, INCR and final leader reads linearizable; ordinary reads for validity only (follower reads may be stale); all nodes converge
TestJepsenReplicated/strong, /quorumreplicated, kill / pause onlyOnly what the mode promises: an acknowledged write is on RF (strong) or RF/2+1 (quorum) nodes once healed; no value no client wrote. No linearizability check
TestJepsenNegativeControl_StaleReadsraft, local reads in the linearizability checkMust find a violation
go test ./tests/jepsen/ -short -timeout 120s          # checker unit tests only
go test ./tests/jepsen/ -v -timeout 15m               # every mode, 20 s of workload each
VELTRIX_JEPSEN_DURATION=5m VELTRIX_JEPSEN_SEED=42 \
  go test ./tests/jepsen/ -v -run TestJepsenRaftLinearizable -timeout 20m

Limits: one host (shared disk, kernel and clock; faults are process-level), no real partitions on macOS, no clock skew, power loss not simulated, single-key text-protocol operations only (no multi-key TXN, MPUT, namespaces, search or binary protocol).

Rolling-upgrade tests (tests/upgrade, VELTRIX_UPGRADE_TEST=1): real v1.16 and current-build processes on the same data dirs — raft rolling upgrades with and without snapshots, mixed-version snapshot transfers in both directions, a replicated rolling upgrade, standalone upgrade and downgrade (clean stop and SIGKILL), and raft downgrade with and without a wipe. They found the v1.16 snapshot TTL loss on upgrade (fixed) and corrected the downgrade guidance.

VELTRIX_UPGRADE_TEST=1 go test ./tests/upgrade/ -v -timeout 30m   # builds v1.16 from the tag

Both run nightly (.github/workflows/nightly.yml, jobs jepsen — with and without --raft-pipeline, partitions enabled — and upgrade).

Against Aerospike and ScyllaDB (same hardware)

No shared run yet The harness exists; no same-hardware comparison has been run or published. The Aerospike and ScyllaDB drivers (upstream go-ycsb code), docker-compose.yml and aerospike.conf (and, since v1.15, docker-compose.cluster.yml and the 3-node Aerospike confs) are compile-checked only. There is no vector driver for Aerospike Vector Search or ScyllaDB vector search.

bench/compare/compare.sh runs go-ycsb workloads through a VeltrixDB driver and go-ycsb’s Aerospike and Cassandra (ScyllaDB) drivers, one database at a time on the same machine, and writes results/<ts>/summary.md.

# On the machine under test (Linux, NVMe), with Docker and Go ≥ 1.25:
export BENCH_DATA=/mnt/nvme0/bench BENCH_CPUS=8 BENCH_MEM=16g
./compare.sh                                   # all three, workloads a b c f
RECORDS=10000000 OPS=10000000 THREADS=128 WORKLOADS="a b c d f" ./compare.sh

# Vectors (VeltrixDB only):
../../scripts/ann-dataset.py glove-100-angular /mnt/nvme0/ann --train 1000000 --test 1000
VECTORS=1 ANN_DIR=/mnt/nvme0/ann VEC_ARGS="-quant pq -graph disk" ./compare.sh

Publish a result only with all of these stated next to it: the same machine and disk with one database running at a time (a client on a second machine is better still); the durability setting of each (VeltrixDB ACKs after fdatasync of WAL and VLog; ScyllaDB’s default commitlog_sync: periodic ACKs before the write is on disk, so use batch or report both; Aerospike ACKs from its write buffer); warm-up and a dataset larger than the caches if the point is disk performance; the replication factor (1 with NODES=1, 3 with NODES=3); and the versions of all three.

3-node clusters, replication factor 3 Fixed in v1.15

NODES=3 sets RF 3 for every database and needs three addresses per database. For VeltrixDB: VELTRIX_ADDRS (comma-separated), VELTRIX_MODE=raft|replicated, and VELTRIX_RAFT_PIPELINE=true|false so the summary records which --raft-pipeline setting the servers ran. The VeltrixDB driver homes threads round-robin over the addresses and reads locally; writes follow the first MOVED <leader> and share the leader address across threads; MOVED - (election running) waits and retries; a connection error fails over to the next listed node. After the run, cmd/keycount checks that every node holds every record. The guarantees differ per database (raft: quorum commit through the leader; ScyllaDB: QUORUM; Aerospike CE: all three copies), so state them next to any number.

# servers already running on three hosts
START=0 NODES=3 VELTRIX_MODE=raft \
  VELTRIX_ADDRS=10.0.0.11:9000,10.0.0.12:9000,10.0.0.13:9000 DBS=veltrixdb ./compare.sh

# GCP: 3 server VMs with local NVMe + 1 client, raft-off / raft-on / replicated, then deletes everything
PROJECT=<your project> ./gcp-multihost.sh

START=1 NODES=3 runs three containers per database on one machine (docker-compose.cluster.yml) to check that clusters form and drivers route — not for performance. That compose file is syntax-checked only; the 3-node VeltrixDB path was run as local processes on one laptop, against raft and replicated clusters and with a raft leader killed mid-run. Laptop figures, which are not cluster results (three raft nodes share one drive): the incremental raft log took load from 70 to 1,046 inserts/s (one run each), and --raft-pipeline was slower on load (560 vs 1,038 inserts/s, medians of 2 runs). No multi-host run has been published yet.

Internal GKE run (unverified)

Not a reproducible result These figures come from an internal run with no published harness or raw output. They have not been reproduced, and “1 billion keys” has not been measured reproducibly. Do not use them for capacity planning; the YCSB results above are the only reproducible headline numbers.

Reported conditions: 3-node GKE cluster · n2-highmem-64 · 8×375 GB NVMe per node · 1 billion keys · 80R/20W · 30 minutes sustained.

MetricValue
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 events0
Errors0
Storage density~160 GB for 1B × 128 B values (by arithmetic from the bench.sh density of ~160 B per 128 B record, not a billion-key measurement)

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, historical — mixed provenance

Pure-Go path with the fixed group-commit window (before adaptive group commit became the default in v1.12). Each row says whether it was measured, computed or projected; none is a current benchmark run.

OperationP50P99
GET — cache hit0.05 ms0.28 ms (~1.4M reads/s, measured on macOS)
PUT — 15 ms fixed flush window5 ms15.2 ms (Linux NVMe)
PUT — 5 ms window, 512 workers2.6 ms5.2 ms (~102K writes/s is the computed ceiling, not a measurement)
MultiPut 1024 entries—~9.5 ms (~426K entries/s is a Linux projection from macOS ~108K/s)

VeltrixDB vs. Redis, head to head

The VeltrixDB column is from the YCSB run above. The Redis column was not measured — it is a range of commonly cited figures, included for orientation only.

ModeVeltrixDBRedis
Durable writes (fsync every write)18,064 ops/sec10,000–30,000 ops/sec
Non-durable writes (no fsync)N/A — always durable100,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.

ResourceVeltrixDB (100M keys)Redis (100M keys)
RAM required15 GB as recorded (index; 400 GB provisioned as cache). Today’s per-key figures give ~14–23 GB (~142 B/key native index + ~90 B/key ordered index)30–45 GB (data lives in RAM; estimate, not measured)
Disk required~25 GB per NVMeSwap/RDB snapshots only
Max dataset size3.5 TB (NVMe)Limited by RAM
Dataset > RAMWorks (reads from NVMe)Evicts or crashes

Key takeaways

Reproduce it yourself The YCSB numbers come from YCSB 0.17.0 against VeltrixDB v1.0 (June 2026); the later measurements from scripts/net-bench.sh and engine benchmarks (September 2026, v1.7 code); the October 2026 tables from the Go tests and bench/compare commands printed above each (v1.11–v1.12 code, macOS laptop); the reference tables from scripts/bench.sh and projections. 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.