mirror of
https://github.com/kvcache-ai/Mooncake.git
synced 2026-11-05 01:17:55 +00:00
[GH-ISSUE #1200] [RFC]: Hot Standby Mode for Master Service Metadata High Availability #408
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#408
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 @Libotry on GitHub (Dec 12, 2025).
Original GitHub issue: https://github.com/kvcache-ai/Mooncake/issues/1200
Introduction
To address the issue where all metadata is lost after a master service failure and recovery, this solution proposes a hot-standby synchronization mechanism and a hybrid approach combining hot standby with snapshots, ensuring rapid data recovery following a master service failure.
Motivation
The current HA (High Availability) mode only supports rapid restart of the master service after a failure but cannot guarantee fast data recovery. The pain points of the current HA mode are as follows:
Goals:
Proposal
1. Core Design Approach
Use etcd as an intermediate reliability component to implement OpLog primary-standby synchronization:
2. Architecture Design
(1) Overall Architecture
The overall architecture diagram shows the interaction relationships between Primary Master, etcd Cluster, and Standby Master:
Architecture Description:
(2) Data Flow Diagram
The data flow diagram shows the complete flow from Client request to Standby synchronization:
Flow Description:
a. Client sends
PutEndrequest to Primary Masterb. Primary Master records operation through
OpLogManager, generating sequence_idc.
EtcdOpLogStorewrites OpLog to etcdd. etcd notifies Standby Master through Watch mechanism
e.
OpLogWatcherreceives events and passes toOpLogApplierf.
OpLogApplierchecks order and applies to Standby's metadata store(3) Failover Sequence
The failover sequence diagram shows the complete process from Primary failure to Standby promotion to Primary:
Flow Description:
a. Normal Operation: Primary maintains Lease, Standby continuously synchronizes OpLog through Watch
b. Primary Failure: Primary's Lease expires, etcd notifies Standby
c. Standby Promotion: Stop Standby service, initialize Lease, clean expired metadata, start leader election
3. Core Component Design
(1) OpLogManager (Primary Side)
Responsibilities:
Key Methods:
(2) EtcdOpLogStore (Primary Side)
Responsibilities:
etcd Key Design:
mooncake-store/oplog/{cluster_id}/{sequence_id}mooncake-store/oplog/{cluster_id}/latestmooncake-store/oplog/{cluster_id}/snapshot/{snapshot_id}/sequence_id(3) OpLogWatcher (Standby Side)
Responsibilities:
Key Methods:
(4) OpLogApplier (Standby Side)
Responsibilities:
Key Methods:
(5) HotStandbyService (Standby Side)
Responsibilities:
Key Methods:
4. OpLog Entry Data Structure
JSON Serialization Format:
5. Ordering Guarantee Mechanism
(1) Global Sequence Number (sequence_id)
OpLogManager(2) Key-Level Sequence Number (key_sequence_id)
(3) Out-of-Order Handling
When key_sequence_id out-of-order is detected:
6. Snapshot Integration
(1) Record Sequence ID During Snapshot
mooncake-store/oplog/{cluster_id}/snapshot/{snapshot_id}/sequence_id(2) OpLog Cleanup
7. Standby Service Integration
(1) Problem
In existing code, Standby only blocks and waits during leader election, without running Standby service to synchronize OpLog.
(2) Solution
In
MasterServiceSupervisor::Start():8. Lease Initialization When Standby Promotes to Primary
(1) Problem
Objects on Standby all have lease = 0 (because OpLog only contains PUT_END, not renewal information), and all objects will expire immediately after promotion to Primary.
(2) Solution
In
HotStandbyService::Promote():default_kv_lease_ttl)9. Memory Optimization: key_sequence_map_ Cleanup
(1) Problem
key_sequence_map_on Standby side is used to trackkey_sequence_idfor each key. After metadata is deleted, these entries are still retained, which may cause memory leaks during long-term operation.(2) Solution
Implement periodic cleanup mechanism:
REMOVEand more than 1 hour has passedPUT_ENDandPUT_REVOKEoperations are not cleanedKey Design Points Summary
Before submitting a new issue...
@Libotry commented on GitHub (Dec 15, 2025):
1. Problem & Assumptions
1.1 Problem
After a
Delete(or eviction) on the primary master:Deleteevent is not replicated to the standby master.We must never return data that belongs to some other key/object/tenant due to buffer reuse, even if we allow some metadata loss.
1.2 Accepted Semantic Constraints
We explicitly accept the following semantics:
Under these constraints, it is acceptable that:
2. Idea
We upgrade each replica from a “raw pointer” into a versioned capability:
Putof a key.versionis stored:ObjectMetadataon the master.ReplicaDescriptorreturned to clients.ReplicaDescriptor.Thus, even if the physical address is reused for a different object, the client will detect it and reject the replica.
3. Data Model Changes
3.1 Version Type
Version can be constructed as:
Requirements:
Putfor a given key gets a unique, monotonically increasing version.3.2 Replica Descriptor Extension
Extend
Replica::Descriptor(or equivalent) to carry version information:On
PutStart, the master generatesversion, stores it in metadata, and includes it in each replica descriptor.4. Write Path (Put) Design
4.1 Master: PutStart
Put(key, slices, config).MasterService::PutStart(key, slice_lengths, config):Version version = MakeVersion()for this key.versioninObjectMetadatafor this key.ReplicaDescriptor.version = versionfor each allocated replica.All replicas of the same key for this
Putshare the same version.4.2 Client: Writing to Store
We enhance
TransferWriteto enforce the following write order per replica:buffer_address.buffer_address + 8for lengthsize.There are two implementation options:
Option A: Two-step write (simpler):
TransferWritewrites the payload (slices) starting frombuffer_address + 8.Option B: Single write with reserved header:
sizeasheader + payload, and always writeversion || payloadin one TE operation.Option A is recommended initially because it avoids invasive changes to the allocation logic.
5. Read Path (Get) Design
We modify as follows.
5.1 Version Validation Before Payload Read
Given a chosen
ReplicaDescriptorwith:version_expected(generated at PutStart).buffer_address.size.The client performs:
This can be done via TE (small transfer) or via a combined read (see below).
version_actual == version_expected:version_actual != version_expected:INVALID_REPLICAand try another replica if available.INVALID_REPLICA/OBJECT_NOT_FOUND) and let the upper layer recompute.Implementation detail:
ReplicaDescriptorwith apayload_offsetfield, or enhanceTransferReadto accept an offset.5.2 Optimization
To minimize RTTs:
(8 + payload)bytes.6. Behavior Under Deletes and Failover
According to the accepted semantic constraints, we do not require writing tombstones at delete time.
6.1 Primary Delete Not Replicated, Memory Not Reused
ReplicaDescriptorwith(addr, version)for this key.Client behavior:
Since you accept “delete may be lost, old data may reappear”, this is allowed.
6.2 Primary Delete Not Replicated, Memory Reused
version_A.version_B.Client behavior:
version_B != version_A→ treat asINVALID_REPLICA.Thus, we never interpret key B’s data as key A’s data.
7. Failure Model & Safety Guarantees
Under the agreed semantics:
ReplicaDescriptor.This scheme therefore:
8. Overhead & Implementation Complexity
8.1 Overhead
Compared to typical KV cache object sizes (KB–MB), this overhead is negligible.
8.2 Implementation Complexity
ReplicaDescriptorand related RPC/serialization to carryversion.MasterService::PutStart, store inObjectMetadata.TransferWriteandTransferRead(or a thin wrapper) to:Getand batch-get helpers to respect version validation and error handling.9. Summary
@ykwd commented on GitHub (Dec 16, 2025):
Thanks for sharing the proposal. Unfortunately, this approach is not safe and does not actually guarantee the hard safety requirement you described, for two reasons:
First, RDMA reads and writes do not provide ordering and atomicity guarantees, which breaks the version-only validation scheme. In your design, correctness relies on the assumption that the first 8 bytes (the version) and the payload are written and observed atomically and in order. That assumption does not hold.
Second, the allocator does not guarantee alignment between successive allocations, which makes the embedded-version assumption invalid. Your scheme assumes that when a buffer is freed and later reused, the next allocation will reuse the same start address and layout, so that the version stored in the first 8 bytes corresponds exactly to the logical object boundary.
@github-actions[bot] commented on GitHub (Jun 10, 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 (Jun 18, 2026):
Closing due to 3 months of inactivity. If this is still relevant, please comment and we can reopen.