Configuration Reference#
This document collects the main runtime knobs exposed by the current implementation.
Tenant Policy Precedence#
Tenant-scoped routing and resource policy should be authored through mooncake-store-rs-admin policy ...
and stored in durable metadata. Runtime-local knobs remain available as compatibility fallbacks.
Precedence is:
admin-managed tenant policy in metadata
legacy compatibility metadata reads where still supported during migration
runtime-local builder / Python / standalone client fallback values when metadata does not provide the relevant section
Keep this distinction clear:
tenantselects the default scope used for request builders and startup policy lookuprequest-scoped APIs and per-request
ReplicationPolicyremain normal execution-time inputslocal route/resource knobs are not the preferred long-term policy authoring surface
strict quota usage/accounting inspection now comes from admin/metadata surfaces, not builder fields
Admin strict-quota inspection and repair#
The admin surface now exposes metadata-backed strict quota inspection plus explicit repair commands:
mooncake-store-rs-admin quota state --tenant <tenant> [--domain <domain>] [--object-set <set>]mooncake-store-rs-admin quota object --tenant <tenant> [--domain <domain>] [--object-set <set>] --key <logical-key>mooncake-store-rs-admin quota reservations --tenant <tenant> [--domain <domain>] [--object-set <set>] [--state pending|finalized|aborted]mooncake-store-rs-admin quota abort --tenant <tenant> [--domain <domain>] [--object-set <set>] --reservation-id <id> [--dry-run]mooncake-store-rs-admin quota reconcile --tenant <tenant> [--domain <domain>] [--object-set <set>] [--dry-run]
Operational notes:
quota state and reservation queries resolve to the tenant-root scope because mutable quota state is tenant-root metadata in Phase 1
object-accounting lookups still accept nested selectors so operators can specify the logical object namespace they care about
reconcile currently aborts expired pending reservations and finalizes pending reservations whose authoritative route + accounting state is already visible
finalized and aborted reservations are retained for a bounded terminal window, then expire from Redis automatically; the default terminal TTL is
24hPendingreservations still rely on reconcile / abort paths rather than Redis TTL so an in-flight write is never deleted out from under finalizecrates/mooncake-store-rs-metadataexposesRedisMetadataConfig::tenant_quota_terminal_ttl(...)for deployments that want a different terminal retention windowreservation listing prunes dangling reservation index entries opportunistically when the backing reservation record is already gone
other mismatches remain operator-visible and are reported as skipped rather than repaired speculatively
the admin HTTP surface rejects requests whose declared
Content-Lengthexceeds1 MiBwith413 Payload Too Large; because the server does not drain the remaining body, it responds withConnection: close
Admin maintenance#
Redis-backed and etcd-backed deployments support explicit stale segment maintenance. The same admin server can also run tenant-quota reservation reconcile for an explicit tenant list.
Relevant surfaces:
mooncake-store-rs-admin cleanup-stale-segmentsmooncake-store-rs-admin server --cleanup-interval-ms <ms> --cleanup-batch-size <n>mooncake-store-rs-admin server --quota-reconcile-interval-ms <ms> --quota-reconcile-tenant <tenant>
Operational model:
the default metadata keyspace is
mc/store-rs/v2;v2is the Redis schema boundary for TTL-backed client resource hashes and intentionally does not read or migrate oldv1keysRedis client resource hashes use TTL as the liveness signal
Redis stores the lease and owned segment records in that single client resource hash; when the lease TTL expires, Redis removes both the lease and the segment records
etcd lease keys do not expire automatically; admin re-checks the stored
expires_at_msfield when due work arrivesetcd segment keys do not use TTL, but they are stored under the owning client runtime namespace
lease publish and heartbeat refresh now also update a backend-native expiry work index under the same metadata keyspace: Redis uses one sorted set, etcd uses
by-runtime+ lexicographically orderedby-timekeysthe admin maintenance loop consumes due entries from that work index, re-checks lease liveness, and removes owner-scoped resource metadata only when the backend still has stale state to repair
same-epoch lease reclaim after an expired lease key is allowed when that epoch is still the historical HWM and no higher live epoch exists, so heartbeat repair does not fail with
StaleEpochafter a TTL gaptenant quota reconcile is intentionally opt-in per tenant because the current metadata model has no bounded global tenant-work index for the admin plane to consume safely
Admin tracing fanout#
mooncake-store-rs-admin server is the cluster-level entry point for dynamic Jaeger tracing control.
Operators should send tracing commands to the admin HTTP server instead of addressing every
store node manually:
mooncake-store-rs-admin tracing status --admin-url http://<admin-host>:<port>mooncake-store-rs-admin tracing on --admin-url http://<admin-host>:<port> [--endpoint <otlp-endpoint>] [--sample-ratio <0..1>]mooncake-store-rs-admin tracing off --admin-url http://<admin-host>:<port>mooncake-store-rs-admin tracing flush --admin-url http://<admin-host>:<port>
The admin server discovers store-node tracing endpoints from live client leases. Store runtimes
publish only the system label metrics_port=<port> when the metrics HTTP endpoint is enabled.
The host is derived from the existing lease endpoint data: control_addr first, then
endpoints.rpc_address. This avoids duplicating another reachable-host field in metadata.
Compatibility behavior:
metrics_portis stored insideClientEndpointSet.labels, so the serialized lease schema does not gain a new required fieldnewer admin servers use
metrics_portwhen it exists and fall back to port9300for older leases that predate the labelstore startup removes any user-supplied
metrics_portlabel and overwrites it with the actual bound metrics port when metrics are enabledstore runtimes with metrics disabled do not publish
metrics_port
Server maintenance defaults:
--cleanup-interval-ms 5000--cleanup-batch-size 128--cleanup-interval-ms 0disables the background maintenance worker--quota-reconcile-interval-ms 0disables background tenant quota reconcile--quota-reconcile-tenant <tenant>can be repeated; when unset, no tenant quota reconcile worker is started
mooncake-store-rs-admin accepts every CLI parameter through an environment
variable as a fallback. Explicit CLI flags override environment values.
Global admin knobs:
CLI flag |
Environment variable |
Default |
Meaning |
|---|---|---|---|
|
|
required |
Store-RS metadata URL ( |
|
|
command-dependent |
admin HTTP endpoint used by route-migration client commands |
|
|
default keyspace |
metadata keyspace |
|
|
tracing default |
tracing filter for the admin process |
Server and migration knobs:
CLI flag |
Environment variable |
Default |
Meaning |
|---|---|---|---|
|
|
|
admin HTTP bind address |
|
|
|
stale-segment maintenance interval; |
|
|
|
stale-segment cleanup batch size |
|
|
|
tenant-quota reconcile interval; |
|
|
none |
comma-separated tenants for background quota reconcile |
|
|
required |
route authority runtime id |
|
|
required |
tenant scope |
|
|
none |
optional domain scope |
|
|
none |
optional object-set scope |
|
|
required |
logical object key |
|
|
required |
source segment for route migration |
|
|
required |
comma-separated copy target segments |
|
|
required |
move target segment |
|
|
required |
executor runtime id |
|
|
admin queue default |
per-task retry override |
|
|
required |
route-migration task id |
Policy and quota knobs:
CLI flag |
Environment variable |
Default |
Meaning |
|---|---|---|---|
|
|
command-dependent |
tenant scope |
|
|
none |
optional domain scope |
|
|
none |
optional object-set scope |
|
|
|
resolve effective policy fallback chain |
|
|
none |
optimistic policy version guard |
|
|
|
policy audit author |
|
|
none |
optional tenant filter |
|
|
unchanged |
WRH route-authority fanout |
|
|
unchanged |
route control mode |
|
|
unchanged |
tenant quota byte limit |
|
|
unchanged |
tenant quota object limit |
|
|
unchanged |
routed batch per-tenant item cap |
|
|
unchanged |
routed batch byte cap |
|
|
unchanged |
routed batch burst item cap |
|
|
unchanged |
per-batch inflight byte cap |
|
|
unchanged |
default placement replica count |
|
|
unchanged |
default local placement preference |
|
|
unchanged |
default same-node allocation preference |
|
|
unchanged |
comma-separated preferred storage owners |
|
|
unchanged |
comma-separated preferred segments |
|
|
required |
logical object key |
|
|
none |
reservation state filter |
|
|
required |
quota reservation id |
|
|
|
inspect without changing metadata |
|
|
runtime default |
OTLP endpoint passed to store tracing enablement |
|
|
runtime default |
tracing sample ratio passed to store tracing enablement |
|
|
|
per-node admin fanout timeout |
|
|
|
maximum store-node fanout count for one request |
Boolean admin environment variables use falsey parsing: 0, false, no,
and off disable the flag; other non-empty values enable it.
Admin route-migration queue#
The standalone admin HTTP server keeps explicit route-migration tasks in process memory and retries transient executor failures automatically while the server remains alive.
Environment knobs:
Variable |
Default |
Meaning |
|---|---|---|
|
|
default retry budget for tasks that do not override |
|
|
base delay used by the admin retry backoff |
|
|
maximum delay cap for the admin retry backoff |
|
|
background admin polling interval for task dispatch and executor status refresh |
Notes:
these knobs are read by
mooncake-store-rs-admin serverthroughAdminService::from_config(...)the same defaults apply to tasks submitted through the long-lived admin HTTP server
task state is not persisted in metadata, so these settings control a live in-memory queue rather than a durable scheduler
StoreClientBuilder#
StoreClientBuilder is the main construction surface for Rust clients.
Method or Field |
Default |
Notes |
|---|---|---|
|
required |
|
|
|
controls compatibility matching |
|
empty |
filled from transport when possible |
|
none |
filled from transport when possible |
|
|
use |
|
|
default tenant for request builders and startup policy lookup |
|
|
storage and scratch memory layout |
|
none |
required for remote transfer paths; low-level Rust transport is wired explicitly |
|
none |
used to create transports for peers |
|
disabled |
enables routed placement |
|
|
cluster-level route-control mode (EmbeddedWrh or MetadataOnly); fixed at startup, not overridable per-tenant |
|
|
compatibility fallback WRH route-authority fanout; metadata tenant policy wins when present; must be |
|
|
background refresh interval for the live-client membership snapshot; |
System-managed behavior:
the builder adds
route=truewhen missingthe control-plane address label is published automatically
if transport is present, RPC address and segment name are inferred when possible
build(...)prewarms the live-client membership snapshot before serving requeststhe background membership worker refreshes that snapshot after startup
LocalMemoryConfig#
LocalMemoryConfig controls the memory that a client exposes to the store.
Field |
Default |
Meaning |
|---|---|---|
|
|
capacity for object storage |
|
|
temporary space for transfer staging |
|
|
placement string passed into transport registration |
|
|
tags published with the segment |
|
|
allocation alignment |
|
|
delayed reclaim window for scheduled cleanup; storage-owner eviction pressure may reclaim stale/orphan local bytes earlier after an authoritative active route no longer references them; route-missing ghosts are not released without a separate confirmed-absent proof |
|
|
start background eviction when local usage reaches this percentage |
|
|
stop background eviction after usage falls to this percentage |
|
|
background storage-owner eviction polling interval; |
|
|
override hugepage enablement for local storage and scratch |
|
|
override hugepage size; |
Validation rules:
scratch_bytesmust be greater than zerolocationmust not be emptyeviction_high_watermark_percentmust be in1..=100eviction_low_watermark_percentmust be lower thaneviction_high_watermark_percenthugepage size must be either
2 MiBor1 GiB
storage_bytes may be 0. This is how scratch-only rw clients are configured when storage and inference are deployed as separate roles.
Storage-role normalization:
storage=truerequiresstorage_bytes > 0if
storage_bytes=0and the storage label is missing, the runtime normalizes it tostorage=falsea scratch-only client may still enable
routed_writes; placement will choose livestorage=trueruntimes and will not use stale segment metadata as a candidate source
Hugepage behavior:
if
hugepage_enabledisSome(true), the client allocates native local memory withMAP_HUGETLBif
hugepage_size_bytesis set, hugepage mode is implicitly enabledif both fields are
None, the runtime falls back toMC_STORE_USE_HUGEPAGEandMC_STORE_HUGEPAGE_SIZE
Compatibility entrypoints expose the same background eviction watermarks:
Surface |
High watermark |
Low watermark |
|---|---|---|
Standalone client |
|
|
Python |
|
|
Python config dict |
|
|
|
|
|
Startup registration behavior:
classic_te+ RDMA keeps startup storage-region planning NUMA-aware whenlocationtargets host memory andnuma_awareremains enabledonly transports that opt into parallel startup registration fan out initial storage into multiple segments; other transports keep the historical single-segment startup layout
when startup planning produces multiple initial storage segments, the runtime allocates and registers those extra segments in parallel, then publishes the full local segment set after local registration completes
under
classic_te+ RDMA, startup storage registration pre-touches pages before MR registration when the total startup storage registration volume reaches4 GiBor moreordinary scratch-region registration still follows the transport registration limit split logic; the startup fast path is only for storage segments
Transport Backend Selection#
The compatibility layer supports two real data-plane backends:
Backend |
Compatibility Value |
Notes |
|---|---|---|
TENT |
|
opt-in compatibility backend |
Classic TE |
|
runtime-selectable compatibility backend |
Selection surfaces:
Surface |
Knob |
|---|---|
Environment |
`MC_STORE_RS_TRANSPORT_BACKEND=tent |
Standalone client |
`–transport-backend tent |
Python compatibility |
|
Notes:
explicit CLI or Python values override the environment variable
when no explicit selection is present, the compatibility layer defaults to
classic_teclassic,classic-te, andteare accepted as compatibility aliases by the parserset
MC_STORE_RS_GID_INDEX=<n>whenclassic_teover RDMA must use a non-default RoCE GID index; Store-RS forwards it to upstreamMC_GID_INDEXfor
classic_tewith Redis-backed transport metadata, Store-RS derives the upstream TE Redis key prefix from the default tenant and forwardstenants/<tenant>as the Mooncake metadata cluster idfor
classic_tewithP2PHANDSHAKE, segment metadata keeps the configured logicalsegment_nameand also publishes the TEtransport_endpoint(ip:rpc_port) used when peers open the segmentlow-level Rust transport construction remains explicit; runtime backend selection is only a compatibility-layer feature
current upstream SGLang Mooncake integration does not forward
transport_backendfrom--hicache-storage-backend-extra-config; useMC_STORE_RS_TRANSPORT_BACKENDwhen SGLang real mode must selecttentorclassic_te
Reconnect behavior:
both backends repair local transport metadata after Redis connectivity returns and the heartbeat repair path runs
classic_terecreates its transport runtime before republishing local bufferstentalso recreates its transport runtime before re-registering the local buffers it still ownspeer restarts that invalidate a cached remote segment handle are repaired on demand: the read path drops the stale handle, reopens by the segment’s transport open name, and only quarantines that runtime if the fresh reopen still fails
segment metadata lookup starts from live clients. In Redis, segment records share the owner client hash TTL with the lease; in every backend, a leftover segment record whose owner lease is gone is ignored for allocation, preferred-segment resolution, and HTTP remote-runtime resolution.
routed writes apply the same stale-handle refresh once before escalating to outer soft-pin retry or failover, so a restarted live peer does not poison the cached remote-segment state
if Redis restarts from an empty dataset, surviving storage clients republish both lease state and segment metadata into their client resource hash during recovery
local memory registration refreshes the runtime lease for at least 30 seconds before publishing segment metadata, so slow startup registration does not publish into an expired Redis client resource hash
requests that arrive while Redis is unavailable can still fail fast; recovery is designed for self-healing after metadata service returns, not for serving through a metadata blackout
Route Control#
Mode |
Default |
Behavior |
|---|---|---|
|
yes |
client-side route authority selection with mirrored top-k publication, ranked authority reads, and a prewarmed background-refreshed membership snapshot |
|
no |
route reads and writes go directly to metadata |
Use MetadataOnly for bring-up and debugging. Use EmbeddedWrh for normal deployments.
Embedded route authorities maintain in-memory indexes for scope and reuse-identity lookups. Hot-path existence and prefix-reuse queries resolve through exact route-authority reads instead of scanning the metadata backend or the full local route map. Batched existence checks stop at the mirrored route_topk authority set, so common misses do not fan out to every live authority.
Routed Placement#
Routed placement is enabled through:
let planner = PlacementPlanner::new(metadata.clone()).require_label("storage", "true");
let client = StoreClientBuilder::new(metadata, "router")
.routed_writes(planner, 2);
PlacementPlanner#
Method |
Default |
Meaning |
|---|---|---|
|
|
label key used to scope candidate sets |
|
none |
filters placement candidates |
Planner behavior:
only active leases are considered
compatibility descriptors must match
candidates are ranked with rendezvous hashing
ReplicationPolicy#
ReplicationPolicy overrides placement behavior for a single request.
Field |
Default |
Meaning |
|---|---|---|
|
|
use the client default |
|
|
request soft pin behavior |
|
empty |
request-scoped segment preference; hard by default, best-effort when |
|
empty |
prefer specific storage owners |
|
|
bias allocation toward the same node |
|
|
prefer the local node before remote spillover |
If replica_count is not set:
local-only clients default to one replica
routed clients default to the replica count passed to
routed_writes(...)
Keep the distinction clean:
replica_countcontrols how many data replicas a write publishesroute_topkcontrols how many route authorities keep mirrored route metadatarequest-level
preferred_segmentsis the explicit pinning surface for a single writetenant policy
placement.preferred_segmentsis only a default hint and falls back when the segment is missing or staletenant-policy
preferred_segmentsmust use the exact activesegment_name; astable_idis not a valid segment identifier
Labels and Naming#
The runtime and examples use these conventions:
Key |
Purpose |
|---|---|
|
opt a client into routed placement candidate sets and enable local background/synchronous eviction when it owns storage memory |
|
default placement scope label |
|
optional route-authority scope |
Recommended practice:
treat
stable_idas the persistent node identitytreat
segment_nameas the current process-owned segment identityassign a distinct metadata keyspace per deployment
Metadata Backends#
Rust#
Rust code constructs metadata backends directly:
RedisMetadataBackendEtcdMetadataBackendInMemoryMetadataBackend
Both Redis and etcd backends accept MetadataKeyspace.
Python compatibility layer#
The Python compatibility layer accepts metadata URLs:
Scheme |
Meaning |
|---|---|
|
Redis store metadata |
|
etcd store metadata |
Notes:
HTTP metadata endpoints are not supported
Redis store metadata accepts URL-embedded credentials or
MC_REDIS_USERNAME/MC_REDIS_PASSWORDwhen
metadata_url(arg7) is etcd, the Transfer Engine still needs its own metadata attransport_metadata_url(arg2): passP2PHANDSHAKEforclassic_te(default) orredis://...fortent
Redis authentication#
Redis compatibility list operations are fail-closed and bounded. Indexed sets accept at most 4096 members per call, while legacy key migration scans accept at most 64 pages and 4096 matching keys. Larger namespaces must use an exact or paginated maintenance surface instead of relying on a collect-all list.
Use MC_REDIS_PASSWORD for password-only Redis deployments, including cloud Redis instances that authenticate the default user:
export MC_REDIS_PASSWORD='<redis-password>'
mooncake-store-rs-client \
--local-hostname 127.0.0.1 \
--metadata-url redis://redis.example.com:6379/0 \
--stable-id store-a
Use MC_REDIS_USERNAME together with MC_REDIS_PASSWORD when Redis ACLs require a named user:
export MC_REDIS_USERNAME='<redis-username>'
export MC_REDIS_PASSWORD='<redis-password>'
URL-embedded credentials are also accepted:
redis://username:password@redis.example.com:6379/0
If both forms are present, credentials in the URL take precedence. Prefer environment variables when passwords contain reserved URL characters such as @, /, : or #; URL-embedded credentials must be percent-encoded. Route namespaces redact URL credentials before they are used for routing metadata identity.
For Redis 5 password-only deployments, the metadata backend also tolerates connections where a username was supplied by configuration but the server accepts only legacy AUTH <password>; the client retries with password-only auth after the server rejects the username form.
Standalone Client Configuration#
mooncake-store-rs-client run accepts its runtime knobs either as CLI flags or as
environment variables. Explicit CLI flags override environment values. For
environment-only startup, keep the run subcommand because the root command with
no arguments still renders help.
CLI flag |
Environment variable |
Default |
Meaning |
|---|---|---|---|
|
|
required |
hostname or IP published for this runtime |
|
|
required |
Store-RS metadata URL ( |
|
|
|
Transfer Engine metadata input ( |
|
|
|
local storage capacity published by this runtime |
|
|
|
local scratch capacity for transfer staging |
|
|
|
transport protocol such as |
|
|
empty |
RDMA device list passed through compatibility setup |
|
|
backend chooses |
fixed real data-plane transport port |
|
|
|
real transport backend; accepts |
|
|
generated |
persistent runtime identity |
|
|
|
startup lifecycle state |
|
|
|
default tenant scope |
|
|
|
default domain scope for scoped object identity |
|
|
|
default object-set scope for scoped object identity |
|
|
none |
comma-separated runtime labels such as |
|
|
|
enable routed writer mode; env accepts falsey values such as |
|
|
|
default routed-writer replica count |
|
|
|
WRH route-authority fanout; must be |
|
|
default keyspace |
metadata keyspace |
|
|
generated from transport/runtime |
explicit local segment name |
|
|
|
lease TTL published by the standalone heartbeat loop |
|
|
|
heartbeat loop interval |
|
|
|
dispatcher and routed operation timeout |
|
|
adaptive |
compatibility-managed registration timeout override |
|
|
|
heartbeat publish timeout |
|
|
|
transfer no-progress timeout |
|
|
disabled |
in-process metrics bind address |
|
|
disabled |
dummy compatibility gRPC server address |
|
|
disabled |
enable hugepage-backed local store memory; standalone env accepts falsey values such as |
|
|
backend default |
hugepage size such as |
|
|
tracing default |
standalone tracing filter |
|
|
|
route-control fallback; accepts |
|
|
|
drain owned routes during graceful shutdown; env accepts falsey values such as |
mooncake-store-rs-client stats also supports MC_STORE_RS_STATS_SERVER for
--server and MC_STORE_RS_STATS_JSON for --json; the JSON switch uses the
same falsey-value parsing as the standalone runtime boolean flags.
Python Compatibility Configuration#
MooncakeDistributedStore.setup(...) accepts the core store knobs plus Python-specific convenience parameters.
Important Python-only compatibility knobs:
tenant, domain, and object_set form the default namespace scope used by Python compatibility read/write operations when a request does not provide a more specific scope. route_topk is kept for compatibility, but admin-managed tenant policy in metadata is the preferred place to author tenant-scoped routing policy. route_control is a cluster-level deployment setting fixed at startup.
Parameter |
Meaning |
|---|---|
|
persistent client identity |
|
default tenant scope |
|
default domain scope; falls back to |
|
default object-set scope; falls back to |
|
lease labels such as |
|
enable routed placement from Python |
|
default replica count when routed writes are enabled |
|
WRH route-authority fanout; must match the policy already stored in the metadata keyspace |
|
choose |
|
fixed real data-plane TCP port for real-mode peers |
|
enable hugepage-backed local store memory |
|
hugepage size for local store memory; accepts |
The config-dict path accepts the same compatibility knobs. For port pinning, both transport_rpc_port and rpc_server_port map to the real-mode backend data-plane port.
local_hostname accepts either:
a plain hostname such as
10.0.0.15host:port, which is normalized intolocal_hostname=hostplustransport_rpc_port=port
If local_hostname already embeds a port and transport_rpc_port or rpc_server_port is also provided, the values must match. The compatibility layer rejects mismatches instead of silently publishing an invalid real-mode endpoint.
Port role reminder:
transport_rpc_port/rpc_server_portis used by real clients and maps to the selected backendrpc_server_portclient_server_addressbelongs to the dummy compatibility server and is not used by real-mode peersmetrics_addronly exposes/metrics
For cross-host or cross-container real-mode deployments, set a reachable local_hostname together with a fixed transport_rpc_port.
Setup positional layout#
setup(local_hostname, transport_metadata_url, global_segment_size, local_buffer_size, protocol, rdma_devices, metadata_url).
transport_metadata_url— Transfer Engine metadata input. Acceptsredis://...orP2PHANDSHAKE. Default isP2PHANDSHAKEwherever a default is expressible: the Python dict-form (theMC_STORE_RS_TRANSPORT_METADATA_URLenv is honored as fallback before the default), the standalone CLI (no--transport-metadata-urlflag and no env set), and the bench. The Python positionalsetup(...)requires it explicitly because Python disallows a defaulted positional before a required positional; pass the literal string"P2PHANDSHAKE"to use the default. The dict-form also accepts the upstream Mooncake keymetadata_serveras an alias.metadata_url— Store-RS metadata URL. Required. Acceptsredis://...oretcd://.... The dict-formsetup({...})also accepts the upstream Mooncake keysmaster_server,master_server_addr, andmaster_server_addressinterchangeably as aliases;setup()raises a clearTypeErrorif none is provided.
transport_metadata_url is for the Transfer Engine only and never influences Store-RS routing or metadata decisions.
The compatibility client defaults lease_ttl_ms to 30000. Keep the heartbeat interval comfortably below that TTL so dead peers converge quickly without triggering avoidable churn.
Timeouts now converge on one shared compatibility helper so the Python wrapper, standalone client, dummy client, and transport builder all resolve the same knobs with the same precedence rules:
CLI override, when a standalone binary exposes the flag
explicit environment variable
built-in default
The compatibility layer exposes five timeout scopes:
Knob |
Default |
Scope |
Meaning |
|---|---|---|---|
|
|
dispatcher request budget, routed read/write request budget, dummy fallback |
outer per-request deadline shared across replica failover |
|
|
startup |
registration-specific timeout budget; explicit override wins over the adaptive default |
|
|
standalone client heartbeat / state publish |
dedicated health-channel publish budget |
|
|
TENT / classic transfer engine |
inner stall detector for one transfer slice or batch wait |
|
|
dummy gRPC client |
dummy RPC budget; falls back to |
Design intent:
request timeout is the outer deadline for one logical store request
startup timeout is the registration budget for compatibility-managed memory registration work; when unset, the runtime derives it from the current registration size with a conservative
20sfloor so small scratch-only startup does not fail under host-side contentionheartbeat timeout is independent, so a slow health publish does not block the shared data path
transfer stall timeout is not a whole-request timeout; it only detects no-progress transport stalls
dummy RPC timeout follows request timeout unless explicitly overridden, so compatibility scripts do not hang forever on one slow server
Standalone clients now retry failed heartbeat publishes instead of exiting on the first timeout. When cloud metadata links or long transfers need more head room, raise the matching timeout scope instead of stretching every timeout.
Control-plane RPC clients run on a dedicated shared Tokio runtime instead of a
single global caller lock. Use MC_STORE_RS_CONTROL_PLANE_THREADS to tune the
client worker count when a deployment needs more concurrent route / allocator
RPCs or when an embedded client should keep its thread footprint smaller. The
default is 2; values must be positive integers.
Each runtime also serves peer control-plane requests on a separate multi-thread
Tokio runtime. Use MC_STORE_RS_CONTROL_PLANE_SERVER_THREADS to tune the
server worker count when routed writers create high allocator / route-authority
fanout. The default is 4; values must be positive integers.
Python Local Hot Cache#
The local hot cache lives inside the Python compatibility runtime and the standalone dummy daemon. It stays disabled unless MC_STORE_LOCAL_HOT_CACHE_SIZE is set to a positive integer.
Variable |
Default |
Meaning |
|---|---|---|
|
disabled |
total cache capacity in bytes; unset or invalid values disable the cache |
|
|
block size in bytes and the maximum payload size that can be cached |
|
disabled |
set to |
Behavior notes:
effective cache capacity is
floor(total_size / block_size)blocksvalues larger than
block_sizebypass the cache instead of being partially cachedsuccessful read misses populate the cache from the fetched value
successful local writes and deletes invalidate the matching local cache entry on that daemon
Python compatibility runtimes partition local entries by effective namespace scope, including
tenant,domain, andobject_set, so different object sets do not reuse the same cached value even inside one processshm mode shares payload bytes with dummy clients connected to the same
mooncake-store-rs-client, while LRU metadata, generations, and pins remain private to the daemoncache entries are daemon-local only and are never published to Redis or etcd
metadata keyspace remains the authoritative read/write isolation boundary; cache partitioning does not make objects visible across keyspaces
Read-side Membership and Failure Semantics#
The client keeps membership refresh out of the steady-state request path.
build(...)prewarms a live-client lease snapshot before serving readsa background worker refreshes that snapshot after startup
steady-state reads reuse the cached snapshot instead of issuing inline membership refreshes
owners in
ActiveandDrainingstate remain readableowners that become offline or hit transport/metadata failures are marked suspect and skipped on later reads
suspect owners observe a minimum quarantine, then recover only after a fresh lease heartbeat or control-plane endpoint change appears in the membership snapshot
when fallback to another replica succeeds, the client best-effort prunes unreadable owners from the route with CAS
MooncakeHostMemAllocator(...) exposes:
Parameter |
Meaning |
|---|---|
|
request hugepage-backed shm regions |
|
hugepage size for shm regions; accepts |
When the native extension is unavailable, the pure-Python allocator falls back to mmap and does not support hugepages.
Environment Variables#
The current repository uses these environment variables.
Variable |
Used By |
Meaning |
|---|---|---|
|
standalone client and bench |
hostname or IP published by the runtime |
|
standalone client and bench |
transport protocol such as |
|
compatibility layer, standalone client, Python wrapper |
select |
|
standalone client, standalone admin, and bench |
Store-RS metadata URL. Backs |
|
standalone client, bench, Python wrapper dict-form fallback |
Transfer Engine metadata input. Backs |
|
standalone client |
local storage bytes for |
|
standalone client and bench |
local scratch bytes for compatibility-managed clients |
|
standalone client and Rust e2e |
RDMA device list |
|
standalone client, standalone admin, and Python wrapper setup fallback |
metadata keyspace used when SGLang cannot pass |
|
standalone client and Python wrapper setup fallback |
stable client id used when SGLang cannot pass |
|
standalone client and Python wrapper setup fallback |
initial lifecycle state, for example |
|
standalone client, Python wrapper setup fallback, and bench |
default tenant used when SGLang cannot pass |
|
standalone client and Python wrapper setup fallback |
default domain used when SGLang cannot pass |
|
standalone client and Python wrapper setup fallback |
default object set used when SGLang cannot pass |
|
standalone client and Python wrapper setup fallback |
standalone labels as comma-separated |
|
standalone client and Python wrapper setup fallback |
enable routed writer mode when set to |
|
standalone client, Python wrapper setup fallback, and bench |
default routed-writer replica count |
|
standalone client, Python wrapper setup fallback, and bench |
WRH route-authority fanout; must be |
|
standalone client, Python wrapper setup fallback, and bench |
route control mode, usually |
|
compatibility layer, standalone client, Python wrapper, and bench |
|
|
standalone client and Python wrapper setup fallback |
fixed real data-plane transport port |
|
standalone client and Python wrapper setup fallback |
explicit local segment name |
|
Python wrapper setup fallback |
absolute lease expiry timestamp in milliseconds |
|
standalone client |
lease TTL for the standalone heartbeat loop |
|
standalone client |
heartbeat interval for the standalone heartbeat loop |
|
standalone client, Python compatibility runtime, applications |
outer per-request deadline for dispatcher requests and routed client operations |
|
standalone client, Python compatibility runtime, applications |
explicit override for compatibility-managed memory registration work; when unset the runtime uses |
|
standalone client, Python compatibility runtime, applications |
dedicated dispatcher timeout for heartbeat publish |
|
standalone client, Python compatibility runtime, applications |
inner transfer stall detector for TENT / classic TE |
|
legacy compatibility alias |
deprecated alias of |
|
dummy compatibility clients |
dummy gRPC timeout; falls back to |
|
standalone client |
dummy compatibility gRPC server address |
|
standalone client |
drain owned routes during graceful shutdown; accepts falsey values such as |
|
standalone client stats command |
server address used by |
|
standalone client stats command |
emit compact JSON from the stats command; accepts falsey values such as |
|
standalone client, Python compatibility runtime, applications |
worker thread count for the shared control-plane RPC runtime; default |
|
standalone client, Python compatibility runtime, applications |
worker thread count for the embedded control-plane gRPC server; default |
|
Python compatibility runtime, standalone dummy daemon, and local e2e |
total byte budget for the daemon-local hot read cache; unset disables it |
|
Python compatibility runtime, standalone dummy daemon, and local e2e |
cache block size and maximum cached object size; default |
|
standalone dummy daemon, dummy compatibility clients, and local e2e |
set to |
|
Python wrapper setup fallback, e2e, and applications |
enable tracing initialization from env |
|
standalone client, Python wrapper setup fallback, e2e, and applications |
|
|
Python real mode, standalone client, e2e, and applications |
append Rust tracing logs to this file; also auto-enables Python real-client tracing |
|
standalone client, Python real mode, e2e, and applications |
tracing span lifecycle events; unset suppresses synthetic span close lines, |
|
standalone client, Python real mode, bench, and applications |
local profiling sink; appends one JSON object per completed operation span and can be changed through |
|
standalone client, Python real mode, bench, and applications |
set to |
|
standalone client, Python real mode, bench, and applications |
key representation for item metadata; default |
|
standalone client, Python real mode, bench, and applications |
OTLP HTTP endpoint for Jaeger profiling; |
|
standalone client, Python real mode, bench, and applications |
standard OTLP traces endpoint; used as-is and takes precedence over |
|
standalone client, Python real mode, bench, and applications |
standard base OTLP endpoint; normalized to |
|
standalone client, Python real mode, bench, and applications |
initial Jaeger profiling switch; unset keeps profiling off until |
|
standalone client, Python real mode, bench, and applications |
Jaeger service name; default |
|
standalone client, Python real mode, bench, and applications |
Jaeger service instance id; defaults to |
|
standalone client, Python real mode, bench, and applications |
OTLP export timeout; default |
|
standalone client, Python real mode, bench, and applications |
OTLP trace sampling ratio from |
|
|
append bench tracing logs to this file; bench otherwise logs to |
|
|
combined write/read interface selector; accepts |
|
|
measured write-side bench API; |
|
|
measured read-side bench API; |
|
Python wrapper setup fallback, e2e, and applications |
bind address for the in-process metrics server |
|
Rust e2e |
metadata Redis URL |
|
local scripts and e2e |
local Redis port |
|
Redis metadata backends and transport Redis plugins |
optional Redis ACL username |
|
Redis metadata backends and transport Redis plugins |
optional Redis password; enables auth when set |
|
Redis metadata backend |
connection timeout for sync Redis metadata calls |
|
Redis metadata backend |
read/write timeout for sync Redis metadata calls |
|
Redis metadata backend |
bounded per-backend Redis connection pool size; default |
|
Redis metadata backend |
retry count for transient Redis reconnect / IO failures on readonly and idempotent metadata operations |
|
Redis metadata backend |
delay between transient Redis retry attempts |
|
Rust e2e |
payload size for validation and benchmark loops |
|
Rust e2e and local scripts |
benchmark iteration count; default |
|
Rust e2e |
print the Prometheus text snapshot at the end of the run |
|
local memory, standalone client, and Python shm allocator |
enable hugepage-backed allocation; standalone client treats |
|
local memory and Python shm allocator |
hugepage size; |
|
local scripts and Python source runtime |
explicit Store-RS source tree |
|
local scripts and native shim builds |
explicit Mooncake source tree |
|
local scripts and native runtime loading |
explicit Mooncake CMake build output tree |
mooncake-store-rs-bench reuses MC_STORE_RS_TRACE_FILTER for level control, but
it has its own trace-file surface. Use MC_BENCH_TRACE_FILE for bench logs and
keep MC_STORE_RS_TRACE_FILE for standalone-client or Python real-client
logging.
Standalone-client heartbeat success refreshes are trace-level routine events. Heartbeat recovery and failure messages remain explicit stderr output. Standalone-client local segment publication is an info-level startup registration event. Background storage-owner eviction completion is an info-level aggregate state change. Standalone-client startup emits one debug-level state snapshot after ready. Debug output keeps bounded per-key summary samples. Trace output keeps full per-key route and eviction details. Control-plane stream open events are trace-level connection churn.
Observability#
The Rust client exposes:
init_tracing(...)init_tracing_from_env(...)render_prometheus_metrics()start_metrics_http_server(...)start_metrics_http_server_from_env(...)stop_metrics_http_server()
The metrics HTTP server exposes:
GET /metricsGET /statsGET /breakdownGET /healthzGET /tracingGET /tracing/onGET /tracing/offGET /tracing?enabled=on&endpoint=http%3A%2F%2Fjaeger.observability.svc.cluster.local%3A4318&sample_ratio=0.05GET /tracing?enabled=on&file=%2Ftmp%2Fstore-rs.trace.jsonlGET /tracing/flush
/tracing returns JSON status for the profiler. Enabling requires at least one
sink: an OTLP endpoint for Jaeger or a local JSONL file. The endpoint is locked
after the exporter is initialized, because changing Jaeger backends while batch
processors are running would make trace ownership ambiguous. The same lock
applies to service_name, service_instance_id, and sample_ratio; set them
before enabling export. The local JSONL file can be set with file=... and
cleared with clear_file=true while profiling is disabled.
Set MC_STORE_RS_TRACE_ITEM_METADATA=1 with a local JSONL file to append
store.api_items.v1 records next to the span records for successful
batch_put_from / batch_get_into paths. These records are for offline
per-key analysis and include trace_request_id, operation, tenant/domain/object
set, runtime id, batch bytes, per-item key hash, readable key prefix, parsed
SGLang TP rank and k/v suffix, size/read length, and status. The default
MC_STORE_RS_TRACE_KEY_MODE=hash never writes full keys; use full only for
local debug captures.
/breakdown returns JSON for SGLang/HiCache performance diagnosis. It includes
API, phase, metadata-backend, transport, runtime, segment, and
bottleneck-candidate sections. Use mooncake-store-rs-client stats --breakdown --server <host:port> for a compact human-readable summary, or add --json to
print the raw JSON.
When OTLP profiling is enabled, Jaeger span names describe the performance
surface instead of raw code hooks. API roots are named store.*; control-plane
work is named control.*; data-plane work is named data.*; metadata backend
calls are named metadata.*. Common span attributes include
mooncake.phase, mooncake.flow, mooncake.request_id,
mooncake.item_count, mooncake.bytes_in, mooncake.bytes_out,
mooncake.replica_count, mooncake.local_target_count, and
mooncake.remote_target_count. Use the Jaeger waterfall for one sampled
request and the Prometheus operation histograms for the matching time-series
view.
Exporter families:
mooncake_store_operation_total,mooncake_store_operation_bytes_in_total,mooncake_store_operation_bytes_out_total,mooncake_store_operation_latency_microseconds_total,mooncake_store_operation_latency_microseconds_maxmooncake_store_request_total,mooncake_store_request_inflight,mooncake_store_request_bytes_totalmooncake_store_request_duration_seconds_bucketmooncake_store_metadata_operation_total,mooncake_store_metadata_operation_inflight,mooncake_store_metadata_operation_duration_seconds_bucketmooncake_store_segment_capacity_bytes,mooncake_store_segment_used_bytesmooncake_store_runtime_status,mooncake_store_runtime_lease_expires_at_msmooncake_store_route_cas_totalmooncake_store_segment_lifecycle_total,mooncake_store_eviction_total,mooncake_store_eviction_duration_seconds_bucketmooncake_store_transport_bytes_total,mooncake_store_rebalance_routes_total,mooncake_store_rebalance_bytes_totalmooncake_store_tenant_quota_reservation_total,mooncake_store_tenant_quota_finalize_total,mooncake_store_tenant_quota_abort_total,mooncake_store_tenant_quota_reconcile_totalmooncake_store_heartbeat_consecutive_failures,mooncake_store_heartbeat_last_success_msmooncake_store_membership_refresh_total,mooncake_store_membership_refresh_duration_secondsmooncake_store_checksum_validation_total,mooncake_store_replication_publish_duration_secondsprocess_cpu_seconds_total,process_resident_memory_bytes,process_open_fds
All Store-RS and process metrics exported by this endpoint include tenant="<default tenant>", where the value is the process-bound tenant selected by StoreClientBuilder::tenant(...) or the corresponding compatibility-layer startup option. All Store-RS metric families use the mooncake_store_ prefix to reflect the store cluster perspective. Each runtime instance exports its own view through the /metrics endpoint regardless of its role (storage node or routed client).
Sparse operational counter families emit zero-valued baseline series for their known label set. This makes steady-state dashboards report an explicit zero for tenant quota, tenant-local eviction, preferred-segment skip, rebalance, and segment lifecycle activity until the corresponding real event occurs and increments the counter.
Metadata backend metrics are recorded around Store-RS calls into the configured MetadataBackend and are labeled by backend, operation, and result. They show whether Store-RS is waiting on or failing calls to Redis, etcd, or another metadata implementation; they are not a replacement for Redis or etcd server-internal exporters.
Storage and route-authority clients also record control-plane-derived traffic: route CAS handlers observe replication publish latency, replica-route tracking records storage-owner write bytes, and route-hit reports record storage-owner read bytes plus successful checksum-validated hits. Scratch-only benchmark workers therefore do not need to expose their own metrics endpoint for the long-running store clients to show benchmark traffic.
Recommended recording queries:
rate(mooncake_store_request_total{tenant="$tenant",operation="get",result="error"}[5m])
histogram_quantile(0.99, sum by (le, tenant, operation) (rate(mooncake_store_request_duration_seconds_bucket{tenant="$tenant"}[5m])))
rate(mooncake_store_metadata_operation_total{tenant="$tenant",backend=~"redis|etcd",result!="ok"}[5m])
histogram_quantile(0.99, sum by (le, tenant, backend, operation) (rate(mooncake_store_metadata_operation_duration_seconds_bucket{tenant="$tenant"}[5m])))
mooncake_store_segment_used_bytes{tenant="$tenant"} / mooncake_store_segment_capacity_bytes{tenant="$tenant"}
Infrastructure split:
process-scoped facts come from this crate
host CPU, disk, and network should come from
node_exporterorcAdvisor
Practical Defaults#
For local development:
use Redis metadata
keep
route_controlatEmbeddedWrhlabel storage targets with
storage=truekeep
prefer_local=trueunless you want remote-first behavior
For debugging:
switch to
MetadataOnlyif you want all route state to flow through metadata
For upgrade and elasticity flows:
preserve
stable_idstart the successor with the same
stable_id; the metadata backend allocates the next epoch atomicallyuse
expand_local_memory,drain_segment,retire_segment, andevacuate_owned_replicas
Python Configuration#
These sections supplement the client and operator settings above with Python-specific metadata, transport, and framework configuration.
Metadata URLs#
The compatibility layer accepts these metadata URL forms:
Scheme |
Meaning |
|---|---|
|
Redis metadata backend |
|
etcd metadata backend |
Redis authentication follows the same environment variables as the native store:
export MC_REDIS_PASSWORD='<redis-password>'
# Optional when Redis ACLs require a named user:
export MC_REDIS_USERNAME='<redis-username>'
Credentials embedded in redis://username:password@host:port/db are also accepted and take precedence over the environment variables. Prefer environment variables when passwords contain URL-reserved characters such as @.
Python setup positional layout#
setup(local_hostname, transport_metadata_url, global_segment_size, local_buffer_size, protocol, rdma_devices, metadata_url).
transport_metadata_urlis forwarded to the Transfer Engine only. Acceptsredis://...orP2PHANDSHAKE. Default value isP2PHANDSHAKEeverywhere it can be defaulted: the Python dict-form (resolution order: dict key →MC_STORE_RS_TRANSPORT_METADATA_URLenv →P2PHANDSHAKE), the standalone CLI bins (mooncake-store-rs-client/mooncake-store-rs-benchwithout--transport-metadata-urlor env), and other defaultable surfaces. The Python positionalsetup(...)requires it explicitly because Python disallows defaults on a positional that precedes required positionals; pass"P2PHANDSHAKE"to opt into the default. The dict-form also accepts the upstream Mooncake keymetadata_serveras an alias.metadata_urlis the Store-RS metadata URL. Acceptsredis://...oretcd://...and is required. The dict-formsetup({...})also accepts the upstream Mooncake keysmaster_server,master_server_addr, andmaster_server_addressinterchangeably as aliases, withMC_STORE_RS_METADATA_URLenv honored as a final fallback. The standalone CLI bins use the same env for their--metadata-urlflag.
Important note for etcd#
When metadata_url is an etcd URL, the Transfer Engine still needs its own metadata: pass either redis://... or P2PHANDSHAKE at transport_metadata_url. For classic_te, P2PHANDSHAKE (the transfer-engine peer-handshake mode) is the default; tent always needs an explicit redis://....
Python Transport Backend Selection#
The compatibility layer can choose the transport backend at runtime.
Supported values:
tentclassic_te
Selection order:
explicit
transport_backend=...argument tosetup(...)MC_STORE_RS_TRANSPORT_BACKENDdefault
classic_te
The standalone client follows the same rule, except the explicit override is --transport-backend.
SGLang Environment Fallbacks#
Current upstream SGLang only forwards legacy Mooncake setup fields. When SGLang cannot pass Store-RS setup extensions, the Python wrapper reads these environment variables as fallbacks:
MC_STORE_RS_METADATA_URL(dict-formmetadata_urlfallback) andMC_STORE_RS_TRANSPORT_METADATA_URL(dict-formtransport_metadata_urlfallback; defaults toP2PHANDSHAKEwhen unset)MC_STORE_RS_TRANSPORT_BACKEND=tent|classic_teMC_STORE_RS_KEYSPACE,MC_STORE_RS_STABLE_ID,MC_STORE_RS_TENANT,MC_STORE_RS_LABELSMC_STORE_RS_ROUTED_WRITES=1,MC_STORE_RS_REPLICA_COUNT=<n>,MC_STORE_RS_ROUTE_TOPK=<n>MC_STORE_RS_ROUTE_CONTROL=embedded_wrh|metadata_onlyMC_STORE_RS_TRANSPORT_RPC_PORT,MC_STORE_RS_LOCAL_SEGMENT_NAMEMC_STORE_RS_INITIAL_STATE,MC_STORE_RS_EXPIRES_AT_MSMC_STORE_RS_METRICS_ADDR=host:portMC_STORE_RS_CONTROL_PLANE_THREADS=<n>to tune concurrent control-plane RPC client capacity; default2MC_STORE_RS_CONTROL_PLANE_SERVER_THREADS=<n>to tune embedded control-plane gRPC server capacity; default4
Explicit setup(...) arguments still take precedence. MC_STORE_RS_METRICS_ADDR starts the Python real-client /metrics endpoint after setup(...). MC_STORE_RS_LABELS accepts either JSON ({"storage":"false","pool":"rw"}) or comma-separated pairs (storage=false,pool=rw).