← All posts

Rasa architecture in one page

Rasa is easiest to understand if you separate the two jobs: deciding where a value lives, and moving the value bytes. The first job is normal metadata. The second job is one-sided RDMA.

Client SDK get / put / delete validates header + CRC Valkey + manager descriptors, leases allocation, rotation Data node registered arenas slots + rkeys metadata commands one-sided RDMA over EFA/libfabric value bytes move here; Valkey is not in the data path The invariant control plane answers: where is it safe to read/write? data path answers: move these bytes now. Client SDK get / put / delete Valkey + manager descriptors, leases, allocation Data node registered arenas + rkeys metadata commands EFA/libfabric data path value bytes move here Valkey does not carry them
The control plane carries intent and safety. The data path carries bytes.

The pieces

The client SDK is the user's entry point. It exposes normal cache verbs: get, put, and delete. Under the hood it resolves descriptors, manages libfabric addresses, posts RDMA operations, polls completions, and validates the value header and CRC.

Valkey is the metadata store. It holds key-to-descriptor records, node records, leases, arena inventory, command streams, metrics, and the small amount of state needed to allocate and reclaim memory. It is on the control path, not the read data path.

The data node owns the bytes. It allocates fixed-size arenas, registers them with libfabric, and publishes descriptors that name specific slots inside those arenas. A descriptor is the bridge between normal metadata and remote memory: {node, region, addr, rkey, len, version, checksum}.

The read path

A read starts with metadata. The client asks Valkey where the key lives, verifies the descriptor if signing is enabled, inserts the data node's fabric address into its address vector, and issues fi_read. After that, the data node's CPU is not serving the request. The NIC reads from registered memory and the bytes land in the client's registered buffer.

Rasa is therefore not Redis with a faster network stack. Redis answers every GET. Rasa makes the answer discoverable ahead of the transfer, then lets the NIC move the value.

The write path

A write is coordinated before it is visible. The client asks the control plane for space. The manager chooses a node and slot, returns a write grant, and the client RDMA-writes one framed value into that slot. The client then commits to the data node. Only after commit does the node publish the signed descriptor that readers can resolve.

This ordering is the safety line. Readers should see the old value, a miss, or the complete new value. They should not discover memory while a writer is still filling it.

Maintaining integrity

Rasa's hard problems are mostly lifecycle problems. A descriptor is a capability to read memory, so the system cannot casually reuse that memory while clients may still hold the old descriptor. Leases bound how long readers can keep a view. Arena rotation creates a new rkey, so stale descriptors fail in hardware instead of reading reused bytes.

Delete follows the same idea: unpublish first, reclaim later. Compaction, eviction, and failure handling are all variations on one rule: never make a remote pointer lie.

The split we kept coming back to

One line settled most of the arguments about where a given piece of logic belongs: policy in the control plane, mechanism in the data nodes.

A data node knows how to rotate an arena, seal one, or report its inventory. It does not decide when any of that should happen, and has no way to. Compaction is the clearest case: a node can see that an arena is mostly dead and propose compacting it, but the rotate that follows is only safe once manifests have been repointed and leases drained, and both are control-plane state a node has no view of. So the node proposes and executes, and the control plane decides. When we were unsure where something belonged, that sentence usually answered it.

What is intentionally not hot

Valkey is not moving value bytes. The manager is not in the read loop. The console is not a data-plane component. The data node is not parsing a request for every read. Those absences are the architecture. Rasa spends normal software where decisions are made, then keeps the byte movement small, direct, and boring.

Mental model: Rasa is a remote-memory data plane for large immutable or versioned values. Valkey says which memory is safe to touch. EFA/libfabric moves the bytes. The rest of the system exists to keep those two statements true.