mirror of
https://github.com/kvcache-ai/Mooncake.git
synced 2026-11-05 01:17:55 +00:00
[GH-ISSUE #4499] [RFC]: Add KVCacheStore as a shared capacity backend for Mooncake Store #1144
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#1144
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 @zxpdemonio on GitHub (Oct 8, 2026).
Original GitHub issue: https://github.com/kvcache-ai/Mooncake/issues/4499
Changes proposed
This RFC proposes an optional KVCacheStore Low Level adapter for Mooncake Store. The adapter uses the existing distributed-storage integration point, keeps Mooncake Master authoritative for logical object lifecycle, and accesses KVCacheStore through the node-local EFC data plane.
PR1 covers the smallest functional Low Level read/write/delete contract: one configured shared target and one provider value per object. The larger prototype remains Draft PR #4500 and is split into staged child PRs below; Standard mode is deferred until its public control-plane contract and validation environment are established.
The design requires explicit configuration and remains buildable when the KVCacheStore SDK is absent. It does not start EFC, infer enablement from a Unix socket, or copy provider placement state into Mooncake metadata.
Why this needs an RFC
Mooncake's contribution guide asks architectural changes larger than 500 lines to start with a GitHub RFC. This change affects storage metadata, request routing, failure handling, and the distributed-storage abstraction. It also overlaps with two existing proposals:
The driver itself is not the hard part. This RFC asks where a shared, provider-managed cache should attach to Mooncake and which parts of the lifecycle Mooncake should own.
Motivation
Mooncake already moves KV cache data between memory and external capacity tiers. KVCacheStore adds a provider-managed G3.5 capacity tier with a user-space KV interface. Its public deployment model places an EFC process beside the application; the SDK talks to EFC over a Unix socket and shared memory, while EFC handles the remote storage data path. The storage service can be attached to another compute node without copying data into that node first.
That model is useful for disaggregated inference, but it does not fit perfectly into Mooncake's current OSS offload path. The current OSS offload design treats the external object as a
LOCAL_DISKreplica owned by a real Mooncake client. Readers contact that owner, and the owner accesses OSS throughFileStorageandDistributedStorageBackend.KVCacheStore is different in one important respect: every correctly configured compute node has a local EFC endpoint for the same attached storage pool. Sending a read through the original writer adds an unnecessary owner hop and makes the writer part of the read availability path. The proposed adapter lets the requesting Mooncake client read the shared provider directly, after Mooncake Master has confirmed that the logical replica is valid.
The integration must preserve a clear metadata boundary:
Goals
Non-goals
Public KVCacheStore architecture
The following diagram is limited to behavior described in the public KVCacheStore documentation. It does not assume an internal control-plane topology.
The public integration guide establishes the constraints that matter to Mooncake:
kvcs-efcrun on the same node and under the same OS user;/var/run/kvcs/efc-grpc.sockby default;The broader product overview describes KVCacheStore as a capacity layer between compute-local memory and remote shared storage. Mooncake should use that capacity service, not duplicate it.
Relationship to existing Mooncake work
ObjectStorageAdapterunderDistributedStorageBackendDistributedKVStorageBackendandIDistributedKVClientFileStorage/owner modelThe prototype uses
ObjectStorageAdapterbecause that path already carries an adapter identity and object size in the DFS replica descriptor. This RFC does not treat that choice as irreversible. If #2993 becomes the accepted common interface, the KVCacheStore driver should implementIDistributedKVClient, while the lifecycle and failure semantics below remain unchanged.Proposed architecture
There are three independent authorities:
This split avoids two bad states: the Master must not advertise provider data that was never committed, and it must not mistake provider placement details for stable metadata.
Access mode and initial scope
The first community landing contains only
kvcs-lowlevel.Keeping Standard out of the first PR is a review and operability decision, not a claim that the mode is unworkable. It can follow once its public deployment contract, failure model, and validation environment are available.
Metadata model
Mooncake Master stores one committed DFS/object-storage replica descriptor containing:
kvcs-lowlevel;It does not store a KVCacheStore target, mountpoint index, EFC address, provider manifest, or device location. On snapshot restore, Mooncake must reject a provider descriptor whose adapter identity does not match the configured adapter. Reopening the same logical key with different physical-key rules is unsafe.
The provider context returned by query is attached only to the client request. It may be reused by the immediately following read for the same logical key and size. It must not be cached across unrelated requests or persisted by the Master.
Provider key and value layout
Tenant-safe physical keys
The physical root key is an injective printable encoding:
The adapter validates the encoded root and every derived suffix against the configured provider key limit before issuing any SDK operation. Hex encoding is intentionally simple: it avoids delimiter ambiguity and keeps different tenants from mapping the same logical key to one provider record.
Inline and chunked values
Small values use the root key directly. Larger values use deterministic
.part_Nkeys plus a.manifestrecord. The manifest is a fixed 32-byte, versioned, little-endian wire format:MCMFThe implementation must encode and decode fields explicitly. Serializing a C++ structure is not part of the format. Readers reject an unknown version, inconsistent size, zero chunk count, non-zero reserved field, missing chunk, or chunk whose size does not match the manifest.
The manifest is written last and acts as the provider-side visibility point. Its existence does not commit the Mooncake object;
PutEndat the Master remains the logical commit point.Request flows
Put
Put remains insert-only. Mooncake creates logical metadata first, writes the provider, and commits only after every required provider record is visible. Rollback deletes only records whose insertion is known to have succeeded. A timed-out SDK call is not proof of failure and is handled as an ambiguous outcome, described below.
Query and Get
The Master result is always authoritative. A provider hit cannot create a Mooncake object, resurrect a deleted key, or override a memory replica. Conversely, a complete Master descriptor cannot turn an EFC miss into data. The read succeeds only when both views agree.
Low Level provider query may run in parallel with the Master query because the SDK call has an absolute deadline. Speculation is an optimization: its result is ignored when the Master returns a usable memory replica or no complete KVCacheStore replica.
Remove and retry
The first implementation removes Master metadata before deleting provider records. This ordering prefers an unreachable orphan over metadata that points to missing data. A retry is allowed to continue provider deletion when the Master already reports
OBJECT_NOT_FOUND.KVCacheStore Low Level does not provide key enumeration for Mooncake-owned prefixes, so the first landing cannot promise background orphan discovery. Durable cleanup tasks are an open design item, not an implicit capability.
Upsert
Upsert is
Removefollowed byPut. It is not atomic. There is an interval in which the key is absent, and a failed second step leaves it absent. Callers that require compare-and-swap or uninterrupted replacement need a future generation-aware API.Eviction and stale metadata
Provider eviction is expected behavior in Low Level mode. It creates a specific consistency case: Mooncake Master may still contain a complete KVCacheStore replica descriptor after its provider records have been evicted.
The adapter handles this conservatively:
The first PR must also define how stale provider replicas are invalidated at the Master. The preferred design is a conditional invalidation tied to the queried replica identity or epoch, so a late miss cannot remove a newer Put. If the existing Master API cannot express that safely, automatic invalidation remains disabled and the limitation must be documented before landing.
Returning a miss is safe; silently claiming that the provider still contains the object is not. This point is a release blocker because provider LRU cannot be disabled.
Target selection and availability
An EFC configuration may expose more than one Low Level target. The prototype computes a stable target order from the encoded root key, tries the first target, and falls back to other healthy targets for the same operation.
Fallback is not replication. The first release writes one target and must not advertise several targets as independent Mooncake replicas. A read fallback is useful only when the object can legitimately exist on another configured target; otherwise it adds latency without durability. The initial community implementation should therefore start with one explicit shared target unless maintainers confirm that multi-target lookup is part of the supported deployment contract.
Mooncake does not persist target indices. A configuration change may reorder mountpoints, so any multi-target design must identify targets by stable provider identity rather than array position before it can be considered durable.
Failure semantics
Low Level has no generation token or conditional delete. A timeout therefore cannot distinguish “the provider did nothing” from “the provider completed but the reply was lost.” The prototype quarantines affected physical keys in the current process until restart. This prevents immediate unsafe reuse, but it is not durable fencing. Cross-process recovery requires provider generations or a Mooncake-owned generation in every physical key.
Configuration and runtime contract
KVCacheStore is enabled only by explicit configuration. Socket presence is not an activation signal.
The values above are safe starting points, not universal tuning recommendations. The KVCacheStore integration guide sizes shared memory approximately from:
Mooncake validates the effective configuration before creating the adapter. It does not create the socket, start EFC, modify
/dev/shm, or rewrite provider configuration. Runtime packaging must mount the EFC socket and allocate enough shared memory inside the application container.The initial scope is single-tenant because the current Mooncake distributed-storage configuration is single-tenant. The physical key still contains the tenant ID so the format does not bake in a cross-tenant collision.
Build and dependency model
The KVCacheStore SDK remains optional. CMake discovers it through
pkg-configand compiles aNOT_SUPPORTEDfactory when it is absent. Existing Mooncake builds and deployments acquire no new runtime dependency.The community repository should not vendor KVCacheStore binaries or implementation sources. SDK-independent behavior—key encoding, manifests, chunking, reconciliation, deadlines, rollback planning, and error mapping—must be testable through an injected driver. Tests that call the public C ABI can run in an optional provider-enabled job.
Published validation evidence must come from the containerized toolchain used for the prototype and provider SDK tests. Host-only compilation or network checks are not acceptance evidence.
Compatibility
NOT_SUPPORTEDonly when KVCacheStore is explicitly requested.MOONCAKE_KVCS_MODE=kvcsmay map tolow-levelfor one transition period, but new documentation must not use it.Security and isolation
Observability
The adapter should expose, at minimum:
Misses are expected cache events and should not be logged as transport failures. Malformed layouts and ambiguous outcomes deserve separate error labels because they require different operational responses.
Validation plan
No implementation PR should be marked ready until the rebased commit has the following evidence from that container environment.
Build matrix
Deterministic tests
Real EFC validation
Performance numbers should be reported separately from correctness evidence, with hardware, EFC configuration, object-size distribution, concurrency, and baseline commit recorded.
Revised staged delivery (supersedes the earlier all-in-one sequence)
This section supersedes the earlier all-in-one implementation plan. The
existing Draft PR #4500 is a full prototype and remains available for
reference; PR 1 is a separate, smaller branch based on community main. Each
stage below should be reviewed and validated on its own commit.
one KVCacheStore value per object; 4 MiB default per-value limit. Keep the
existing distributed-storage adapter and Master-authoritative placement
path. Implement insert-only Put, Query, Get and Delete and quarantine ambiguous
writes. Query Master first;
perform any needed provider query within a bounded deadline only for
matching Master KVCS replicas. Query reports existence, not a manifest;
Get validates its bytes against the Master object size. Reject oversize
values before calling the SDK, and fail
initialization on multi-target or incompatible mixed deployments. Bulk
RemoveByRegexandRemoveAllexplicitly report unsupported untilprovider-wide deletion has a safe contract. Without the optional SDK,
other backends still build
and explicit KVCS initialization reports NOT_SUPPORTED. Exit criterion:
focused SDK/no-SDK builds and correctness tests, plus the existing
single-value real-EFC correctness evidence. Single-key Remove and
BatchRemove are included. Because PR 1 is insert-only, they delete the
physical value before releasing the Master name; a concurrent Put therefore
cannot publish a new value that this Remove later deletes. A provider miss
is idempotent. If Master rejects the removal after the provider delete, the
error is returned and the logical metadata remains for retry; generation
IDs or a Master-side reservation can provide atomic cross-system deletion
in a later protocol. Bulk RemoveByRegex and RemoveAll remain unsupported.
No chunks, multi-target router, eviction repair or metrics.
multi-target routing. A separate stacked child PR based on PR 1 adds
versioned manifests, deterministic chunks, bounded batch handling,
cross-chunk rollback and uncertain-outcome isolation. Only add stable
multi-target routing once target identity and mixed-deployment semantics
are agreed. Validate boundaries, failed/partial operations and recovery
against the actual deployment. If these responsibilities are too large for
one review, submit them as two sequential child PRs; PR 1 remains usable.
stale Master replicas after provider misses, with race tests and operator
recovery guidance. PR 1 fails closed on a provider miss; it does not
automatically correct stale Master metadata.
the separate metrics backup branch. Keep it out of PR 1 and do not publish
performance figures in PR descriptions, comments or logs.
contract and validation environment have been established.
The earlier full prototype has already passed real-EFC correctness
validation. Retain that result as historical evidence. The cleanup head has
separate focused SDK/no-SDK evidence; do not turn the historical run into a
claim about a new live-EFC execution of this cleanup head.
Corresponding corrections to the existing RFC sections
object on a single shared mountpoint. The chunk format, manifest and target
selection are PR 2 designs, not claims about the PR 1 code.
only Master-advertised KVCS replicas can be read from the provider. There is
no speculative parallel Master/provider query in PR 1. Provider query
only checks presence. The Master descriptor supplies the expected
size; Get checks the actual provider response. There is no second manifest
or per-request shard context to serialize.
writes, preserves ambiguous-outcome isolation, treats a missing provider
value as an idempotent delete, and leaves Master metadata for retry if its
removal is rejected after the physical delete. Automatic stale-replica
cleanup is stage 3; bulk deletion remains unsupported.
SDK-optional build and real-EFC checks from PR 2 chunk/multi-target and
stage 3 eviction-race cases. The prototype's completed real-EFC run and the
PR 1 head's run must be labeled independently.
Alternatives considered
Implement KVCacheStore directly under #2993
This is a viable outcome and may be the cleanest community direction. The missing piece is direct-reader semantics: the current owner-oriented path should not require every shared-provider read to traverse the original writer. If #2993 accepts request-local provider queries and direct reads, this RFC's adapter can live there.
Reuse the current OSS owner path unchanged
This avoids client changes but keeps the original writer in the data path. It weakens availability and adds a network hop even though the requesting node already has local access to the shared provider.
Reuse the #1957 Mooncake control plane
That design suits Mooncake-owned NVMe devices. Applying it unchanged to KVCacheStore would duplicate provider placement, capacity, LRU, and health decisions. Mooncake would hold state it cannot keep authoritative.
Persist provider target locations in Master metadata
Rejected. EFC topology and provider placement may change independently of Mooncake snapshots. Persisting them would convert a runtime routing hint into stale protocol state.
Enable KVCacheStore whenever the EFC socket exists
Rejected. A mounted socket does not prove that every client and the Master agree on adapter mode, key format, tenant, or target set. Explicit configuration makes mismatches visible.
Land Standard and Low Level together
Deferred. Low Level has a public contract and bounded record operations. Standard introduces a second metadata authority and currently lacks the same public failure and deadline model. Combining both would make the first review broader without proving the shared path better.
Open questions
ObjectStorageAdapter, or become the first concrete driver under #2993?Requested decision
This RFC asks maintainers to agree on five points before implementation review begins:
Once those boundaries are settled, the implementation can be rebased and split without asking reviewers to infer architecture from a large prototype diff.
Before submitting
@github-actions[bot] commented on GitHub (Oct 8, 2026):
Thanks for opening this issue, @zxpdemonio!
16206312A maintainer will triage this when possible. To help us respond faster, please include:
Useful links: Documentation · Contributing guide