Storage Internals
How MemKV stores blocks on NVMe — extent layout, forward-compatible versioning, and batched TRIM.
Extent-based storage
Large context blocks are split across multiple NVMe drives to enable parallel I/O. Two dials govern the split:
storage.block_size— the on-drive extent size. Default 4 MiB. Allocations larger than one extent are striped across drives; smaller allocations live in a single extent. Tune per workload (smaller for many small objects, larger for sustained bulk transfers).memory.block_size— the bounce-buffer chunk size used by the RDMA staging pool. Default 2 MiB. This is the granularity of a single RDMA READ / WRITE; multi-extent transfers pipeline through many chunks.
The two are independent — a 4 MiB extent is reached by two 2 MiB bounce-buffer chunks at the default settings.
Versioning and forward compatibility
MemKV releases are date-stamped (RELEASE.<commit-date>). There is no
semver line because the on-drive and wire formats are forward-compatible
by contract. Every record — superblocks, journal headers, B+Tree pages,
the embedded failure registry, and TCP message headers — carries a
version field, and a build accepts any version inside the range it
supports. Two things fall outside that range and are refused: a version
higher than the build's current constant, and a version below the
build's floor.
For operators this means:
- Roll-forward is automatic within the supported range. Upgrading the binary keeps the NVMe state usable with no migration step. The new server simply reads the older format.
- A device below the floor must be reformatted. The superblock and
B+Tree floor is version
2, because v2 moved the data region to make room for a key region. A server that opens a v1 device refuses it and names the supported range in the error; re-runmemkv setup --forceon that drive. Its contents are cache state, so reformatting costs repopulation time, not data. - Don't roll back across format bumps. An older MemKV binary refuses NVMe state written by a newer one rather than risk misinterpreting unknown bytes. Plan upgrades as one-way.
- Mixed-version fleets work in one direction. A newer server
accepts requests from older clients (NIXL plugin or admin client);
an older server rejects requests from a strictly newer client with
UnsupportedVersion. Upgrade servers first, then clients.
The contract is enforced at every header parse site. The wire-protocol
header, the device superblock, the embedded failure registry, the
journal header, and the B+Tree index header each carry a 1-byte (or
2-byte, for the B+Tree) version field, and each decoder checks it
against the range that build supports before reading any other byte.
Capacity reclaim
MemKV holds a cache, so the drives recycle on their own instead of filling up
and refusing writes. Once storage passes storage.eviction.high_watermark
(70% by default) a background worker releases the least recently used blocks
until fill is back under low_watermark (60%), and the freed space goes
through the same batched TRIM path as an explicit delete.
This matters most for engines that never delete. SGLang's storage-backend
interface has no per-key delete at all — each backend is expected to manage its
own retention — so without server-side reclaim a HiCache deployment would fill
its drives once and then fail every subsequent write. Set
storage.eviction.enabled: false only when the client manages retention and
you would rather see writes fail than lose a cached block. See
Configuration for the knobs.
Block deletion and TRIM
DELETE operations mark blocks as free in the in-memory index and queue TRIM requests to a background worker. The
trim worker batches and coalesces adjacent ranges, then issues NVMe TRIM (BLKDISCARD) commands every 5 seconds or
when the batch reaches 1,024 extents. This batched approach avoids synchronous TRIM latency while keeping the SSD
controller able to perform garbage collection for sustained write performance.
Transport & Auth
How MemKV moves bytes — RDMA DC, RC fallback, the TCP wire format, HMAC-SHA256 authentication, and the context-block offload flow.
Benchmarks
Measured MemKV throughput — 97.4 GiB/s peak read, 97.4 GiB/s peak write on a 2-server fleet at ~97% of 2× 400GbE line rate. The NIXL plugin's request batch optimizer fetches shared read ranges once and scatters locally, so effective read bandwidth exceeds raw NIC line rate.