Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
25 changes: 25 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -238,6 +238,31 @@ jobs:
DFKV_SERVER_URING=1 ./build/rdma_lease_loopback_test --gtest_output=xml:lease-uring.xml
./build/rdma_lease_client_test --gtest_output=xml:lease-client.xml
python3 -c 'import xml.etree.ElementTree as E; roots=[E.parse(p).getroot() for p in ("lease-sync.xml","lease-uring.xml","lease-client.xml")]; assert all(int(r.attrib["tests"]) > 0 and not list(r.iter("skipped")) and not list(r.iter("failure")) for r in roots)'
- name: Exercise RDMA through the shipped runtime image
if: steps.rxe_probe.outputs.ok == 'true'
run: |
set -eu
docker build --target runtime -t dfkv-runtime-rdma .
id=$(docker run -d --privileged --network host \
--ulimit memlock=-1:-1 -e DFKV_RDMA_DEV=rxe0 \
dfkv-runtime-rdma --dir /tmp/dfkv-data \
--port 12000 --rdma-port 12001 \
--metrics-port 12010 --metrics-bind 127.0.0.1 \
--cap 67108864 --store-engine file)
trap 'docker logs "$id"; docker rm -f "$id" >/dev/null' EXIT
ready=0
for attempt in $(seq 1 60); do
if docker exec "$id" dfkvctl stat 127.0.0.1:12000 \
| grep -q 'dfkv_server_ready 1'; then
ready=1
break
fi
test "$(docker inspect -f '{{.State.Running}}' "$id")" = true
sleep 1
done
test "$ready" = 1
docker exec -e DFKV_RDMA=1 -e DFKV_RDMA_DEV=rxe0 "$id" \
dfkv_smoke --members n=127.0.0.1:12001 --size 1048576
- name: Build + run RDMA datapath test under ThreadSanitizer (hard gate when rxe works)
if: steps.rxe_probe.outputs.ok == 'true'
run: |
Expand Down
17 changes: 17 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,23 @@

## Unreleased

### v2.27.0 — Runtime RDMA providers and native hybrid-state integration

- Include `ibverbs-providers` in the runtime image; exposing RDMA devices does
not make them discoverable when the userspace hardware plugins are absent.
- Exercise real RDMA PUT/GET through the built runtime image when the CI
hardware probe succeeds, rather than relying on version or TCP-only checks.
- Refresh the shipped SGLang hybrid Mamba/DSA patch for the pinned native
GLM-5.3-Flash image, preserving indexer sidecars and actual scaled-MLA host
geometry with the current allocator API.
- Add a bounded real-GPU offload/poison/restore regression for KV, indexer,
temporal and convolution state, without model weights.
- Ship a targeted native vLLM GLM-5.3-Flash V2-runner patch: exclude the
single-block kpool tail from generic position-indexed slot mapping, retaining
the dedicated circular metadata builder and existing allocation policy.
- Document strict patch applicability and fresh cache generations. Native
client/server wire formats and connector runtime code are unchanged.

### v2.26.4 — SGLang DeepSeek-V4.1 HiCache deployment guidance

- Add the verified preview-image HiCache/L3 recipe and physical side-pool
Expand Down
4 changes: 2 additions & 2 deletions Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
# DFKV_STATIC_LIBSTDCXX folds libstdc++/libgcc into the artifacts (those are NOT
# glibc; static-linking them removes a separate runtime dep). libibverbs CANNOT
# be static (it dlopen()s provider drivers at runtime), so the run node still
# needs rdma-core / libibverbs installed.
# needs rdma-core / libibverbs and their hardware provider plugins installed.
# ubuntu:22.04, pinned so a release tag always rebuilds from identical bytes.
ARG DFKV_BASE_IMAGE=docker.io/library/ubuntu@sha256:3b06811b2afd352be909dd088a004166d665dc76d38b13eada33522a9d915c6f
FROM ${DFKV_BASE_IMAGE} AS build
Expand All @@ -29,7 +29,7 @@ RUN cmake -S . -B build -G Ninja -DCMAKE_BUILD_TYPE=Release -DDFKV_BUILD_TESTS=O

FROM ${DFKV_BASE_IMAGE} AS runtime
RUN apt-get update && apt-get install -y --no-install-recommends \
rdma-core libibverbs1 && rm -rf /var/lib/apt/lists/*
rdma-core libibverbs1 ibverbs-providers && rm -rf /var/lib/apt/lists/*
COPY --from=build /out/ /usr/local/
RUN ldconfig
EXPOSE 12000
Expand Down
2 changes: 1 addition & 1 deletion VERSION
Original file line number Diff line number Diff line change
@@ -1 +1 @@
2.26.4
2.27.0
51 changes: 40 additions & 11 deletions docs/CONNECTORS.md
Original file line number Diff line number Diff line change
Expand Up @@ -532,23 +532,41 @@ sglang serve /models/glm-5.2-nvfp4 --served-model-name glm-5.2 \
MR,无 payload memcpy。
- MLA 下插件自动单对象、无 rank 后缀、`backup_skip`(仅 tp_rank0 写)。decode 共享前缀配同 members。
- **多池模型**(Mamba/SWA/DeepSeek-V4)用 v2 PoolTransfer 接口(插件已实现)。
DSA/DeepSeekV4 主 `kv` 池是无数据的 LogicalHostPool(`get_page_buffer_meta→None`),
插件对其 `batch_set_v1` 写空 marker 锚定命中前缀、`batch_get_v1` no-op,真实 KV 走 v2 侧池。
部分 DeepSeek-V4 等引擎的主 `kv` 是无数据 LogicalHostPool(`get_page_buffer_meta→None`):
插件写 marker 锚定前缀,主池读取不搬运字节,实际数据走 v2 侧池。普通 MLA/DSA
的主 `kv` 可以是真实物理池;必须按运行时布局核对,不能将所有 DSA 都当作 marker。
- **Mamba+DSA 混合模型必须同时注册 `KV`、`MAMBA`、`INDEXER`。**
只恢复 latent 与 recurrent state、遗漏历史 indexer 数据,会出现“所有已请求
对象均命中,但长提示答案错误”;不能通过增加生成长度或把命中计数当作正确性
来跳过检查。SGLang 的普通 DSA 路径正确注册 sidecar,不代表混合路径也已注册。
对尚缺该接线的引擎,随包提供
[混合 DSA indexer 修复补丁](../integration/hicache/patches/sglang-hybrid-mamba-dsa-indexer.patch)。
它修复引擎的 host-pool entry 与 `SidecarPoolSpec` 两处声明,不改变 dfkv
value/wire 格式。补丁的实测源文件是
`python/sglang/srt/mem_cache/hybrid_cache/hybrid_pool_assembler.py`,
原始 SHA256 为 `48456e7ce2cf20f839d100333404c90ba1d65b370a7f8265e9bc044ec18c2216`;
应在对应 SGLang 源码树先执行 `git apply --check`,再应用、重建或部署受控
overlay。不要盲目覆盖其它引擎版本。启动池描述必须包含 `INDEXER`,并对原始
长提示执行完整进程重启后的 L3 回载与答案校验;旧的缺 indexer 缓存不能视为
上游 SGLang main(2026-09-08 核对)仍未在 `build_hybrid_mamba_stack` 注册
INDEXER,该补丁对当前上游同样适用,并非仅限旧镜像。
它补齐 host-pool entry 与 `SidecarPoolSpec`,并让 MLA 宿主页使用设备池实际
`kv_cache_dim`,避免带缩放布局被默认维度截断;不改变 dfkv value/wire 格式。
当前补丁针对官方 `lmsysorg/sglang:glm-5.3-flash` 的
`0.0.0.dev1+gf609d677b` 构建,镜像 digest 为
`sha256:a2c0f7d4d9ebce97a2707c5415081d284d741db1033a1008a955453b9b5255bf`。
目标文件是 `python/sglang/srt/mem_cache/hybrid_cache/hybrid_pool_assembler.py`,
原始 SHA256 为 `6689d642d7868e66a34cd95ef09e5d710ef6f40fd053ca2f1f7d04afe99223ff`。
先核对源文件,再严格检查和应用补丁;禁止用 fuzzy apply 跨版本套用。
例如在该镜像内将 dfkv 仓库挂载到 `/dfkv` 后:

```bash
git -C /sgl-workspace/sglang apply --check \
/dfkv/integration/hicache/patches/sglang-hybrid-mamba-dsa-indexer.patch
git -C /sgl-workspace/sglang apply \
/dfkv/integration/hicache/patches/sglang-hybrid-mamba-dsa-indexer.patch
python3 /dfkv/integration/hicache/tests/gpu_hybrid_state_roundtrip.py \
--include-scaled-mla
```

[GPU 状态回归](../integration/hicache/tests/gpu_hybrid_state_roundtrip.py)使用真实池、
分配器和 CUDA 传输:卸载后改写全部设备字节,再恢复到不同槽位,逐字节验证
KV、INDEXER、temporal 与 conv 状态。它不加载模型权重,也不代替整模型、
多 rank、L3 或完整进程重启验收。部署时必须记录补丁和派生镜像身份,
启动池描述须包含 `INDEXER`;使用新的 `model_revision`,不能复用曾遗漏
indexer 或截断状态的旧缓存。其它引擎版本应重新核对接口与状态恢复,不能
从此目标构建外推适用性。
- **identity/layout 必须协同发布。** namespace 使用 SGLang runtime 给出的精确
`model_name` + `sglang-hicache/raw-v1`;同一模型的 pool/hash/并行坐标/component
进入 canonical object key。dfkv value 只有 raw bytes,不会检查 page size、
Expand Down Expand Up @@ -850,6 +868,17 @@ lsmod | grep nvidia_peermem
逻辑 block 数折叠物理 tile 轴,完整收集每个逻辑 block 的所有 bytes,不能
直接把逻辑 block ID 用作 kernel-tile 索引。

#### GLM Flash 原生 V2 runner 的循环尾状态映射

`vllm/vllm-openai:glm53-flash` 的 `g385dce36b` 将 `KpoolTailSpec` 错当作
普通位置索引缓存:长 prefill 在通用 slot-mapping 内核中越界,异步错误可能
随后表现为 KDA 投影的 cuBLAS 失败。无 dfkv 连接器也会触发。
随包提供 [循环尾映射补丁](../integration/vllm/patches/vllm-glm53flash-kpool-tail-slot-mapping.patch),
仅让该类型跳过通用映射;已有 `KpoolTailMetadataBuilder` 仍按每请求的
首块与 `position % kpool` 生成真实尾状态位置。保留原表宽、APC、模型和请求长度。
补丁针对上述源码版本,应用前运行 `git apply --check`,不盲目应用到其他版本。
原短—短—长请求故障序列在修复后通过;这项引擎回归不替代 L3 字节完整性和性能验收。


#### 混合模型的 KV 加载故障恢复

Expand Down
4 changes: 2 additions & 2 deletions docs/DEPLOY.md
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ deploy/package_release.sh build release
tar tzf "release/dfkv-$(cat VERSION)-linux-x86_64.tar.gz"
ldd build/libdfkv.so | grep ibverbs
```
依赖:`libibverbs-dev`(构建期)+ 运行节点装 `rdma-core`。无 RDMA 也可去掉 `-DDFKV_WITH_RDMA` 构建纯 TCP 版。
依赖:`libibverbs-dev`(构建期);运行节点须安装 libibverbs 及对应硬件 provider。Ubuntu/Debian 运行包为 `rdma-core libibverbs1 ibverbs-providers`,只装前两项不足以发现设备。发布的 runtime 镜像包含这三项;设备透传不能替代用户态 provider。无 RDMA 也可去掉 `-DDFKV_WITH_RDMA` 构建纯 TCP 版。
> QP 信息走 TCP bootstrap 交换(非 librdmacm),所以只依赖 libibverbs,不需要 librdmacm。
> CacheLib/Navy 不是 v2.0.0 的构建依赖,也没有占位 backend/CMake 开关;
> 评估结论、兼容性差距和重开条件见
Expand All @@ -51,7 +51,7 @@ ldd build/libdfkv.so | grep ibverbs
> 直接构建的二进制不能部署到 glibc 2.35。CI 的 portable job 和仓库根
> `Dockerfile` 都固定 Ubuntu 22.04 + RDMA + 静态 libstdc++,并构建同一
> canonical tarball。`DFKV_STATIC_LIBSTDCXX` 只静态链接 libstdc++/libgcc;
> libibverbs 仍动态加载 provider,运行节点必须安装 rdma-core。
> libibverbs 仍动态加载 provider,运行节点必须同时具备对应插件。镜像验收要在可用 RDMA 设备上完成真实 PUT/GET;仅 `--version` 或 TCP 冒烟不能证明 RDMA 可用。

## 2. 每节点:分发 + 缓存目录

Expand Down
2 changes: 1 addition & 1 deletion integration/common/pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"

[project]
name = "dfkv-common"
version = "2.26.4"
version = "2.27.0"
description = "Canonical namespace and pool-key schema shared by dfkv connectors"
requires-python = ">=3.9"

Expand Down
27 changes: 18 additions & 9 deletions integration/hicache/patches/sglang-hybrid-mamba-dsa-indexer.patch
Original file line number Diff line number Diff line change
@@ -1,15 +1,23 @@
--- a/python/sglang/srt/mem_cache/hybrid_cache/hybrid_pool_assembler.py
+++ b/python/sglang/srt/mem_cache/hybrid_cache/hybrid_pool_assembler.py
@@ -695,6 +695,8 @@
storage_backend_extra_config: Optional[dict] = None,
enable_storage_metrics: bool = False,
@@ -724,7 +724,7 @@
) -> tuple[HostPoolGroup, HybridCacheController]:
+ from sglang.srt.mem_cache.memory_pool import DSATokenToKVPool
+
transfer_layer_num = len(full_layer_mapping | mamba_layer_mapping)
mamba_allocator = params.req_to_token_pool.mamba_allocator
- from sglang.srt.mem_cache.memory_pool import HybridLinearKVPool
+ from sglang.srt.mem_cache.memory_pool import DSATokenToKVPool, HybridLinearKVPool

mtp_draft_device_pools = tuple(
@@ -748,6 +750,24 @@
pool.full_kv_pool if isinstance(pool, HybridLinearKVPool) else pool
@@ -739,6 +739,7 @@
kv_pool=kv_pool,
page_size=params.page_size,
use_mla=use_mla,
+ override_kv_cache_dim=kv_pool.kv_cache_dim if use_mla else None,
host_size=kv_host_size,
mtp_draft_device_pools=mtp_draft_device_pools,
)
@@ -778,6 +779,25 @@
device_free_fn=mamba_allocator.free,
),
]
Expand All @@ -20,7 +28,7 @@
+ kv_pool,
+ kv_host_pool,
+ get_memory().hicache_mem_layout,
+ allocator_type=_get_allocator_type(server_args),
+ allocator_type=_get_allocator_type(),
+ )
+ entries.append(
+ build_pool_entry(
Expand All @@ -29,12 +37,13 @@
+ device_pool=kv_pool,
+ layer_mapping=full_layer_mapping,
+ transfer_layer_num=transfer_layer_num + len(mtp_draft_device_pools),
+ packed_draft_device_pools=mtp_draft_device_pools,
+ )
+ )
host_pool_group = HostPoolGroup(entries)
cache_controller = HybridCacheController(
params.token_to_kv_pool_allocator,
@@ -1311,6 +1331,11 @@
@@ -1345,6 +1365,11 @@
storage_backend_extra_config=storage_backend_extra_config,
enable_storage_metrics=enable_storage_metrics,
)
Expand All @@ -46,7 +55,7 @@
return StackBuildResult(
host_pool_group=host_pool_group,
cache_controller=cache_controller,
@@ -1318,9 +1343,10 @@
@@ -1352,9 +1377,10 @@
ComponentType.FULL: host_pool_group.get_pool(PoolName.KV),
ComponentType.MAMBA: host_pool_group.get_pool(PoolName.MAMBA),
},
Expand Down
Loading
Loading