Architecture Overview#
Maru manages KV cache data in CXL shared memory, enabling cross-instance sharing across multiple nodes. Nodes attached to the CXL memory share it without data transfer; nodes without CXL reach it over RDMA (see Remote CXL below).
System Architecture#
%%{ init: { "flowchart": { "curve": "linear" } } }%%
flowchart TB
subgraph Instances[" "]
direction LR
subgraph SN["Server N"]
direction TB
V1(["LLM Instance"])
H1{{"MaruHandler"}}
V1 --- H1
end
subgraph S2["Server 2"]
direction TB
V2(["LLM Instance"])
H2{{"MaruHandler"}}
V2 --- H2
end
subgraph S1["Server 1"]
direction TB
V3(["LLM Instance"])
H3{{"MaruHandler"}}
V3 --- H3
end
end
subgraph ControlPlane["Control Plane"]
direction LR
subgraph Remote["Remote Mode"]
direction TB
MS["MaruServer"]:::maru
D["MaruResourceManager"]:::maru
MS <--> D
end
subgraph Filesystem["Shared Filesystem Mode"]
direction TB
FS["MaruFs"]:::fs
end
end
H1 <-.->|"store / retrieve"| FS
H2 <-.->|"store / retrieve"| MS
H3 <-.->|"store / retrieve"| MS
subgraph CXL["CXL Shared Memory"]
direction LR
R0["Region 0"] ~~~ R1["Region 1"] ~~~ R2["Region 2"]
end
D -.->|"allocate / free regions"| CXL
FS -.-> CXL
H1 <==>|"read / write"| CXL
H2 <==>|"read / write"| CXL
H3 <==>|"read / write"| CXL
classDef maru fill:#f8cecc,stroke:#b85450,font-weight:bold
classDef fs fill:#dae8fc,stroke:#6c8ebf,font-weight:bold
Control Plane (dashed arrows) — KV metadata operations and region allocation.
Data Plane (solid arrows) — on nodes attached to CXL, direct access to CXL shared memory, zero-copy. The data path is identical regardless of control plane mode. Nodes without CXL move KV over RDMA, as Remote CXL below describes.
The system has three layers:
Layer |
Role |
Components |
|---|---|---|
Client |
KV operations, page allocation, region mapping (with |
MaruHandler; remote CXL agent ( |
Metadata |
Key registry, allocation lifecycle |
MaruServer (Remote) / marufs (Filesystem) |
Memory |
Shared memory pool, capability issuance, crash recovery |
MaruResourceManager (Remote) / marufs (Filesystem) |
Key Design Properties#
Zero-copy data path. Clients on nodes attached to CXL access KV data directly in shared memory — no server process ever touches the data path (dashed arrows in the diagram). The only traffic on the control plane is lightweight metadata; between those nodes, the data itself never moves. This strict control/data plane separation means data-path performance is bounded by memory bandwidth, not by software overhead. Clients on nodes without CXL keep the same separation: their NIC moves KV with one-sided RDMA and no Maru process is on that path, with one copy added between the GPU and a host staging buffer (see Remote CXL below).
Per-application control plane. Each application group runs its own metadata service for isolation (e.g., app A with 2 instances, app B with 3 instances). A single Resource Manager manages the shared memory pool across all groups. The diagram below illustrates this in Remote mode:
%%{ init: { "flowchart": { "curve": "linear" } } }%%
flowchart LR
subgraph AppA["App A"]
direction TB
A1(["Instance 1"])
A2(["Instance 2"])
end
subgraph AppB["App B"]
direction TB
B1(["Instance 1"])
B2(["Instance 2"])
B3(["Instance 3"])
end
MSA["MaruServer A"]:::maru
MSB["MaruServer B"]:::maru
RM["MaruResourceManager"]:::rm
A1 & A2 --> MSA
B1 & B2 & B3 --> MSB
MSA & MSB --> RM
subgraph CXL["CXL Shared Memory Pool"]
direction TB
R0["Region 0"] ~~~ R1["Region 1"] ~~~ R2["Region 2"] ~~~ R3["Region 3"]
end
RM --> CXL
classDef maru fill:#f8cecc,stroke:#b85450,font-weight:bold
classDef rm fill:#d5e8d4,stroke:#82b366,font-weight:bold
Pluggable control plane. The control plane is isolated behind a stable interface, so its implementation can change without affecting the data path. Remote mode (current) uses a centralized MaruServer + MaruResourceManager. Shared Filesystem mode (in development) replaces both with MaruFs, enforcing memory access control at the kernel level for stronger security than user-space RPC.
Capability-based memory access. Clients never open shared memory devices directly. The Resource Manager acts as a capability broker, issuing authorized handles that grant access to specific memory regions (the Memory layer in the diagram). This confines hardware access to a single trusted process and decouples clients from the underlying memory technology.
Data Flow#
Store#
sequenceDiagram
participant C as Caller
participant H as MaruHandler
participant CP as Control Plane
participant CXL as CXL Shared Memory
C->>H: store(key, data)
H->>H: allocate page from owned region
H->>CXL: write data directly (zero-copy)
H->>CP: register key → location
CP-->>H: OK
H-->>C: success
Data is written to shared memory before the key is registered. Other instances can never observe a partial write — the key only becomes visible after the data is fully committed.
Retrieve (cross-instance)#
sequenceDiagram
participant C as Caller
participant H as MaruHandler
participant CP as Control Plane
participant CXL as CXL Shared Memory
C->>H: retrieve(key)
H->>CP: lookup key
CP-->>H: location (region, offset, length)
H->>H: map region if not yet mapped
H->>CXL: direct read (zero-copy)
H-->>C: data
Every retrieve requires one metadata lookup via the control plane. Once a region is mapped, the mapping is cached for subsequent accesses to the same region — only the first access to a given region incurs the mmap cost.
Remote CXL: CXL Memory of Other Nodes over RDMA#
LLM instances on nodes without CXL use the remote_cxl storage backend: their
KV cache stays in the CXL memory of memory nodes and moves over RDMA. The
three layers and the resource flow stay as above: the Resource Manager gives
regions to MaruServer, and MaruServer gives them to each MaruHandler, one when
its storage session opens and one more whenever its regions are full. One step
moves: mapping a region. One-sided RDMA reaches only memory that a process on
the target node has mapped and registered with that node’s NIC, and a node
without CXL cannot map the region itself. A remote CXL agent on every memory
node is that process: it maps the regions Handlers ask for and registers them
with the node’s NIC (the job DaxMapper does inside a Handler on a CXL-attached
node), and returns each region’s address and remote key. The Handler then reads and
writes a region with one-sided RDMA between its staging buffer and the region,
and the bytes go from NIC to NIC without passing through a process on the
memory node.


How the properties above carry over:
Data path. No Maru process is on it: the worker’s NIC and the memory node’s NIC move the bytes. One copy is added, between the GPU and the worker’s staging buffer. The remote CXL agent uses CPU when it maps a region and while a worker sets up its RDMA connection. It does not busy-poll while idle; periodic sweeps still progress UCX and check regions.
Capability-based access. The remote CXL agent is the process that opens the DAX device on a memory node, and it checks a handle with the Resource Manager (
HOLD, aGET_ACCESSthat also keeps the region’s range out of use until the agent lets go of it) before it maps a region. Who may ask it is bound as who may open a DAX device is: it listens on the node’s RDMA network address, and every connection proves the remote CXL agent key, a file that only the users running workers and maru-server can read. A reader gets a read handle, which maps a region but cannot release it.
Region lifetime. A region goes back to the Resource Manager only after its remote CXL agent has deregistered it from the NIC, so an RDMA WRITE of the old owner that is still in flight fails at the NIC instead of landing in the next owner’s KV. When a worker leaves, MaruServer keeps its regions that hold keys, as it keeps a cxl Handler’s regions while keys refer to them, and gives them back when the pool needs the space.
The MaruHandler and MaruServer designs describe the parts; the vLLM integration guide shows how to run it.
Extensibility#
MaruHandler is framework-independent. Its interface operates on string keys and memory views — a minimal, framework-neutral contract. Any inference framework can integrate with Maru by writing a thin adapter layer (typically under 200 lines) that converts framework-specific cache keys to strings and delegates to MaruHandler’s store/retrieve API.
graph LR
A[LMCache] -->|MaruConnector| D[MaruHandler]
B[SGLang] -->|MaruStorage| D
C[Other Framework] -->|Custom Adapter| D
D --> E[MaruServer]
D --> F[CXL Shared Memory]
See also: LMCache, SGLang HiCache, MaruHandler Design