从零开始部署 Rectifiers 协同加速层,集成 GPUStack 实例、配置 LMCache 和 RDMAS 存储,完成端到端验证。
Rectifiers 为 vLLM/SGLang 多 GPU 推理集群提供缓存感知路由和动态 P:D 比例调优。部署涉及以下组件:
GPUStack (worker 生命周期) ──→ Rectifiers (路由+编排) ──→ RDMAS (共享存储)
│
LMCache Connector (PyO3 plugin)
| 组件 | 职责 | 端口 | 部署个数 |
|---|---|---|---|
| Rectifiers (Director+Router 合并) | 缓存索引 + 请求路由 | HTTP :8080, gRPC :9200 | 1 |
| Orchestrator | P:D 比例自动调优 | gRPC :9201 | 1 |
| RDMAS Storage | One-Sided RDMA 共享 KV cache 存储 | gRPC :9400 | ≥1 |
| vLLM Workers | 推理引擎(Preffill + Decode) | :8000 | ≥4 |
| LMCache Connector | KV cache 写入后自动上报 Director | 嵌入 vLLM 进程 | 每 worker 1 个 |
| 组件 | 最低 | 推荐 |
|---|---|---|
| GPU 节点 | 1 × A100/H100 (80GB) | 4-8 × A100/H100 |
| RDMAS 存储节点 | 128GB RAM + RDMA NIC | 512GB RAM + 100Gbps RoCEv2 |
| Rectifiers 节点 | 2 CPU, 2GB RAM | 4 CPU, 4GB RAM (可与 GPU 节点同机) |
# Rust 工具链
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh
rustup default 1.80
# protoc (gRPC proto 编译)
sudo dnf install protobuf-compiler # Fedora
sudo apt install protobuf-compiler # Ubuntu/Debian
# RDMA (RDMAS 存储节点需要)
sudo dnf install libibverbs-devel rdma-core # Fedora
sudo apt install libibverbs-dev ibverbs-utils # Ubuntu/Debian
# Docker (可选)
sudo dnf install docker docker-compose
sudo systemctl enable --now docker
# 分配 HugePages (512GB = 262144 × 2MB)
sudo bash -c 'echo 262144 > /proc/sys/vm/nr_hugepages'
# 永久生效
echo 'vm.nr_hugepages=262144' | sudo tee /etc/sysctl.d/99-hugepages.conf
# 验证
grep HugePages_Total /proc/meminfo
# HugePages_Total: 262144
git clone https://github.com/ipconfiger/rectifiers
cd rectifiers
# 编译所有组件(Release 模式)
cargo build --workspace --release
# 产物:
# target/release/rectifiers # Director + Router 合并 (推荐)
# target/release/director # 独立 Director (开发用)
# target/release/rdmas-router # 独立 Router (开发用)
# target/release/orchestrator # Orchestrator
# 1) 编译镜像
docker build -t rectifiers -f docker/Dockerfile.rectifiers .
docker build -t rectifiers-orchestrator -f docker/Dockerfile.orchestrator .
# 2) 启动 (docker-compose)
docker compose -f docker/docker-compose.yml up -d
# 3) 查看状态
docker compose -f docker/docker-compose.yml ps
# NAME STATUS
# rectifiers Up (healthy) :8080, :9200
# rectifiers-orchestrator Up :9201
# mock-vllm Up :8010
# 1) 部署 Rectifiers (Director + Router 合并, replicas=1)
kubectl apply -f k8s/rectifiers.yaml
# 2) 部署 Orchestrator (含 RBAC)
kubectl apply -f k8s/orchestrator.yaml
# 3) 验证
kubectl get pods,svc
# NAME READY STATUS
# pod/rectifiers-xxxx 1/1 Running
# pod/rectifiers-orchestrator-xx 1/1 Running
# service/rectifiers ClusterIP :8080,:9200
# service/rectifiers-orchestrator ClusterIP :9201
# Terminal 1: Rectifiers (合并模式, HTTP :8080 + gRPC :9200)
cargo run -p rectifiers --release
# Terminal 2: Orchestrator
RECTIFIERS_CONFIG=examples/rectifiers_config.json cargo run -p rdmas-orchestrator --release
Rectifiers 合并二进制使用 Router 配置格式,无需 DIRECTOR_ADDR(默认内部直连):
{
"listen_addr": "[::]:8080",
"tenant_id": "default",
"model_name": "llama-70b",
"block_size": 16,
"cache_salt": "",
"worker_endpoints": ["http://vllm-worker-0:8000"]
}
Orchestrator 配置见 examples/rectifiers_config.json:
{
"orchestrator": {
"listen_addr": "[::]:9201",
"director_addr": "http://rectifiers:9200",
"tenant_id": "default",
"model_name": "llama-70b",
"auto_tune": {
"enabled": true,
"evaluation_interval_secs": 30,
"hit_rate_low_watermark": 0.3,
"hit_rate_high_watermark": 0.8,
"min_prefill": 2, "max_prefill": 6,
"min_decode": 2, "max_decode": 6,
"prefill_deployment": "vllm-prefill",
"decode_deployment": "vllm-decode",
"dry_run": true
}
}
}
dry_run: true 时 Orchestrator 只记录建议,不实际扩缩。确认无误后改为 false。
cd /path/to/rdmas
cargo run --release
# ControlPlane gRPC 监听 :9400
# 检查节点可达
grpcurl -plaintext 10.0.0.1:9400 rdmas.control.ControlPlane/Discover
# 预期输出: ServerMetadata { generation: 1, bucket_count: ..., regions: [...] }
┌────────────────────────────────────────────┐
│ RDMAS Storage Cluster │
│ │
│ Node 0 (10.0.0.1:9400) ← 主 │
│ Node 1 (10.0.0.2:9400) │
│ Node 2 (10.0.0.3:9400) │
│ │
│ Rectifiers 不需要感知节点拓扑。 │
│ Connector 上报 (node_id, block_hashes) │
│ 后,Director 自动建立索引。 │
└────────────────────────────────────────────┘
Rectifiers 与 RDMAS 的关联通过 Connector 上报表建立——不需要在 Rectifiers 配置中硬编码 RDMAS 节点地址。
GPUStack 的 AI Gateway (Higress) 将推理请求 upstream 指向 Rectifiers Router :8080,而非直接指向 vLLM workers:
Client → GPUStack Gateway → Rectifiers Router (:8080) → 最佳 vLLM Worker
配置 GPUStack AI Gateway upstream:
# GPUStack Higress McpBridge 配置
kubectl apply -f - <<EOF
apiVersion: networking.higress.io/v1
kind: McpBridge
metadata:
name: gpustack-gateway
spec:
registries:
- name: rectifiers
type: static
domain: rectifiers.default.svc.cluster.local
port: 8080
EOF
在 GPUStack 中创建 Custom Inference Backend:
backend_name: vllm-rectifiers-custom
default_entrypoint: vllm serve
default_execution_command: >
{{model_path}}
--host {{worker_ip}}
--port {{port}}
--served-model-name {{model_name}}
--tensor-parallel-size {{gpu_count}}
--enable-prefix-caching
--kv-transfer-config '{"kv_role":"kv_producer","kv_connector":"LMCacheConnectorV1"}'
--lmcache-config '{"type":"native_plugin","module_path":"lmcache_rdma_connector","class_name":"RDMANativeConnector","adapter_params":{"device":"mlx5_0","server":"10.0.0.1:9400","num_workers":4,"director_addr":"rectifiers:9200","node_id":"rdmas-0","tenant_id":"default","model_name":"{{MODEL_NAME}}","block_size":16,"instance_id":"prefill-{{WORKER_NODE}}","role":"prefill","rpc_endpoint":"http://{{worker_ip}}:{{port}}"},"eviction":{"eviction_policy":"LRU","trigger_watermark":0.8}}'
version_configs:
v1:
image_name: vllm-rectifiers:latest
custom_framework: cuda
backend_name: vllm-decode-rectifiers-custom
default_entrypoint: vllm serve
default_execution_command: >
{{model_path}}
--host {{worker_ip}}
--port {{port}}
--served-model-name {{model_name}}
--tensor-parallel-size {{gpu_count}}
--enable-prefix-caching
--kv-transfer-config '{"kv_role":"kv_consumer","kv_connector":"LMCacheConnectorV1"}'
--lmcache-config '{"type":"native_plugin","module_path":"lmcache_rdma_connector","class_name":"RDMANativeConnector","adapter_params":{"device":"mlx5_0","server":"10.0.0.1:9400","num_workers":4,"director_addr":"rectifiers:9200","node_id":"rdmas-0","tenant_id":"default","model_name":"{{MODEL_NAME}}","block_size":16,"instance_id":"decode-{{WORKER_NODE}}","role":"decode","rpc_endpoint":"http://{{worker_ip}}:{{port}}"},"eviction":{"eviction_policy":"LRU","trigger_watermark":0.8}}'
version_configs:
v1:
image_name: vllm-rectifiers:latest
custom_framework: cuda
# Dockerfile.vllm-rectifiers
FROM vllm/vllm-openai:v0.8.5
# 编译 RDMAS Connector (在 RDMAS 仓库中)
# cd /path/to/rdmas && cargo build -p lmcache-connector --features director --release
COPY lmcache_rdma_connector.so /usr/local/lib/python3.12/site-packages/
| 字段 | 必填 | 默认值 | 说明 |
|---|---|---|---|
device |
是 | — | RDMA 网卡名,如 mlx5_0 |
server |
是 | — | RDMAS 存储节点 host:9400 |
num_workers |
否 | 4 |
RDMA worker 线程数,建议与 GPU 数一致 |
batch_chunk_num_bytes |
否 | 16777216 |
批量聚合阈值 (16MB) |
director_addr |
否 | — | 设置后启用 Rectifiers 缓存上报。格式 host:9200 |
node_id |
是* | — | 当前 worker 所属 RDMAS 节点 ID,如 rdmas-0 |
tenant_id |
是* | — | 租户隔离标识 |
model_name |
是* | — | 模型名,与 Router 配置一致 |
block_size |
是* | 16 |
KV cache block 大小,必须与 Router 配置一致 |
instance_id |
否 | {node_id}-{ts} |
Worker 实例 ID,自动上报给 Director |
role |
否 | both |
prefill / decode / both |
rpc_endpoint |
否 | http://localhost:8000 |
Worker HTTP 地址,供 Director 返回给 Router |
* 启用 director_addr 后必填。
启用 director_addr 后,Connector 在启动时自动:
- Register — 向 Director 注册此 worker 实例(
instance_id,role,rpc_endpoint) - Heartbeat — 每 10 秒向 Director 发送心跳,保持注册有效
- ReportStore — 每次
submit_batch_set的 RDMA 写入完成后,在drain_completions中上报(node_id, block_hashes) - ReportRemove — 每次
submit_batch_delete完成后上报移除 - Deregister — 进程关闭时自动注销
cd /path/to/rdmas
cargo build -p lmcache-connector --features director --release
# 产物: target/release/liblmcache_rdma_connector.so
不设置 director_addr 时,Connector 退化为普通 RDMAS L2 存储后端,不向 Director 上报:
{
"type": "native_plugin",
"module_path": "lmcache_rdma_connector",
"class_name": "RDMANativeConnector",
"adapter_params": {
"device": "mlx5_0",
"server": "10.0.0.1:9400",
"num_workers": 4
}
}
# 1) Rectifiers HTTP 健康检查
curl http://localhost:8080/healthz
# {"status":"ok"}
# 2) Rectifiers gRPC 健康检查
grpcurl -plaintext localhost:9200 grpc.health.v1.Health/Check
# {"status":"SERVING"}
# 3) Orchestrator 状态
grpcurl -plaintext localhost:9201 rectifiers.orchestrator.Orchestrator/GetRecommendation
# 查看 Director 中已注册的实例
grpcurl -plaintext localhost:9200 rectifiers.director.Director/GetStats \
-d '{"tenant_id":"default","model_name":"llama-70b"}'
# {"hit_rate":0.0, "total_blocks_indexed":0, "prefill_instance_count":4, "decode_instance_count":4}
prefill_instance_count 和 decode_instance_count 应与非零值。
# 1) 发送一个推理请求,触发 KV cache 写入
curl -X POST http://localhost:8080/v1/completions \
-H "Content-Type: application/json" \
-d '{"prompt":"Explain quantum computing in simple terms","model":"llama-70b","max_tokens":32,"stream":false}'
# 2) 等待几秒后,查询 Director 索引状态
grpcurl -plaintext localhost:9200 rectifiers.director.Director/GetStats \
-d '{"tenant_id":"default","model_name":"llama-70b"}'
# {"total_blocks_indexed":128, ...} ← 应 > 0
# 3) 验证缓存感知路由
grpcurl -plaintext localhost:9200 rectifiers.director.Director/Query \
-d '{"tenant_id":"default","model_name":"llama-70b","block_hashes":[12345678901234567890],"block_size":16}'
# {"hits":[{"node_id":"rdmas-0","matched_blocks":1,...}]} ← 应有命中
# 完整缓存感知路由测试
# 第一次请求 (冷启动, 写入 KV cache)
time curl -X POST http://localhost:8080/v1/completions \
-H "Content-Type: application/json" \
-d '{"prompt":"What is the capital of France?","model":"llama-70b","max_tokens":10,"stream":false}'
# 第二次相同请求 (热缓存命中, 应从 RDMAS 加载 KV cache)
time curl -X POST http://localhost:8080/v1/completions \
-H "Content-Type: application/json" \
-d '{"prompt":"What is the capital of France?","model":"llama-70b","max_tokens":10,"stream":false}'
# 对比两次请求的延迟 — 第二次应明显快于第一次 (跳过了 prefill)
# 查看当前 P:D 比例 (dry_run 模式)
grpcurl -plaintext localhost:9201 rectifiers.orchestrator.Orchestrator/GetPDRatio
# {"prefill_count":4,"decode_count":4,"total_instances":8}
# 查看调优建议
grpcurl -plaintext localhost:9201 rectifiers.orchestrator.Orchestrator/GetRecommendation
# {"recommended_prefill":4,"recommended_decode":4,"reason":"stable"}
# 查看 Orchestrator 日志 (docker)
docker compose -f docker/docker-compose.yml logs orchestrator | grep -i "tick\|scale"
# 节点发现
grpcurl -plaintext 10.0.0.1:9400 rdmas.control.ControlPlane/Discover
# {"metadata":{"generation":1,"bucket_count":16777216,"regions":[...]}}
# 检查 RDMA 连通性
ibv_devinfo | grep -E "hca_id|link_layer|state"
# hca_id: mlx5_0
# link_layer: Ethernet
# state: PORT_ACTIVE (4)
# RDMAS 存储节点上
grep -E "HugePages_Total|HugePages_Free" /proc/meminfo
# HugePages_Total: 262144
# HugePages_Free: 262140 ← 应有足够空闲页
# 如果为 0,重新分配
sudo bash -c 'echo 262144 > /proc/sys/vm/nr_hugepages'
| 症状 | 原因 | 检查 |
|---|---|---|
grpcurl :9200 无响应 |
Director 未启动 | docker compose ps rectifiers |
prefill_instance_count: 0 |
Connector 未配置 director_addr |
检查 adapter_params 中的 director_addr |
total_blocks_indexed: 0 |
RDMA 写入失败或 drain_completions 未触发 |
检查 RDMAS 节点可达性、RDMA 网卡状态 |
| 缓存命中路由无效 | block_size 不一致 |
确认 Router 配置和 adapter_params 中的 block_size 相同 |
| Orchestrator 无建议 | dry_run: true 或 Director 不可达 |
检查 director_addr 配置、查看 Orchestrator 日志 |
replicas=1 无法扩展 Router |
设计约束 | 合并模式下 PrefixIndex 为内存状态,不支持水平扩展。若需扩展 Router,改用独立 Director + Router 模式 |
| Connector 编译失败 | 缺少 libibverbs |
sudo dnf install libibverbs-devel |
| vLLM 启动失败 | lmcache_rdma_connector.so 未找到 |
确认 .so 已打入镜像,路径在 site-packages/ 中 |
# Rectifiers 日志
docker compose -f docker/docker-compose.yml logs rectifiers
# Orchestrator 日志
docker compose -f docker/docker-compose.yml logs orchestrator
# RDMAS 日志 (直接运行的进程)
journalctl -u rdmas -f
# 查看所有注册实例
grpcurl -plaintext localhost:9200 rectifiers.director.Director/GetStats \
-d '{"tenant_id":"default","model_name":"llama-70b"}'
# 查看 Router 健康
curl http://localhost:8080/healthz
# 查看 P:D 比例
grpcurl -plaintext localhost:9201 rectifiers.orchestrator.Orchestrator/GetPDRatio
# RDMA 性能测试
ib_read_bw -d mlx5_0 -a -F --report_gbits 10.0.0.1
#!/bin/bash
set -e
echo "=== Rectifiers Deployment ==="
# 1. 编译
echo "[1/5] Building..."
cargo build --workspace --release
# 2. 构建镜像
echo "[2/5] Building Docker images..."
docker build -t rectifiers -f docker/Dockerfile.rectifiers .
docker build -t rectifiers-orchestrator -f docker/Dockerfile.orchestrator .
# 3. 启动服务
echo "[3/5] Starting services..."
docker compose -f docker/docker-compose.yml up -d
# 4. 等待就绪
echo "[4/5] Waiting for services..."
sleep 5
curl -s --retry 10 --retry-delay 2 http://localhost:8080/healthz
# 5. 验证
echo "[5/5] Verifying..."
grpcurl -plaintext localhost:9200 grpc.health.v1.Health/Check | grep SERVING
echo ""
echo "=== Deployment complete ==="
echo "Router: http://localhost:8080"
echo "gRPC: localhost:9200"
echo "Orch: localhost:9201"