KV Cache Offloading¶
Model implementation support
This feature runs on the vllm model implementation only. See the Feature Matrix for feature support by model implementation.
Overview¶
Prefix caching reuses a KV cache only while it stays in NPU device memory. Device memory is the smallest tier available, so a prefix that is evicted must be recomputed when a later request contains the same prefix.
KV cache offloading stores reusable KV chunks in a larger, slower tier while requests are processed. After the NPU cache evicts a prefix, a later request can restore its KV from that tier instead of recomputing it. RBLN vLLM supports this through LMCache and its RBLN extension, lmcache-rbln.
Architecture¶
lmcache-rbln is a hardware-specific extension of LMCache for RBLN NPUs. It depends on the upstream lmcache package for cache management (chunking, lookup, and eviction policy) and replaces the device-specific components: the KV cache transfer between NPU memory and the offload tier, and the storage backend for NVMe direct storage.
RBLN vLLM registers the extension's connector, RBLNLMCacheConnectorV1, with its KV connector factory, so it is selected by name through --kv-transfer-config like any other vLLM KV connector.
Storage tiers¶
LMCache's configuration selects the offload tier. This page covers two:
- CPU memory: a host memory pool, and LMCache's default backend.
- Rebellions Direct Storage (RDS): writes KV chunks from NPU memory directly to NVMe, bypassing host memory.
Rebellions Direct Storage (RDS)¶
RDS is a data path along which an RBLN NPU reads from and writes to an NVMe SSD directly. It connects NVMe and NPU memory over PCIe peer-to-peer DMA and removes the host bounce buffer.
The RDS backend has two constraints:
- The RDS backend holds its index in memory, so offloaded chunks do not survive a restart.
- The RDS backend caps the number of stored chunks at
rds_max_chunksand evicts the least recently used chunk to make room. If NVMe fills before the cap, the failed write also evicts the least recently used chunk and retries.
Prerequisites¶
Install lmcache-rbln in the server environment
KV cache offloading requires lmcache-rbln; it is not included in the default vllm-rbln installation. Install the kv_connectors extra in the same Python environment that runs vllm serve. It also installs the required upstream lmcache dependency. See Optional dependencies.
Check the packages in that environment:
The connector runs on the vllm model implementation, so the server is launched with --model-impl vllm. That is also what puts the KV cache in device tensors, which is the only mode the connector supports: it transfers the cache as torch tensors on device='rbln'.
- Unless the run resolves to the
vllmmodel implementation, RBLN vLLM never imports the module that registersRBLNLMCacheConnectorV1, so engine startup fails while validating the connector name withUnsupported connector type: RBLNLMCacheConnectorV1. Set--model-impl vllmexplicitly, sinceautopickstransformersfor the architecturesoptimum-rblnsupports. PYTHONHASHSEEDhas to be set to a fixed value. Without it, vLLM derives the base of its block hash chain from a per-process random value, the chain diverges between the scheduler and the workers, and every cache lookup misses. The connector refuses to construct withRuntimeErrorinstead of failing silently. vLLM hashes the variable's string to seed the chain, so any fixed value works.
RDS device availability¶
For RDS offloading, the host must have an NVMe device bound for RDS. On a systemd host, inspect the binding service and its boot logs:
The binding service is a oneshot service, so active (exited) can be normal. In a container, check the service on the host. Then check runtime visibility in the Python environment where the server runs:
Expect RDS available: True and a nonzero device count. These checks establish runtime visibility; verify writes and restores after startup using Verify offloading.
Configuration¶
The cache is configured through LMCache's LMCACHE_* environment variables, and the connector is selected through --kv-transfer-config. Choose a storage tier, review its settings below, then copy the complete block in Server launch.
CPU offloading¶
CPU offloading keeps KV chunks in host memory through LMCache's default backend, LocalCPUBackend. It needs no additional hardware and follows upstream LMCache usage.
| Variable | Description | Default |
|---|---|---|
LMCACHE_LOCAL_CPU | Enables the host memory backend. | True |
LMCACHE_MAX_LOCAL_CPU_SIZE | Host memory pool size in GB. | 5.0 |
LMCACHE_CHUNK_SIZE | Tokens per KV chunk. With partial-chunk saving disabled, a prefix must fill a chunk before it can be stored; short prefixes produce no hits. | 256 |
Tip
Set LMCACHE_CHUNK_SIZE equal to --block-size. One chunk then maps to one KV cache block, which gives the best KV copy performance.
For the full set of LMCache configuration keys, see the LMCache documentation.
SSD offloading (RDS)¶
RDS offloading keeps KV chunks on NVMe, written from NPU memory without passing through host memory. Confirm that the server works with CPU offloading before switching to this tier.
Info
RDS requires a bound NVMe RDS device on the host. There is no fallback path: without the device, the tier is unavailable.
The backend is registered through LMCache's storage-plugin launcher. To make RDS the primary allocator, turn the CPU tier off explicitly. Keeping the CPU tier enabled creates a hybrid configuration in which host memory is the primary tier and chunks reach NVMe through host memory.
| Key | Value | Description |
|---|---|---|
storage_plugin.RDSBackend.module_path | lmcache_rbln.storage_plugin.rds_backend | Module that holds the backend class. |
storage_plugin.RDSBackend.class_name | RDSBackend | Backend class name. |
rds_buffer_size | 2048 | Device memory staging budget in MiB, not NVMe capacity. Defaults to 2048; values <= 0 disable staging sub-batching. |
rds_failure_policy | ignore | ignore keeps best-effort operation; fail propagates terminal RDS failures to the serving worker. Defaults to ignore. |
rds_max_chunks | 1000 | Maximum number of chunks stored on NVMe. Each stored chunk takes 2 MiB of NPU device memory per NVMe drive while it stays cached, so with the default, up to 2 GiB per drive can be taken dynamically as chunks are stored. This memory is not reserved when the KV cache is sized. 0 removes the cap. Defaults to 1000. |
Warning
Staging memory is allocated on demand. A configured budget does not reserve NPU memory or guarantee a store succeeds. With the default rds_failure_policy=ignore, a failed write batch is dropped and serving can continue; the backend is not automatically disabled. With fail, non-capacity write failures and read failures are propagated to the worker. Recognized capacity errors on writes can still evict cached chunks and retry. Check logs after the first requests.
Device memory headroom for RDS
RDS uses NPU device memory outside the KV cache: the staging buffer (rds_buffer_size) and 2 MiB per NVMe drive for each stored chunk (rds_max_chunks). When device memory is tight, lower rds_max_chunks or --gpu-memory-utilization. On Rebel100™, keep rds_max_chunks and rds_buffer_size at their defaults and set --gpu-memory-utilization 0.8 when using RDS.
Server launch¶
Run one block below in a fresh shell with the server environment activated and no other LMCACHE_* settings, which can otherwise affect the run. LMCACHE_USE_LAYERWISE=True is unsupported and rejected at startup.
| Key | Value | Description |
|---|---|---|
kv_connector | RBLNLMCacheConnectorV1 | Connector name, registered by RBLN vLLM. |
kv_role | kv_both | The instance both stores and restores KV cache. |
Verify offloading¶
First check startup, store, and restore logs:
| Log | Meaning |
|---|---|
RDS staging buffer: 2048 MiB | The staging budget was resolved. This does not confirm memory allocation or I/O success. |
RDS _sync_batched_write: issuing N offloads | A write batch started. Check subsequent errors before treating it as successful. |
RDS batched_get_blocking: requested=N, hot_cache hits=M | The in-memory index contains M requested NVMe entries. hot_cache is an index, not a host KV-data tier. |
RDS batched_get_blocking: issuing N restores | Restore calls are about to run. A later error can still prevent retrieval. |
To check a restore, start the server with --no-enable-prefix-caching and send the same prompt, longer than one chunk, twice. If vllm:external_prefix_cache_hits_total in /metrics is higher after the second request than before the first, the second request reused KV from the offload tier. For RDS, also check that the log shows Retrieved N out of N required tokens with no RDS batched write failed error. Turn prefix caching back on afterward. If no tokens are retrieved, see Troubleshooting.
Troubleshooting¶
RDS batched write failed¶
This message reports a batch write failure. Check the following traceback for the cause. Failed writes are not published as new entries in the RDS index.
| Symptom | What to check |
|---|---|
NVMe not enabled or RDS unavailable | Check the host binding service, its journal, and runtime device visibility in Prerequisites. Restart the server after correcting host setup. |
Staging allocation fails or staging pool exhausted | Check available NPU memory, KV pool size, chunk size, and the staging budget. Increasing the budget does not create physical memory; reduce memory pressure first. |
| KV pool allocation fails during startup | Size the pool for the workload. --num-gpu-blocks-override can set an explicit block count when automatic sizing fails; RDS tests use 32 blocks with Qwen3-1.7B and block size 1024, not a universal production value. |
| Repeated offload failures with LRU eviction | Inspect the original exception. In ignore mode, non-capacity errors can also cause eviction and retries; this does not by itself prove NVMe is full. rds_failure_policy=fail avoids eviction retries for non-capacity write errors. |
No cache stores or restores¶
Confirm that lmcache-rbln is installed in the server environment, --model-impl vllm is selected, and the intended backend loaded. Check the effective chunk size and prompt token count. For RDS, keep LMCACHE_LOCAL_CPU=False and LMCACHE_MAX_LOCAL_CPU_SIZE=0 to use device staging as the primary allocator.
A repeated request may be served entirely by NPU prefix caching or sub-block caching. To isolate external retrieval, follow Verify offloading. RDS entries are lost on server restart, so the first request after a restart must populate the cache again.
Limitations¶
- Sub-block prefix caching and a KV connector both extend a full-block prefix cache hit, and the scheduler runs only one of them per request, taking whichever offers more tokens, with sub-block winning a tie. See Prefix Caching.