目录

RDMemRPC

面向跨主机共享内存式环境的多路径高性能 RPC 运行时

RDMemRPC 是中国研究生操作系统开源创新大赛参赛项目。系统以 RDMA 注册内存为跨主机共享区域的原型载体,在用户态构建请求提交、远程执行、结果返回、资源回收、异常回退和并发会话管理的完整 RPC 调用闭环。

项目运行于 openEuler,基于标准 libibverbslibrdmacm 接口实现,不依赖 Mellanox 私有 API。运行时提供 EAGER、LAZY、BULK 和 TCP FALLBACK 四条实际调用路径,并根据请求规模、预期响应规模、RDMA 状态和远端资源压力自动选路。

系统边界说明

RDMemRPC 不是 CXL/UB 硬件实现,也不提供 CPU load/store 直接访问远端指针的硬件共享内存语义。项目使用 RDMA 单边读写访问对端注册内存,并在软件层组织出请求环、响应环、数据池、对象池和控制页,因此属于 shared-memory-like RPC runtime

目录

项目特点

1. 跨主机共享内存式 RPC 数据平面

每个 RDMA Session 在本地分配并注册一块连续 Memory Region,双方交换 remote_addrrkey 和布局信息后,通过固定偏移访问对端逻辑区域。跨主机描述符仅使用定长字段、区域编号和偏移量,不传递裸指针。

数据平面包括:

  • Request Ring:发起端提交请求描述符;
  • Response Ring:执行端返回响应描述符;
  • Data Pool:承载小对象、请求负载、内联结果和槽位局部数据;
  • Object Pool:承载 LAZY 路径的大对象结果;
  • Control Page:发布队列占用、对象池使用率、错误计数、延迟 EWMA 和生命周期统计。

2. 负载—状态双感知的多路径选择

运行时集中通过 rdmem_select_path() 选择路径。决策不仅考虑请求和响应规模,也考虑本地 RDMA 状态与执行端控制页中的资源压力。

路径 适用场景 数据流向
RDMA_WRITE_EAGER 小请求、小响应 Client 写请求;Server 将结果主动写回 Client
RDMA_READ_LAZY 小请求、大响应 Server 将结果放入 Object Pool;Client 按需 RDMA Read 拉取
RDMA_WRITE_BULK 大请求、大 Value、图像分块 Client 先将负载写入 Server Data Pool,再发布请求描述符
TCP_FALLBACK RDMA 不可用、错误过多或远端压力过高 复用相同业务分发逻辑,经 TCP 完成调用

默认规则如下:

  1. 显式指定 --force-path 时,使用指定路径;
  2. RDMA 不可用或错误计数超过阈值时,回退 TCP;
  3. Request Ring 占用率超过 90%,或 Object Pool 使用率超过 85% 时,回退 TCP;
  4. 请求大小不小于 8 KiB 时,选择 BULK;
  5. 预期响应大小不小于 8 KiB 时,选择 LAZY;
  6. 其他情况选择 EAGER。

阈值可通过 --bulk-threshold--large-threshold--error-threshold 调整。

3. 请求与对象的双端生命周期管理

异步请求通过 submit / progress / poll / wait 状态机推进,支持多个 outstanding 请求同时在途。槽位只有在上层消费结果且相关 CQ 完成项全部回收后才会重新置为 FREE,从而避免迟到完成导致的槽位误复用。

LAZY 路径使用固定大小 Slab Object Pool 管理大对象。对象引用包含 object_idoffsetlengthgeneration

  • Server 分配对象并发布 READY;
  • Client 根据对象引用执行 RDMA Read;
  • Client 完成读取后发送 RECLAIM;
  • Server 校验 generation,支持重复回收幂等处理;
  • 未正常回收的对象可由 TTL 扫描释放。

4. Session 级通信资源隔离

执行端监听线程只负责接受连接。每个 Client 连接对应一个独立 Session,并拥有独立的:

  • RDMA CM 事件通道;
  • Protection Domain、Completion Queue 和 Queue Pair;
  • 注册内存与共享内存式布局;
  • Request/Response Ring、Data Pool 和 Object Pool;
  • 请求处理 Worker。

不同 Session 的通信资源和故障清理互不影响;分片 KV 服务作为全局业务状态被多个 Session 和 TCP 回退路径共享。

5. 复杂返回值与业务能力

系统支持:

  • PINGECHO
  • KV_PUTKV_GET
  • MGET 动态数组返回;
  • PROFILE 复合结构体返回;
  • LARGE_GET 大对象拉取;
  • 二进制图像分块上传;
  • 同步调用与异步流水线压测;
  • 本机多进程 POSIX 共享内存接入;
  • RDMA 异常、远端压力和错误阈值注入验证。

动态数组和复合结构体使用自包含 Blob 与相对 offset 编码,避免跨地址空间指针失效。

系统架构

┌──────────────────────────────── 发起节点 Client ────────────────────────────────┐
│                                                                                 │
│  业务进程 ──┐                                                                    │
│             ├─ 统一 RPC API ── 路径选择器 ─┬─ RDMA_WRITE_EAGER ───────────────┐  │
│  本机 SHM ─ Agent                      ├─ RDMA_READ_LAZY  ───────────────┤  │
│                                         ├─ RDMA_WRITE_BULK ───────────────┤  │
│                                         └─ TCP_FALLBACK ──────────────────┤  │
│                                                                              │  │
│  本地注册 MR:Request Ring / Response Ring / Data Pool / Control Page       │  │
└──────────────────────────────────────────────────────────────────────────────┘  │
                                                                                   │
                              RDMA / TCP                                            │
                                                                                   │
┌──────────────────────────────── 执行节点 Server ────────────────────────────────┐ │
│                                                                                │ │
│  Listener ── Accept ── Session 1 Worker ─┐                                     │ │
│                       Session 2 Worker ─┼─ 统一业务分发 ── 分片 KV 服务         │ │
│                       Session N Worker ─┘                 ├─ 大对象生成          │ │
│                                                         └─ 图像持久化 / YOLO   │ │
│                                                                                │ │
│  每 Session 独立 MR、QP、CQ、PD、Ring、Data Pool、Object Pool、Control Page   │ │
└────────────────────────────────────────────────────────────────────────────────┘ │

注册内存布局

逻辑区域 默认规模 用途
Request Ring 1024 个描述符槽 Client 向 Server 发布请求
Response Ring 1024 个描述符槽 Server 向 Client 发布响应
Data Pool 64 MiB 内联负载、结果、槽位局部缓冲与对象池
Slot-local Region 1024 × 32 KiB 多 outstanding 请求的独立负载区
Object Pool 256 × 64 KiB LAZY 路径的大对象结果
Control Page 4 KiB 区域表、状态与运行时遥测

BULK 路径中的 zbuf-lite 使用 RNIC 原生 multi-SGE 能力,将本地分散的 key/value 等缓冲区通过一次 RDMA Write 写入远端连续区域。该实现借鉴 scatter-gather 思想,但未移植 zBuffer、PhotonLibOS 或 zRPC 源码。

核心机制

请求提交与两阶段发布

请求描述符与负载准备完成后,运行时最后单独写入 state=READY。执行端只有在观察到 READY 后才读取请求体,避免读取半写描述符。响应采用相同的 state-last 发布原则。

异步流水线

公开异步接口包括:

rdmem_rpc_submit(...);
rdmem_rpc_progress(...);
rdmem_rpc_poll(...);
rdmem_rpc_wait(...);

Server 端通过 rdmem_server_poll_batch() 在一轮中处理多个 READY 请求,配合 Client 多 outstanding 提交,重叠请求发布、远端执行、结果获取和资源回收。

控制页与遥测

Server 本地更新控制页,Client 每隔固定调用次数通过 RDMA Read 刷新快照。主要遥测包括:

  • Request Ring 占用率;
  • Object Pool 使用率;
  • RDMA/TCP 可用状态;
  • 完成、失败、回退和错误计数;
  • 各路径延迟 EWMA;
  • 对象分配、回收、超时回收和陈旧引用计数;
  • BULK multi-SGE 请求数量与字节量。

统一业务分发

RDMA 与 TCP 路径复用 rdmem_service_dispatch(),因此链路切换不会改变上层操作码、KV 状态或返回值格式。

项目结构

.
├── RDMemRPC/                         # 核心源码目录
│   ├── Makefile
│   ├── include/                      # 公共头文件、协议与布局定义
│   ├── src/                          # RDMA、RPC、路径、对象池、KV、SHM 等实现
│   ├── examples/
│   │   ├── rdmemrpc_server.c         # 执行端程序
│   │   └── rdmemrpc_client.c         # 发起端及测试客户端
│   ├── scripts/
│   │   ├── collect_env.sh            # 环境信息采集
│   │   ├── run_basic_tests.sh        # 基础功能验证
│   │   ├── run_benchmarks.sh         # 路径与异步性能测试
│   │   ├── run_business_scenarios.sh # 七类业务场景组合测试
│   │   ├── run_eager_get_regression.sh
│   │   ├── parse_business_report.py
│   │   ├── yolo_infer.py
│   │   └── yolo_viewer.py
│   ├── docs/quickstart.md
│   ├── photos/                       # 演示输入图片
│   ├── ultralytics-main/             # 本地 YOLO 代码目录
│   └── yolo26n.pt                    # 演示模型
├── RDMemRPC系统队-技术文档.pdf
├── RDMemRPC系统队-技术文档.docx
├── RDMemRPC系统队-演示PPT.pptx
├── RDMemRPC系统队-演示视频.mp4
└── README.md

主要模块对应关系:

模块 关键文件
连接建立、Session 与 RDMA 资源 src/rdmemrpc_conn.c
单边读写与 CQ 完成处理 src/rdmemrpc_rdma_ops.c
Request/Response Ring src/rdmemrpc_ring.c
RPC 同步/异步调用链 src/rdmemrpc_rpc.c
多路径选择与控制页 src/rdmemrpc_path.csrc/rdmemrpc_control.c
Object Pool 生命周期 src/rdmemrpc_objpool.c
BULK multi-SGE 聚合 src/rdmemrpc_zbuf.c
复杂返回值编码 src/rdmemrpc_types.c
分片 KV 服务 src/rdmemrpc_kv.c
TCP 回退 src/rdmemrpc_tcp.c
本机多进程共享内存前端 src/rdmemrpc_shm.c
图像分块上传与持久化 src/rdmemrpc_blob.c

环境要求

硬件

  • 两台可互通的 Linux 主机;
  • 支持 RDMA/RoCE 的网卡;
  • 项目实测设备为 Mellanox ConnectX-5;
  • Client 和 Server 必须使用 RDMA 网口地址建立连接。

软件

  • openEuler 22.03 LTS-SP3,或其他提供 rdma-core 的 Linux 发行版;
  • GCC、GNU Make;
  • libibverbslibrdmacm 及其开发头文件;
  • POSIX Threads 与 POSIX Shared Memory;
  • Python 3(测试脚本与可选视觉演示使用)。

openEuler / openKylin / CentOS 风格系统:

sudo dnf install -y \
  gcc make \
  rdma-core rdma-core-devel \
  libibverbs-devel librdmacm-devel

Ubuntu 风格系统:

sudo apt update
sudo apt install -y \
  gcc make \
  rdma-core ibverbs-providers \
  libibverbs-dev librdmacm-dev

检查 RDMA 环境:

ls /dev/infiniband
ibv_devinfo
rdma link
ibdev2netdev
ip -br addr

ibv_devinfo 中应能看到设备和活动端口。若系统只有 RDMA 运行库而没有 -dev-devel 包,编译时会缺少 rdma/rdma_cma.hinfiniband/verbs.h

编译与运行

1. 获取代码

git clone https://gitlink.org.cn/HWjxnIWecg/jykjhlzxdgxnrxt.git
cd jykjhlzxdgxnrxt/RDMemRPC

2. 编译

make -j

生成:

rdmemrpc_server
rdmemrpc_client

清理构建产物:

make clean

3. 启动执行端

以下示例假设 Server 的 RDMA 网口地址为 192.168.100.2

./rdmemrpc_server \
  -b 192.168.100.2 \
  -p 7471 \
  --image-dir received_images

默认行为:

  • RDMA 端口为 7471
  • TCP 回退端口为 7472,即 RDMA 端口加 1;
  • 每个 Client 建立独立 Session 和 Worker;
  • 每轮最多批量处理 16 个 READY 请求;
  • Server 断开一个 Client 后仍继续接受新连接。

常用 Server 参数:

--verbose              输出逐请求调试信息
--no-tcp               禁用 TCP fallback 监听线程
--batch-budget <n>     单轮最多处理的 READY 请求数
--image-dir <dir>      图像持久化目录
--yolo-enable          图像提交完成后执行 YOLO

正式性能测试时不建议启用 --verbose,以免日志输出影响尾延迟。

4. 发起基础调用

SERVER_IP=192.168.100.2
PORT=7471

./rdmemrpc_client -s "$SERVER_IP" -p "$PORT" --ping
./rdmemrpc_client -s "$SERVER_IP" -p "$PORT" --echo hello
./rdmemrpc_client -s "$SERVER_IP" -p "$PORT" --put k1 v1
./rdmemrpc_client -s "$SERVER_IP" -p "$PORT" --get k1
./rdmemrpc_client -s "$SERVER_IP" -p "$PORT" --mget user:1001,user:1002,hello
./rdmemrpc_client -s "$SERVER_IP" -p "$PORT" --profile 1001
./rdmemrpc_client -s "$SERVER_IP" -p "$PORT" --large-get big:64k

-b-s 必须使用 RDMA 网口 IP,而不是管理网口 IP。使用错误网口通常会导致 address resolve failedroute resolve failed

功能使用

自动与手动路径选择

默认使用 AUTO 模式:

./rdmemrpc_client -s "$SERVER_IP" -p "$PORT" --get user:1001 --verbose
./rdmemrpc_client -s "$SERVER_IP" -p "$PORT" --large-get big:64k --verbose
./rdmemrpc_client -s "$SERVER_IP" -p "$PORT" --bigput bigkey 16384 --verbose

测试时可强制指定路径:

./rdmemrpc_client -s "$SERVER_IP" -p "$PORT" --get user:1001 --force-path rdma-write
./rdmemrpc_client -s "$SERVER_IP" -p "$PORT" --large-get big:64k --force-path rdma-read
./rdmemrpc_client -s "$SERVER_IP" -p "$PORT" --put kbulk value --force-path bulk
./rdmemrpc_client -s "$SERVER_IP" -p "$PORT" --get user:1001 --force-path tcp

--force-path 仅用于功能验证和对照测试。正常运行应使用 AUTO 模式。

BIGPUT 说明

--bigput <key> <bytes> 用于验证大请求传输与 BULK 选路。当前 KV 服务的单条 Value 存储上限为 4096 字节,因此超过该上限的 BIGPUT 在存储侧会被截断;该命令的主要目的不是保存任意长度对象,而是验证大请求路径。需要完整传输大二进制对象时,应使用 --image-put 或 LAZY 大对象接口。

异步流水线

./rdmemrpc_client -s "$SERVER_IP" -p "$PORT" \
  --async-bench 10000 \
  --bench-op ping \
  --async-window 32

支持的 --bench-op

ping | get | put | large-get | bigput

输出包括平均延迟、P50、P99、QPS、失败数、路径分布、迟到响应数和异步超时数。

运行时状态与故障回退

# 查看本端遥测和 Server 控制页快照
./rdmemrpc_client -s "$SERVER_IP" -p "$PORT" --stats

# 模拟 RDMA 不可用
./rdmemrpc_client -s "$SERVER_IP" -p "$PORT" \
  --get user:1001 --simulate-rdma-down --verbose

# 注入一次运行时 RDMA 操作失败,AUTO 模式重试 TCP
./rdmemrpc_client -s "$SERVER_IP" -p "$PORT" \
  --get user:1001 --simulate-rdma-op-fail 1 --verbose

# 模拟远端资源压力
./rdmemrpc_client -s "$SERVER_IP" -p "$PORT" \
  --simulate-server-pressure ring
./rdmemrpc_client -s "$SERVER_IP" -p "$PORT" \
  --simulate-server-pressure objpool

# 模拟 RDMA 错误数超过阈值
./rdmemrpc_client -s "$SERVER_IP" -p "$PORT" \
  --simulate-rdma-errors 16

对象生命周期验证

./rdmemrpc_client -s "$SERVER_IP" -p "$PORT" --lifecycle 8
./rdmemrpc_client -s "$SERVER_IP" -p "$PORT" --lifecycle-stale
./rdmemrpc_client -s "$SERVER_IP" -p "$PORT" --lifecycle-repeat-reclaim
./rdmemrpc_client -s "$SERVER_IP" -p "$PORT" --lifecycle-timeout

本机多进程共享内存前端

该功能用于同一 Client 主机上的多个本地业务进程。多个进程通过 POSIX 共享内存 MPSC 环向常驻 Agent 投递请求,Agent 复用一个 RDMemRPC 连接转发到远端 Server。

它不改变跨主机数据通路,也不是多主机共享内存集群。当前 MVP 支持:

PING | ECHO | KV_PUT | KV_GET

启动 Agent:

./rdmemrpc_client \
  -s "$SERVER_IP" -p "$PORT" \
  --shm-agent \
  --shm-reset

同机其他进程直接提交:

./rdmemrpc_client --shm-ping
./rdmemrpc_client --shm-echo hello
./rdmemrpc_client --shm-put user:1 Alice
./rdmemrpc_client --shm-get user:1

本地 SHM Client 不需要 -s-p;只有 Agent 需要连接远端 Server。

边缘视觉协同演示

系统支持二进制图像分块上传。默认分块大小和上限均为 24 KiB。每个分块携带上传编号、总长度、当前偏移、分块长度和 INIT/COMMIT 标志。

执行端流程:

  1. 按顺序校验并接收分块;
  2. 写入临时文件;
  3. 使用 64 位 FNV-1a 滚动哈希进行两端内容一致性检查;
  4. 收齐全部数据后原子重命名为最终文件;
  5. 可选执行 YOLO 推理并生成 JSON 与标注图像。

图像上传

./rdmemrpc_client \
  -s "$SERVER_IP" -p "$PORT" \
  --image-put edge:image photos/1.jpg

指定分块大小:

./rdmemrpc_client \
  -s "$SERVER_IP" -p "$PORT" \
  --image-put edge:image photos/1.jpg \
  --image-chunk-size 24576

启用 YOLO

Server 端:

./rdmemrpc_server \
  -b 192.168.100.2 \
  -p 7471 \
  --image-dir received_images \
  --yolo-enable \
  --yolo-repo ultralytics-main \
  --yolo-model yolo26n.pt \
  --yolo-device cpu

可选启动结果查看器:

python3 scripts/yolo_viewer.py \
  --root . \
  --results-dir received_images/yolo_results \
  --port 8080

YOLO 演示需要 Python 环境能够加载项目内的 Ultralytics 代码及其依赖。核心 RPC 功能不依赖 YOLO。

测试与性能评估

环境信息采集

./scripts/collect_env.sh

输出保存在 logs/env_<host>_<timestamp>.log

基础功能验证

Server 启动后,在 Client 执行:

./scripts/run_basic_tests.sh 192.168.100.2 7471

脚本覆盖基础 RPC、KV、复杂返回值、四条路径、自动选路、图像分块、对象生命周期、异步流水线和故障回退。

性能测试

./scripts/run_benchmarks.sh 192.168.100.2 7471 10000

结果保存在 logs/bench_<timestamp>.log,主要指标包括:

  • 平均延迟;
  • P50 与 P99 延迟;
  • QPS;
  • 失败数;
  • 路径选择计数;
  • RDMA 错误与 TCP 回退计数。

业务场景组合测试

./scripts/run_business_scenarios.sh 192.168.100.2 7471 1000
python3 scripts/parse_business_report.py

七类场景包括:

  1. YCSB-style 热点 KV Cache;
  2. User Profile 复合结构体读取;
  3. CDN 大对象拉取与生命周期管理;
  4. 边缘图像分块迁移;
  5. TCP 回退承载完整 RPC;
  6. 运行时故障与资源压力恢复;
  7. 多 outstanding 异步流水线。

EAGER GET 回归测试

./scripts/run_eager_get_regression.sh 192.168.100.2 7471

该脚本对多个请求规模强制运行 EAGER GET,并要求全部输出 failed=0

文档记录的性能结果

技术文档中的测试平台为两台 openEuler 22.03 LTS-SP3 主机,通过 25 Gbps RoCE v2 直连,网卡为 Mellanox ConnectX-5。以下结果仅对应文档所述硬件、软件和负载配置:

负载 gRPC 平均延迟 RDMemRPC AUTO 平均延迟 gRPC QPS RDMemRPC AUTO QPS
GET 108.36 μs 13.48 μs 9,223.48 73,960
LARGE_GET 269.30 μs 88.73 μs 3,712.48 11,266
BIGPUT 151.85 μs 58.41 μs 6,583.59 17,109

在该测试配置下,AUTO 模式的 GET、LARGE_GET 和 BIGPUT 吞吐分别约为 gRPC 基线的 8.0 倍、3.0 倍和 2.6 倍。不同硬件、编译参数、CPU 绑定方式、日志级别和网络拓扑会影响最终结果,复现实验时应保持双方测试条件一致。

技术文档同时记录:基础功能测试 26 项全部通过,7 类业务场景共 45 项组合检查全部通过。

常见问题

现象 排查方法
/dev/infiniband 不存在 检查 RDMA 硬件与内核模块,尝试加载 mlx5_ibrdma_cmrdma_ucm
ibv_devinfo 看不到设备 检查驱动、固件、PCIe 设备和端口状态
编译缺少 rdma/rdma_cma.h 安装 librdmacm-devlibrdmacm-devel
编译缺少 infiniband/verbs.h 安装 libibverbs-devlibibverbs-devel
address resolve failed 检查目标地址是否属于可达的 RDMA 网段
route resolve failed 确认 -s 使用 RDMA 网口 IP,而非管理网口 IP
region exchange timeout 检查双方是否完成连接、QP 和 Region 元数据交换
RDMA completion timeout 检查 rkey、remote address、MR 权限和链路状态
RPC response timeout 检查 Server Worker 是否运行、Request Ring 是否被处理
completion status error 查看 ibv_wc_status_str,重点检查越界地址、权限和 QP 状态
TCP fallback 无法连接 检查 Server 是否启用 TCP,且 RDMA_PORT + 1 端口未被占用
YOLO 运行失败 检查 Python、模型路径、Ultralytics 依赖和图像输出目录权限

更完整的依赖安装说明见 RDMemRPC/docs/quickstart.md

项目材料与团队信息

项目团队:

  • 学校:西安电子科技大学
  • 队伍:RDMemRPC 系统队
  • 成员:夏宇恒、林正煌、郑明哲
  • 指导教师:万波

RDMemRPC 通过 RDMA 注册内存构建共享内存式数据平面,以统一 API 协调多路径传输、复杂对象表达、资源生命周期、Session 隔离和并发请求推进,为跨主机低延迟 RPC 及边缘数据协同提供可运行的系统原型。

关于
84.9 MB
邀请码
    Gitlink(确实开源)
  • 加入我们
  • 官网邮箱:gitlink@ccf.org.cn
  • QQ群
  • QQ群
  • 公众号
  • 公众号

版权所有:中国计算机学会技术支持:开源发展技术委员会
京ICP备13000930号-9 京公网安备 11010802047560号