mirror of
https://github.com/kvcache-ai/Mooncake.git
synced 2026-11-05 01:17:55 +00:00
[GH-ISSUE #4591] [RFC]: Shared NVMe KV Backend for Mooncake Store #1168
Labels
No labels
ascend
auto-closed
bug
bug
CI/Build
Common
documentation
enhancement
feature request
good first issue
help wanted
high priority
MetaX
nightly-failure
pull-request
PyTorch Backend
question
RFC
Roadmap
stale
Store
Tests
Transfer Engine
No milestone
No project
No assignees
1 participant
Notifications
Due date
No due date set.
Dependencies
No dependencies set.
Reference
kvcache-ai/Mooncake#1168
Loading…
Add table
Add a link
Reference in a new issue
No description provided.
Delete branch "%!s()"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Originally created by @Javen-Ke on GitHub (Oct 12, 2026).
Original GitHub issue: https://github.com/kvcache-ai/Mooncake/issues/4591
Changes proposed
1. Introduction
This proposal introduces a
SHARED_NVME_KVreplica type that allows multiple Clients to access the same external KV storage pool directly over NVMe-oF. The Master manages allocation identities, replica publication, LRU eviction, and cleanup. The Target executes KV commands and manages physical storage space. Published replicas remain available independently of the writing Client, and other Clients can read them without forwarding requests through that Client.All Clients connect to the same set of namespaces using an identical, ordered namespace list. Each Client selects a namespace using
hash(logical_key) % N, whereNis the number of namespaces. This distributes large sets of keys approximately evenly across namespaces. Applications continue to use Put/Get: a write selects the shared replica type, obtains an allocation ID from the Master, writes directly to the Target, and publishes the replica. Other Clients query the descriptor and read directly using the same routing rule. This balances key counts, not necessarily storage usage or access load.2. Background and Motivation
SPDK 26.09 adds support for exposing KV-capable bdevs as NVMe KV namespaces through its NVMe-oF Target. This provides a Target implementation on which multiple Clients can build direct access to an external KV pool. The release was published on September 24, 2026; see the SPDK 26.09 release notes.
The existing
NvmeKvStorageBackendpublishesLOCAL_DISKreplicas throughFileStorage, with reads served by the Client that owns the replica. PR #3513 proposes NVMe-oF connectivity for that backend while retaining this replica model. Even when multiple Clients can access the underlying device, Client B still reads data written by Client A through A. Once A exits, that proxy path can no longer serve the data, even if the data remains intact on the Target.A shared pool needs data access and replica lifetime to be independent of the writer. The relationship to existing work is:
FileStorage/LOCAL_DISK. This proposal reuses object encoding and command execution, lets the requesting Client access the Target directly, and assigns physical identities and lifecycle management to the Master.LOCAL_DISKreplicas throughFileStorage. This proposal represents data as independent shared replicas, without requiring an owning Client to load and forward it.3. Technical Design
3.1 Components and Responsibilities
Dashed arrows represent control requests; solid arrows represent data operations.
PutStart/PutEndto manage allocation identities, publication state, access recency, and pending cleanup records. A writing Client's exit does not invalidate its published shared replicas.SharedNvmeKv: The Client selects the shared path from the replica descriptor. The newSharedNvmeKvobject layer handles physical key encoding, object framing, idempotent writes, and read validation.NvmeKvCommandExecutoras the reuse boundary and adapt the SPDK KV implementation from #3513. The executor owns device connections, KV commands, DMA buffers, and completion handling.Deletethrough the KV executor independently of the original writing Client. Section 5 describes the implementation approach.3.2 Replica Descriptors and Physical Addressing
The shared descriptor is returned through the existing replica query interface. Its core fields are:
The descriptor does not need the writing Client's address. The request carries the logical key, which selects the namespace using the routing rule above;
allocation_ididentifies the physical allocation within that namespace. Initially, namespace membership, ordering, and the hash function must remain unchanged while shared allocations exist. Reads, writes, and cleanup use the same mapping.Each new allocation receives a new
allocation_id; retries of the same device write reuse that ID. Physical keys use a fixed 16-byte encoding, matching the maximum key length allowed by the NVMe Key Value Command Set specification:BE64denotes a 64-bit big-endian encoding. Part 0 stores an inline object or a manifest; parts 1 through N store data chunks.Using unique, non-reused allocation IDs avoids accidental deletion and physical-key hash collisions:
Deletefrom affecting the new object.IDs must never be reused within the managed storage domain, including across Master restarts. We propose integrating ID range reservations with the Master's existing persistence infrastructure and issuing IDs only from durably reserved ranges, as described in Section 5. Stored objects include their full logical and physical identities, lengths, and checksums, all of which are validated on reads.
The Master separately maintains control state that is not copied into the descriptor:
allocation_id, used to match completion and revocation requests. This identity is retained even if a write to multiple replica types falls back to memory only.3.3 Put and Get
Put:
PutStartcreates an in-progress record on the Master, allocates an ID, and returns aSharedKvDescriptor.PutEnd. The Master publishes the replica only if it matches the current write attempt, preserving the existing success criteria for writes involving multiple replica types.The first write to a new ID should not encounter an existing entry. However, if a
Storesucceeds and its completion result is lost, retrying the same allocation may return an already-exists result. The Client then reads back the entry and validates its identity, length, and checksums before treating the retry as successful. Retries must use the same ID and contents.PutRevokealso matches the write identity so that delayed requests cannot alter a later write attempt. Clients do not delete physical data merely because a write or publication result is unknown. The Master is responsible for reclaiming abandoned allocations.Get:
NotFound, the Client asks the Master to invalidate only the shared replica matching the allocation ID from that query. Other replicas are retained. Timeouts and disconnections are returned as read errors without invalidating the descriptor.Normal LRU eviction must not cause
NotFoundfor a published replica under valid read protection. This path handles Target data loss or stale descriptors, such as published data lost after restarting a nonpersistent Target.3.4 Master LRU and Cleanup
The Master may use an NVMe-oF initiator to periodically query capacity metrics exposed by the Target. Capacity watermarks trigger LRU eviction, with candidates selected by access recency. Monitoring is used to trigger reclamation; the Master does not use it to restrict new writes. The Target decides whether space can be allocated during
Storeand reports insufficient capacity. The supported capacity metrics and monitoring interface remain to be determined.The Master coordinates eviction and deletion:
The Target must not independently evict managed entries through LRU or TTL expiration. The Master controls their eviction and cleanup.
Never reusing IDs does not prevent a delayed
Storefrom recreating an old entry afterDelete. Until old writes are confirmed to have stopped, retain the pending cleanup task and recheck it later. A timeout alone is not proof that a write has stopped. Section 5 describes write termination and cleanup recovery.4. Implementation and Evaluation
4.1 Implementation Phases
This proposal supports Put/Get for complete, immutable objects. Upsert, range writes, and session writes are outside its scope and must be explicitly rejected.
Phase 1: Shared Reads and Writes
The initial deployment uses a single Master, dedicated namespaces, fixed routing, and the default tenant.
Phase 2: Reclamation
Phase 3: Chunking and Multiple Tenants
Chunking: Extend the object layout while retaining the same allocation and publication protocol. Publish and evict complete objects.
Register the allocation ID, layout version, and chunk count before writing. Write chunks first, then the manifest, and finally publish through the Master. The registered chunk count allows cleanup to enumerate every physical key even if the manifest is missing. Both chunks and the manifest must fit the device's value-size limit.
Multiple tenants: Reuse the existing logical identity model and add capacity accounting, quotas, and eviction policies per tenant.
All tenants sharing a physical namespace use one ID allocation domain. Mutually untrusted tenants also require access isolation at the Target; logical key prefixes do not enforce device access permissions.
4.2 Validation Plan
Storeoperations, deletion retries, partial chunk-write failures, sustained capacity pressure, tenant quotas, and eviction fairness.LOCAL_DISKover NVMe-oF, and the shared path using the same devices, network, object sizes, and concurrency. Report throughput, P99 latency, CPU usage, and data-copy overhead. Results will be added after implementation.5. Implementation Approach and Remaining Validation
Storesubmissions and retries for that ID and establish that in-flight I/O has ended. Keep allocations without that confirmation in a queue for later rechecking. When metadata recovery is added, use the operation log's durable-completion callback to issueDeleteonly after the visibility withdrawal and pending cleanup record are durable, and retry unfinished tasks after recovery. If a disconnected Client cannot confirm termination, whether the chosen transport can provide reliable evidence that old writes have stopped remains to be validated. A fixed delay is not a safety guarantee.Before submitting a new issue...
@github-actions[bot] commented on GitHub (Oct 12, 2026):
Thanks for opening this issue, @Javen-Ke!
288857397A maintainer will triage this when possible. To help us respond faster, please include:
Useful links: Documentation · Contributing guide