Conductor Architecture#
Overview#
Mooncake Conductor is the KV-cache indexer used by cache-aware routers. It subscribes to KV cache events from inference engines (vLLM, SGLang) and from the Mooncake Store master, recomputes those events into its own prefix hashes, maintains a global prefix cache table, and answers cache-hit queries over HTTP and RPC.
The design goal is to let routers answer a simple scheduling question: for this request prefix, which registered instance has the best reusable KV cache locality, and on which cache tiers is that prefix available?
Architecture#
flowchart TD
subgraph Router["Gateway or router"]
HTTPClient["HTTP client (msgpack)"]
RPCClient["ConductorClient (C++, Python, Rust)"]
end
subgraph Conductor["mooncake_conductor"]
EventManager["EventManager"]
Service["ConductorService"]
ZMQClient["ZMQClient (one per service)"]
KVEventHandler["KVEventHandler"]
PrefixCacheTable["PrefixCacheTable"]
end
subgraph Publishers["Event publishers"]
Engine["vLLM / SGLang engines"]
Master["Mooncake Store master"]
end
Engine -->|ZMQ PUB, optional replay ROUTER| ZMQClient
Master -->|ZMQ PUB| ZMQClient
EventManager -->|creates and manages| ZMQClient
ZMQClient -->|decoded batches| KVEventHandler
KVEventHandler -->|store / remove / clear| PrefixCacheTable
HTTPClient -->|HTTP :13333| EventManager
RPCClient -->|coro_rpc :13334| EventManager
EventManager --> Service
Service -->|query, register, unregister| PrefixCacheTable
Components#
Component |
Responsibility |
|---|---|
|
Owns the process lifecycle, the HTTP server, the RPC server, and the active service map. Creates one |
|
Implements |
|
Subscribes to one publisher endpoint, validates frames, tracks sequence numbers, and recovers gaps through the replay endpoint when one is configured. |
|
Applies decoded vLLM, SGLang, or Mooncake events to the prefix table using the service’s registration metadata and hash profile. |
|
Holds per-context prefix entries with per-tier owners, binds each context to one hash profile, and computes query-time hits. |
|
RPC client in C++ ( |
Data model#
The prefix index is scoped by a context key:
(tenant_id, model_name, lora_name, block_size)
Each context is bound to exactly one hash profile. Registering a service whose
hash profile conflicts with an existing binding for the same context is
rejected. Each context records which instances and DP ranks are registered in
it, and holds at most max_blocks_per_context prefix entries (default 200000).
When the cap is exceeded, the oldest entries are evicted in a batch down to 90%
of the cap; 0 disables the cap.
A prefix entry records owners per storage tier:
Tier |
Owner |
Fed by |
|---|---|---|
|
engine |
vLLM |
|
engine |
SGLang |
|
shared store object |
Mooncake |
|
engine or shared store object |
Mooncake |
Mooncake events with a medium other than cpu, cpu_pinned, or disk are ignored.
Hash profiles#
Conductor never trusts a block hash it cannot reproduce. Every service registers
a hash_profile that tells Conductor how the publisher hashes token blocks, and
/query recomputes the same hashes from the request tokens.
|
|
|
Block coverage |
|---|---|---|---|
|
|
|
Complete blocks only |
|
|
|
Includes the final partial block |
|
|
|
Includes the final partial block; hashes adjacent token pairs |
vllm_v1 also requires python_hash_seed (decimal 0..4294967295, or
"random"), from which Conductor derives the chain root root_digest.
SGLang strategies have no seed; their root depends only on the optional
cache_salt.
Engine block hashes are projected to the 64-bit index key with the profile’s
projection. For Mooncake Store events, the key is derived from the object key or
connector_block_hash, not from seq_hashes, which the master always leaves
empty.
Event flow#
A service is registered statically from
conductor_config.jsonor dynamically throughPOST /registeror the RPCRegistermethod. The service key isinstance_id|tenant_id|dp_rank. Re-registering an identical configuration is a no-op.EventManagerstarts aZMQClientthat connects aSUBsocket to the publisher endpoint. Each live message must have exactly three frames:[topic, sequence (u64 big-endian), payload].The payload is a msgpack array
[timestamp, [event_map, ...], dp_rank]. Events must be maps; array-encoded events are rejected. Decoders exist for:vLLM:
type=BlockStored,BlockRemoved,AllBlocksCleared;SGLang: the same type tags, with signed 64-bit hashes and optional bigram token pairs;
Mooncake Store:
event_type=stored,removed,cleared(see subscriber-guide).
KVEventHandlermaps the medium to a tier and applies the event:vLLM and SGLang events are applied to the registered context and must carry the registered
dp_rank;Mooncake events take their context from the event envelope (
tenant_id,model_name,lora_name,block_size), which must match a context already registered with the same hash profile. The object key is parsed with the vLLM or SGLang key convention selected by the profile.
Clears are scoped to their owner: vLLM
AllBlocksClearedclears that engine’sdevicetier, SGLangAllBlocksClearedclears all of that engine’s tiers, and Mooncakecleareddrops every object bound to thatbackend_id + tenant_id.
Sequence gaps and replay#
ZMQClient treats a sequence number above last + 1 as a gap.
With a
replay_endpoint(vLLM and SGLang only), the client buffers live messages, sends["", from_seq]on aDEALERsocket, and applies the replayed range in order. The replay stream ends with sequenceUINT64_MAXand an empty payload. Recovery is bounded to 30 seconds and to a 10000-message / 64 MiB buffer.Without a replay endpoint, and for every Mooncake publisher (the master has no replay service), a gap cannot be recovered.
When recovery is impossible, the source is marked stale: its entries are removed from the index and further events from it are dropped until the service is unregistered and registered again. On a dropped connection the client reconnects after one second and, when replay is enabled, replays from the last applied sequence.
Query flow#
A router obtains prompt token IDs, usually from an engine tokenizer endpoint.
The router calls
POST /query(or RPCQuery) withmodel,block_size,token_ids, and optionaltenant_id,lora_name,cache_salt, andinstance_id.Conductor recomputes the prefix hash chain with the context’s hash profile.
For each instance and DP rank, a cursor walks the chain through cumulative tier predicates. The first miss ends each predicate, so prefix continuity is preserved:
device <= cpu_local <= cpu_share <= disk.Instance-level tier counts are the maximum over that instance’s ranks, and
longest_matchedequalsdisk. Counts are in tokens, clamped to the number of queried tokens (n - 1forsglang_bigram).The router selects the best target instance and forwards the request.
Configuration#
Static configuration lists services under kvevent_instance, using the same
field names as POST /register. When instance_id is omitted, the entry key is
used. Invalid entries are logged and skipped.
{
"http_server_port": 13333,
"rpc_server_port": 13334,
"max_blocks_per_context": 200000,
"kvevent_instance": {
"vllm-prefill-node1": {
"endpoint": "tcp://127.0.0.1:5557",
"replay_endpoint": "tcp://127.0.0.1:5558",
"type": "vLLM",
"modelname": "qwen2.5",
"lora_name": "",
"tenant_id": "default",
"block_size": 16,
"dp_rank": 0,
"hash_profile": {
"strategy": "vllm_v1",
"algorithm": "sha256_cbor",
"python_hash_seed": "0",
"index_projection": "low64_be"
}
}
}
}
Key |
Default |
Description |
|---|---|---|
|
|
HTTP port. Set it explicitly. |
|
|
RPC port. |
|
|
Prefix entries kept per context (tenant, model, LoRA, block size); the oldest are evicted beyond it. |
|
none |
Static services keyed by name. |
Environment variables#
Variable |
Default |
Description |
|---|---|---|
|
|
Path to the static configuration file. |
|
|
|
Build and run#
Conductor is built as part of the Mooncake CMake project:
cmake -S . -B build -DWITH_CONDUCTOR=ON
cmake --build build --target mooncake_conductor
-DWITH_CONDUCTOR_RUST=ON additionally builds the Rust client. The Python
client (mooncake.conductor) is built with the Mooncake Python package when
WITH_CONDUCTOR=ON.
export CONDUCTOR_CONFIG_PATH=conductor_config.json
export CONDUCTOR_LOG_LEVEL=info
./build/mooncake-conductor/mooncake_conductor
The process stops on SIGINT or SIGTERM.
Project structure#
mooncake-conductor/
+-- include/conductor/ # public headers
+-- src/
| +-- client/ # ConductorClient and C ABI
| +-- common/ # shared types and helpers
| +-- kvevent/ # EventManager, KVEventHandler, ConductorService, config
| +-- prefixindex/ # PrefixCacheTable and hash strategies
| +-- zmq/ # ZMQ client, transport, msgpack decoding
| +-- main.cpp # mooncake_conductor entry point
+-- rust/ # Rust client crate
+-- tests/
+-- CMakeLists.txt
See Indexer API for the HTTP API and Python API for the client.