[Store] Add dynamic hot replica fanout - #3389
Conversation
|
Thanks for the PR. One question on the external usage path: since Master only accepts SubmitReplicaActionProposal and does not auto-propose from GetReplicaList (that heat observation is observe-only), could you clarify the expected caller scenario and end-to-end flow for external users? Specifically: Who is expected to observe heat and submit proposals in production (domain-local controller, Store client, sidecar, something else)? |
|
Thanks for raising this. We considered this because we do not want Master to become the hot-path decision maker for every read. The intended production flow is closed inside Mooncake, with the reader-side Store client path observing heat and proposing promotion; Master only arbitrates and fences the action. The PR now supports two internal execution paths:
sequenceDiagram
participant R as Reader Store client
participant M as Master
participant S as Source Store client
participant D as Target segment
R->>M: GetReplicaList / read object
R->>R: observe heat and pick local preferred target when available
R->>M: SubmitReplicaActionProposal(requester_client_id, preferred_target_segment, allow_reader_local_promotion)
M->>M: validate version, quota, source, target, lease
alt reader-local target is owned by requester
M-->>R: lease(reader_local_promotion=true, task_id=0)
R->>M: CopyStart(source, target)
M->>M: recheck requester owns target and stage metadata
R->>D: async write from read buffer
R->>M: CopyEnd
else source-side fallback
M->>S: enqueue REPLICA_COPY task
M-->>R: lease(reader_local_promotion=false, task_id)
S->>M: CopyStart(source, target)
S->>D: transfer object
S->>M: CopyEnd
end
So the answer to “who observes heat and submits proposals” is: the Mooncake reader-side Store client path. Master remains the consistency/lease authority, but it does not auto-propose from For “who picks up the task”: in the source-side baseline, the selected source client picks up the existing Could you take a look at whether this split matches the direction you expect? I think keeping both paths in this PR is useful: source-side copy is the conservative fallback, while reader-local promotion avoids duplicate transfer when the reader has already paid the read cost, and both paths still use the same |
|
Thanks for the write-up. I am still a little bit confused about the following issues: 1. Who is supposed to submit the replica-expansion proposal? My reading is that this is meant to stay inside Mooncake: the reader-side Store client observes heat and calls Could you confirm that? I ask because the production loop is not wired on the Store 2. Why should the client make the “this key is hot enough to expand” decision? A Store client can only see its own access frequency for a key. That seems like a weak signal for replica-count expansion:
So I am not sure why heat admission belongs on the client. If the concern is Master becoming the hot-path decision maker on every read, that is understandable — but the current code already pays most of that cost. In In |
|
Thanks for the questions. I agree the previous description was not clear enough and may have made the reader-side path look like the hotness decision maker. Let me separate the two parts.
For this PR, the dynamic replication loop is intended to be closed inside Mooncake Store. We are not introducing an external scheduler or framework integration contract in this phase.
The intended model is centralized admission with distributed execution. The reader-side Store client is only a trigger. Master is the admission authority because it owns the aggregated read-observation signal from the To avoid turning Master into a heavy execution bottleneck, Master only does lightweight admission and control-plane work: maintain a bounded per-key heat window, check threshold / pending / cooldown / replica limit / version / placement, then grant a lease and enqueue a copy task. The actual data movement remains distributed and asynchronous: the selected source Store worker picks up I am also removing reader-local promotion from this PR. Preserving foreground read latency is the highest priority, and reader-local promotion needs a more careful async buffer-lifetime design. This PR will keep only the source-side async copy path. sequenceDiagram
participant Reader as "Reader / Store client"
participant Master as "Mooncake Master"
participant Source as "Source Store worker"
participant Target as "Target segment"
Reader->>Master: "Get / BatchGet"
Master->>Master: "Update per-key heat window"
Master-->>Reader: "Replica list"
alt "Heat threshold not reached"
Master->>Master: "No expansion"
else "Heat threshold reached"
Master->>Master: "Admission: pending / cooldown / limit / version / placement"
Master->>Master: "Select source replica and target segment"
Master->>Source: "Queue REPLICA_COPY task"
Source->>Master: "FetchTasks"
Source->>Master: "CopyStart"
Source->>Target: "Async copy"
Source->>Master: "CopyEnd"
Master->>Master: "Mark dynamic replica readable"
end
|
|
Thanks for the explanation. I understand now. |
8de9dc4 to
cce119a
Compare
cce119a to
23357e8
Compare
Icedcoco
left a comment
There was a problem hiding this comment.
I re-reviewed the latest head (23357e8d). The regular CopyStart compatibility regression from the previous revision has been fixed by restricting the zero-target early return to dynamic copies.
I verified the focused MasterServiceTest.CopyStart case and reran the complete master_service_test, together with the dynamic replication, tenant quota, task manager, and task executor tests. All passed locally, and the current CI checks are green.
No blocking issues found. LGTM.
Description
RFC: #3388
This PR adds the first-stage dynamic hot replication path for Mooncake Store.
The target problems are hot objects becoming single-node bottlenecks and repeated remote-domain reads paying avoidable access cost. This PR focuses on the baseline dynamic multi-replica fanout path for immutable MEMORY objects. Cross-domain placement fields remain reserved for the next phase; non-empty requester/target domain hints are rejected in this first-stage PR so the baseline path cannot accidentally claim domain-aware placement.
The implementation uses centralized admission with distributed execution. Master records a bounded per-key heat window from the
Get/BatchGetpath viaGetReplicaList/BatchGetReplicaList. When the heat threshold is crossed in enforce mode, the read path only queues a lightweight admission trigger. A Master background worker validates metadata, object version, replica limits, in-flight state, placement, and lease validity before creating an asynchronous copy task. The source-sideCopyStartpath reserves quota and now rolls back dynamic pending state if that reservation fails.Copy execution is source-side asynchronous in this PR. Master creates the existing
REPLICA_COPYtask for the selected source client, and the Store task worker drivesCopyStart -> transfer -> CopyEnd. Reader-local promotion is intentionally left out of this PR because foreground read latency has higher priority, and that path needs a separate async buffer-lifetime design.The PR includes:
Get/BatchGetpath through a lightweight background admission queue;CopyStart,CopyEnd, andCopyRevokevalidation;CopyStart;CopyStartfails before task creation;This PR deliberately excludes TCP transport optimization, RL weight transport, external framework integration, reader-local promotion, a separate shrink controller, active reclaim policy changes, and a full cross-domain cost model.
Shrink is intentionally delegated to the existing memory eviction/reclaim path. When eviction removes a dynamic replica, Master forgets the dynamic replica record and records a short recreate cooldown so hot-read admission does not immediately re-add the capacity that reclaim just freed.
Rollout note: dynamic enforce mode should be enabled only after both Master and Store workers include this change. Mixed deployments where old Store workers consume dynamic
REPLICA_COPYpayloads are not supported by this first-stage PR.Replica Selection Note
Dynamic replication creates additional replicas; client-side read selection is still handled by the existing replica selection path. For remote MEMORY replicas, Mooncake keeps the first remote replica unless
MC_STORE_REPLICA_SCORING=1is set or a scorer is injected. The built-in scorer prefers RDMA over TCP, but equal-score replicas still keep Master return order, so it is not equal-cost load spreading.For tests or deployments that depend on remote-replica preference, enable
MC_STORE_REPLICA_SCORING=1together with dynamic replication. True same-tier fanout still requires local placement, an injected load/hash-aware scorer, or a follow-up same-tier spreading policy.Module
mooncake-transfer-engine)mooncake-store)mooncake-ep)mooncake-pg)mooncake-integration)mooncake-p2p-store)mooncake-wheel)mooncake-common)mooncake-rl)Type of Change
How Has This Been Tested?
Test commands:
./scripts/code_format.sh cmake --build build-dynamic-shrink --target dynamic_replication_test task_executor_test task_manager_test -j32 ctest --test-dir build-dynamic-shrink -R 'dynamic_replication_test|task_executor_test|task_manager_test' --output-on-failure git diff --checkTest results:
dynamic_replication_test,task_executor_test,task_manager_test, format, andgit diff --checkpassed.dynamic_replication_testnow has 27 cases covering accepted Master-side hot admission, async enforce-modeGetandBatchGetpath auto expansion, observe-mode dry run behavior, max replica suppression, below-threshold rejection, proposal idempotency, conflicting proposal-id reuse, short proposal deadline clamping, first-stage rejection of domain hints, copy lifecycle completion, invalid-target cleanup, bounded heat-window cleanup, stale dynamic task rejection, non-source dynamicCopyStartrejection, failed dynamicCopyStartpending cleanup, stale task isolation from newer pending state, expired dynamic copy cleanup, expired dynamic pending isolation from ordinary Copy, version/lease fencing for dynamicCopyStart/CopyEnd/CopyRevoke, eviction-driven dynamic replica shrink cooldown, source stable tie-breaking, and target host anti-affinity.task_manager_testnow covers retiring a pending task without later assigning it to a worker.Checklist
./scripts/code_format.shpre-commit run --all-filesand all hooks passTouched C++ files build in
dynamic_replication_test,task_executor_test, andtask_manager_test. Full pre-commit has not been run in this pass.AI Assistance Disclosure
OpenAI Codex helped research the design, draft the RFC, implement the initial proposal/lease flow, run focused tests, and perform self-review. The human submitter is responsible for reviewing and defending the change before merge.