mirror of
https://github.com/kvcache-ai/Mooncake.git
synced 2026-11-05 01:17:55 +00:00
[GH-ISSUE #2031] [RFC]: Promote data from L2 -> L1 when it's not in L1 #562
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#562
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 @yzhan1 on GitHub (May 4, 2026).
Original GitHub issue: https://github.com/kvcache-ai/Mooncake/issues/2031
Changes proposed
Motivation
Mooncake Store maintains a two-tier KVCache hierarchy: MEMORY replicas (DRAM, RDMA-direct, sub-millisecond reads) and LOCAL_DISK replicas (per-client SSD, multi-millisecond reads via a peer RPC plus disk I/O). Today, once a key has been evicted from DRAM down to LOCAL_DISK, it stays on LOCAL_DISK indefinitely. Every read for that key pays the SSD cost forever.
For inference-serving workloads this is a TTFT-shaped problem. A KV block that gets reused dozens of times after its first SSD-only lookup keeps generating SSD reads instead of being warmed back into DRAM.
This RFC proposes the mirror direction of #1899: when a Get hits a key whose only complete replicas are LOCAL_DISK, asynchronously create a new MEMORY replica so subsequent Gets for that key go fast. The structure mirrors offload-on-evict exactly — opt-in gflag, deferred per-shard queue, heartbeat-pull on the owning client, NotifyPromotionSuccess push back, refcnt-pinned source replica.
In Scope
Notify…Successcompletion path.Out of Scope
Background
Lifecycle today, and why this RFC is needed
A traced walkthrough of an object's lifecycle in
mainconfirms there is no master-coordinated promotion today. Every relevant code path was inspected.*Re-Put is rejected:PutStarton an existing key returnsOBJECT_ALREADY_EXISTS.Upsertis the only path that succeeds, and it replaces the entire metadata (discards old replicas + reallocates) — it cannot add a MEMORY replica next to an existing LOCAL_DISK.Background threads that mutate replica state (eviction, client monitor, task cleanup, snapshot, job dispatch) were each examined; none scan for hot LOCAL_DISK keys or perform any promotion-shaped work.
This is the gap Roadmap #1883 Milestone 13 names. Mooncake has the primitives in place — allocation strategy, RDMA write, replica add, refcnt pinning — but no policy that wires them together for the access-triggered case.
Design choices considered
Two coherent ways to close the gap exist; this RFC commits to (a).
AllocationStrategypath, writes via Transfer Engine, master commits the new MEMORY replica. Mirrors #1899 seam-for-seam.Upsertcompose-friendly so the engine re-Puts. Today'sUpsertStartdiscards old replicas before reallocating; a variant that adds a new MEMORY replica next to existing LOCAL_DISK without dropping the old would let the engine Re-Put on every Get-from-disk. The engine becomes responsible for the policy.Recommendation: (a). Three reasons:
(b) is left available as a future option if a need ever arises for engine-driven cache control over the same surface; this RFC does not preclude it.
Why a deferred queue (not synchronous promotion at Get time)
A Get RPC must return fast. Synchronous DRAM allocation + SSD read + Transfer Engine write would add multi-ms to every cold-path Get and gate the response on writeable DRAM space. Deferring is also what offload-on-evict chose for the same reason. The Get path is unchanged from today's behavior; promotion happens out of band.
Proposal
Architecture
Two phases, mirroring #1899:
After Phase 2 completes, the next Get for that key sees the MEMORY replica first and avoids the SSD path.
Config
New gflags in
mooncake-store/src/master.cpp, added directly after the existing--offload_force_evictblock:Mirrored fields on
MasterConfig,MasterServiceSupervisorConfig,MasterServiceConfig, andMasterServiceConfigBuilder— same propagation pattern asoffload_on_evict_/offload_force_evict_.Master-side internals
Per-client pending state
Mirrors
LocalDiskSegment::offloading_objects. Add a sibling map:The promoting client is always the same client that holds the LOCAL_DISK replica (it is the only node that can read the SSD bytes), so the existing
LocalDiskSegmentkeyed by client UUID is the natural home.New RPCs
Three new master-service RPCs, mirroring
OffloadObjectHeartbeat/NotifyOffloadSuccess:PromotionAllocStartreusesAllocationStrategy::AllocateFrom(already used byMasterService::PutStartandCopyStart), so DRAM allocation goes through the same admission path as normal Puts.Get-path trigger
A small block added to
MasterService::GetReplicaList(master_service.cpp:758-794), executed only whenpromotion_on_hit_is true:TryPushPromotionQueueis a private method that does the gating:promotion_sketch_->increment(key) >= threshold, watermark check viaMasterMetricManager::instance().get_global_mem_used_ratio(), dedup againstshard->promotion_tasks, queue-limit check, then enqueue.Race and edge-case handling
PushPromotionQueueprevents disk-side eviction (mirrorsPushOffloadingQueue). If the disk replica is already pinned for unrelated reasons, refcnt simply increments and decrements normally.NotifyPromotionSuccesslooks up metadata; if the key is gone, the staged MEMORY replica is freed via the existingPutRevoke-style cleanup and no replica is committed.shard->promotion_tasks.contains(key). Frequency-sketch increments are still cheap.promotion_admission_thresholddefaults to 2, so single-shot reads don't trigger; combined with the natural delay of the heartbeat tick this is empirically not a concern but tested explicitly.PromotionAllocStartreturns an error; client logs and drops the task. Master's task entry is reaped on a configurable timeout (suggest 30 s), with refcnt decremented on the source replica.LocalDiskSegmenton client expiry (perc58d1f9).Backward compatibility
--promotion_on_hitdefaults tofalse. Existing deployments see zero behavior change.promotion_tasksmap is in-flight state, not persisted (consistent with howoffloading_tasksis treated). Restoring from a snapshot starts with an empty promotion queue; in-flight tasks are simply re-queued by the next Get on the same key.Metrics
Surfaced via the existing
MasterMetricManagerin the same shape as the offload counters that #1899 added:promotion_attempts_total(counter) — every Get that found only LOCAL_DISK replicas, regardless of whether the promotion fired.promotion_queued_total(counter) — successful PushPromotionQueue calls.promotion_completed_total(counter) — NotifyPromotionSuccess calls.promotion_failed_total(counter, by reason) — admission_gated, watermark_gated, queue_full, alloc_failed.promotion_in_flight(gauge) — sum ofshard->promotion_tasks.size()across shards.These are minimal but enough to validate the feature in production telemetry without further per-class plumbing.
Tests
**mooncake-store/tests/promotion_on_hit_test.cpp** (new) — mirrorsoffload_on_evict_test.cpp. Cases:promotion_queue_limitdistinct keys.**mooncake-wheel/tests/test_promotion_on_hit.py** (new) — mirrorstest_offload_on_eviction.py. End-to-end:threshold + 1rounds.Potential Next Steps
--promotion_on_hit. Self-contained PR.--promotion_drop_source).Before submitting a new issue...
@ykwd commented on GitHub (May 6, 2026):
Thanks for this great RFC. While there is an RFC (https://github.com/kvcache-ai/Mooncake/issues/2025) working on a similar area, may we need some collaboration in case there will be some conflict or duplicated work. @LujhCoconut
@yzhan1 commented on GitHub (May 6, 2026):
@ykwd Thanks for bringing that up. Besides that does the RFC look good to your or any other comments? I have some local diffs based on the RFC that's ready for PR.
Hi @Srinivasoo7, saw you created https://github.com/kvcache-ai/Mooncake/issues/2025 and wondering if you'd like to work on this together? Are you interested in taking v2/v3 mentioned in the RFC?
@Srinivasoo7 commented on GitHub (May 7, 2026):
Hi @yzhan1 ,
Glad to see this design land so quickly this is exactly the feature I opened #2025 to explore.
@ykwd thanks for flagging the overlap.
I like several parts of your proposal: async master-coordinated promotion, source replica pinning, heartbeat-pull, and the completion notification path. The symmetry with #1899 offload-on-evict structure is also the right call.
For a clean V1 I'd suggest keeping scope minimal:
Default-off --promotion_on_hit flag
Async best-effort promotion only no blocking on Get
Master-side metadata only (promotion tasks tracked per-shard on master, not on client)
Dedup in-flight promotion by key
Memory watermark guard (reuse existing offload_mem_watermark_high)
Source LOCAL_DISK refcnt pinning for the task lifetime
Tests covering: promotion success, allocation failure, and no behavior change when flag is disabled
CountMinSketch/frequency-gated admission, NotifyPromotionFailure fast-path, richer metrics, and v2/v3 policy can all be clean follow-up PRs once V1 lands.
Happy to collaborate on the implementation, I can take up the V2 and V3.
Also,
Would you be open to consolidating this into #2025 so we have a single tracking thread for Milestone 13 / #1883? Happy to update the #2025 body with your architecture and co-own the implementation
@yzhan1 commented on GitHub (May 7, 2026):
@Srinivasoo7 For sure, feel free to copy over and consolidate into one issue list. I don't seem to have edit access.
I will publish my changes for v1 soon and will tag you for review and context needed (if any) for v2/v3.
@Srinivasoo7 commented on GitHub (May 7, 2026):
@yzhan1 Sure, looking foward to the PR!
@yzhan1 commented on GitHub (May 10, 2026):
Hi @ykwd @Srinivasoo7 PTAL at #2071. Thanks!
@yzhan1 commented on GitHub (May 24, 2026):
@Srinivasoo7 Hi, now that v1 is complete, do you plan to work on v2/3? Let me know if you are busy working on other RFCs, I can continue to work on them if that's the case
@Srinivasoo7 commented on GitHub (May 24, 2026):
@yzhan1
Thanks for the headsup, I'll work on the v2 and let's collaborate on v3?
Let me know your thoughts!
@github-actions[bot] commented on GitHub (Aug 23, 2026):
This issue has had no activity for 90 days and will be closed in 7 days if there is no further activity. Please comment or react if it should stay open.
@github-actions[bot] commented on GitHub (Aug 31, 2026):
Closing due to 3 months of inactivity. If this is still relevant, please comment and we can reopen.