Skip to main content

Peer-to-peer RDMA zero-copy L3 KV-cache backend for SGLang HiCache

Project description

PeerCache

English · 简体中文

CI Docs License

A lightweight, peer-to-peer L3 storage backend for SGLang HiCache, built for PD-disaggregated (prefill/decode) inference: prefill workers publish KV pages, decode workers read them back over RDMA with zero CPU copies.

Docs: https://flymysql.github.io/PeerCache/

PeerCache gives you Mooncake-style RDMA zero-copy KV-cache sharing across nodes, but without the centralized master + metadata services. Instead it uses:

  • Embedded service discovery — no separate meta process. One node (chosen by discovery_addr) auto-hosts the discovery service in-process; nodes register their endpoint, heartbeat, and pull the live membership list.
  • A consistent-hash distributed directory (DHT) — the mapping key -> {data_node, remote_addr, rkey, length} is sharded across all nodes by hashing the key. There is no central metadata store.
  • Data stays local on writeset() copies the page into a node-local published pool (a host memcpy, no network, no master) and pushes only a tiny location record to the directory.
  • One-sided RDMA READ on readget() looks up the directory, then issues a zero-copy IBV_WR_RDMA_READ straight into SGLang's registered host buffer.
  • Concurrent multi-threaded I/O — a per-peer channel pool (each an RC QP with its own completion queue) lets reader/writer threads run with no shared-CQ contention; the control plane parallelises directory lookups too.
  • Disk persistence tier (L4) — pages evicted from memory spill to disk (default /data/peercache/, 100GB) and are promoted back into the pool on a later read (locally or by a remote reader).
  • Built-in monitoring — Prometheus /metrics + an embedded HTML dashboard (default port 31997): hit rate, throughput, latency p50/p99, mem/disk usage.

Architecture

PeerCache splits into a C++ data plane (raw RDMA verbs) and a Python control plane (discovery, directory, pool). The meta node only tracks membership; the key -> location map is sharded across every node by consistent hashing, and the KV bytes never leave the node that produced them until a peer reads them directly.

flowchart LR
    subgraph A["Node 0 — prefill / producer"]
        S0["PeerCacheStore"]
        P0[("Published pool MR (LRU)")]
        D0["Directory shard"]
    end
    subgraph B["Node 1 — decode / consumer"]
        S1["PeerCacheStore"]
        R1[("Receive MR = SGLang kv_buffer")]
        D1["Directory shard"]
    end
    M(["Embedded discovery / membership"])

    S0 -- "set(): local memcpy" --> P0
    S0 -- "PUT key→loc (hash)" --> D1
    S1 -- "GET key (hash)" --> D0
    S1 == "one-sided RDMA READ (zero copy)" ==> P0
    P0 -. "lands directly in" .-> R1
    S0 -. "register / heartbeat" .-> M
    S1 -. "register / heartbeat" .-> M
write:  set() ── local memcpy ──> published pool MR
                └── PUT key->{node,addr,rkey,len} ──> directory shard (hash(key))
read:   get() ── GET key ──> directory shard ──> {node,addr,rkey,len}
                └── one-sided RDMA READ ──> local host buffer (zero copy)
  • C++ data plane (cpp/): raw libibverbs + librdmacm. RC QPs, one-sided READ/WRITE, per-peer channel pool with private CQs for concurrency. Exposed to Python via pybind11 as the _peercache module.
  • Python control plane (python/peercache/): TCP RPC, service discovery, consistent-hash ring, distributed directory, and the published-pool with LRU.
  • TCP fallback transport: a pure-Python transport that mirrors the RDMA API so the design can be validated end-to-end on machines without RDMA hardware.

Two-MR model (correctness)

SGLang's host KV buffer is the L2 tier and is evicted/overwritten by HiCache, so we cannot register its address into the directory directly (dangling reference). Each node therefore registers two memory regions:

  1. Receive MR = mem_pool_host.kv_buffer — destination of one-sided READ on get.
  2. Published pool MR = a backend-owned host pool with LRU — source of READ on remote nodes. set memcpys the page into this pool (node-local, no network) and publishes its addr+rkey+len to the directory. Eviction from the pool deletes the corresponding directory entry, so a published address stays valid until evicted.

See the Architecture docs for the full design.

Why simpler than Mooncake?

Mooncake PeerCache
metadata central master + metadata service sharded directory (consistent hash)
data placement dedicated managed pool stays on producing node
coordination master allocates / tracks objects only service discovery on meta node
transfer RDMA zero-copy RDMA zero-copy (one-sided READ)

Install

From PyPI (recommended)

pip install peercache

This builds the C++ data plane from source, so the target host needs a C++17 toolchain, CMake ≥ 3.18, and the RDMA dev headers (libibverbs / librdmacm, e.g. rdma-core or Mellanox OFED). If those headers are absent, the build automatically falls back to a stub module and the pure-Python TCP transport.

To force the no-RDMA build explicitly (control plane + TCP fallback only, e.g. on a laptop or in CI):

pip install peercache --config-settings=cmake.define.PEERCACHE_NO_RDMA=ON

From source

git clone https://github.com/flymysql/PeerCache.git
cd PeerCache
pip install .                 # or: pip install -e ".[test]"

Run with SGLang

The meta service is embedded — there is no separate meta process. Point discovery_addr at one node's IP on every node; the node whose IP matches auto-starts the discovery service in-process.

# On every SGLang node, set discovery_addr to the SAME node's IP (say node-0).
# node-0 detects the IP is itself and hosts the embedded meta automatically.
python -m sglang.launch_server --enable-hierarchical-cache \
  --hicache-storage-backend dynamic \
  --hicache-storage-backend-extra-config \
  '{"backend_name":"peercache","module_path":"peercache.store","class_name":"PeerCacheStore","discovery_addr":"NODE0_IP:31998","protocol":"rdma","device_name":"mlx5_0","global_segment_size":"4gb"}'

(Optionally, you can still run a standalone meta with peercache-meta --bind 0.0.0.0:31998 if you prefer a dedicated discovery host.)

See examples/sglang_launch.md for details.

Benchmarks

A systematic benchmark suite ships inside the package and is exposed as a single console command (no repo clone, no PYTHONPATH). It drives PeerCache's HiCacheStorage interface exactly as SGLang HiCache does (PD-disaggregated batch_set_v1 / batch_exists / batch_get_v1) and reports throughput (pages/s, tokens/s, GB/s) and latency tail (p50/p95/p99/p999/max) across a sweep of thread models, including the full-load saturation/peak throughput.

pip install peercache

# RDMA hardware (publishable numbers)
peercache-bench suite --device-name mlx5_0 --layout mla --page-size 131072 \
    --batch-size 32 --concurrencies 1,2,4,8,16,32,64 --duration 10 --tag rdma

peercache-bench subcommands: latency, throughput, saturation, suite (SGLang-HiCache), plus micro, mooncake, compare.

RDMA-first. PeerCache is built on RDMA one-sided READ; publishable figures must be measured on RDMA hardware. The TCP fallback is for functional smoke testing only and must not be quoted. See the bench README and the Benchmarks docs for the methodology, thread models, metric definitions, and reproduction recipe.

Test

pip install -e ".[test]"
pytest -q

Maintainer setup (one-time)

  • GitHub Pages: Settings → Pages → Build and deployment → Source = GitHub Actions. The Docs workflow then publishes to https://flymysql.github.io/PeerCache/ on every push to main.
  • PyPI Trusted Publishing: on the PyPI peercache project, add a GitHub publisher (owner flymysql, repo PeerCache, workflow release.yml, environment pypi). Tagging vX.Y.Z then builds the sdist, attaches it to a GitHub Release, and publishes to PyPI. Until configured, the PyPI step is non-blocking and the GitHub Release still ships the package.

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

peercache-0.3.0.tar.gz (107.3 kB view details)

Uploaded Source

Built Distributions

If you're not sure about the file name format, learn more about wheel file names.

peercache-0.3.0-cp312-cp312-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl (178.1 kB view details)

Uploaded CPython 3.12manylinux: glibc 2.27+ x86-64manylinux: glibc 2.28+ x86-64

peercache-0.3.0-cp311-cp311-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl (176.5 kB view details)

Uploaded CPython 3.11manylinux: glibc 2.27+ x86-64manylinux: glibc 2.28+ x86-64

peercache-0.3.0-cp310-cp310-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl (175.6 kB view details)

Uploaded CPython 3.10manylinux: glibc 2.27+ x86-64manylinux: glibc 2.28+ x86-64

peercache-0.3.0-cp39-cp39-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl (176.3 kB view details)

Uploaded CPython 3.9manylinux: glibc 2.27+ x86-64manylinux: glibc 2.28+ x86-64

File details

Details for the file peercache-0.3.0.tar.gz.

File metadata

  • Download URL: peercache-0.3.0.tar.gz
  • Upload date:
  • Size: 107.3 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.12

File hashes

Hashes for peercache-0.3.0.tar.gz
Algorithm Hash digest
SHA256 4faa6cbca573efb08f1e21ea5ffd00d89aac4de2fb30a8fc40540df18a93d67b
MD5 345d9a4e15cae76d1e71d29aee25b044
BLAKE2b-256 f1f4f09dd1d521a1e529c73c6621b59ff4fbf7c16244c93250e332de8f03f09d

See more details on using hashes here.

Provenance

The following attestation bundles were made for peercache-0.3.0.tar.gz:

Publisher: release.yml on flymysql/PeerCache

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file peercache-0.3.0-cp312-cp312-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl.

File metadata

File hashes

Hashes for peercache-0.3.0-cp312-cp312-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl
Algorithm Hash digest
SHA256 29d6296ede28465b0580e022d5041c2726dfaa1e9fbc3eaa72a42d4b6582cfc3
MD5 1a47e3edc7e0588968312679a826649c
BLAKE2b-256 1be96048d204481b5c565fd78550562344eebfbf3d658409c3966d8687a90e4d

See more details on using hashes here.

Provenance

The following attestation bundles were made for peercache-0.3.0-cp312-cp312-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl:

Publisher: release.yml on flymysql/PeerCache

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file peercache-0.3.0-cp311-cp311-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl.

File metadata

File hashes

Hashes for peercache-0.3.0-cp311-cp311-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl
Algorithm Hash digest
SHA256 15c3ff9a2c81ddcac9a1c314f1a5502a6981dfafb2ccd0b4d8ca8fbbe0455735
MD5 a18ae60c3fd7e94d39c1c287910d9596
BLAKE2b-256 10d4cf14f80554157591808a196258edbc6d1ab3188371edea2822bd78d4d4f6

See more details on using hashes here.

Provenance

The following attestation bundles were made for peercache-0.3.0-cp311-cp311-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl:

Publisher: release.yml on flymysql/PeerCache

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file peercache-0.3.0-cp310-cp310-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl.

File metadata

File hashes

Hashes for peercache-0.3.0-cp310-cp310-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl
Algorithm Hash digest
SHA256 d2b13e3d25531430fb503ac012ead2763fb7b66b3a20a2240c275d165c4953f3
MD5 dc96bcfd4cb1cf5adef6cfd524a2ead2
BLAKE2b-256 38fb7183ccf80e0a24426b20723add89e94df3c61da5cb7288e832c3dcfd13c0

See more details on using hashes here.

Provenance

The following attestation bundles were made for peercache-0.3.0-cp310-cp310-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl:

Publisher: release.yml on flymysql/PeerCache

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file peercache-0.3.0-cp39-cp39-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl.

File metadata

File hashes

Hashes for peercache-0.3.0-cp39-cp39-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl
Algorithm Hash digest
SHA256 edcbdb477710a55761de9b582371ffc971fa18466df88ab462437324a59de0bc
MD5 b25406ec9d8f2c801d6c44511821f739
BLAKE2b-256 a4b6f624ffcf235c7b4a66863b5d8d5fffc21cdc98f6a851ba651f024663c4dc

See more details on using hashes here.

Provenance

The following attestation bundles were made for peercache-0.3.0-cp39-cp39-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl:

Publisher: release.yml on flymysql/PeerCache

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page