☰
RDMA技术调研:从协议选型到verbs编程的落地指南
2026/10/5 2:39:12 网站建设 项目流程

简介:这是一份面向网络与系统方向工程师、高性能计算及数据中心从业者的RDMA技术调研文档,系统梳理了远程直接内存访问的原理、协议与编程方法,适合希望入门或夯实RDMA基础的读者。资源包内含1个PDF文件,整体约1.01MB,篇幅紧凑便于通读。文档从DMA与RDMA的基本概念切入,对比传统网络协议栈的转发过程,重点讲解零拷贝、内核旁路、CPU卸载三大核心优势,并说明低延迟、高带宽、低CPU占用等典型业务场景。随后展开Infiniband、RoCE、iWARP三种协议的特点与差异,介绍WQ、SQ、RQ、CQ、QP等关键术语及SEND/RECV、WRITE/READ、ATOMIC等通信操作,还涉及RC、UC、UD等传输模式与rdma-core用户态库。目前已有528人学习,适合作为RDMA学习路线中的调研与概念梳理材料。

1. 从一次存储集群调优说起:这份 RDMA 技术调研 PDF 到底能解决什么

去年帮一个做分布式存储的团队排查时延抖动,业务侧反馈单节点吞吐卡在 12Gbps 上不去,CPU 的si(软中断)占比却常年 30% 以上。抓了perf top一看,全耗在 TCP 协议栈的报文封装和中断处理上。当时我第一反应就是:这套场景该上 RDMA 了。但团队里没人系统梳理过 RDMA 的协议选型、术语体系和编程接口,翻官方手册又太散。这份《RDMA技术调研.pdf》就是在这种背景下值得先过一遍的材料——它把 RDMA 是什么、三种协议怎么选、WQ/QP/CQ 这套术语怎么串起来、rdma-core 两个库各管什么,用一份文档的篇幅讲清楚了。它适合两类人:一是准备在存储、HPC、金融行情这类低延迟场景落地 RDMA 的工程师,二是被 verbs 编程里一堆缩写绕晕、需要先建立全局认知的开发者。它不是代码大全,但能帮你把「为什么用、用哪种、怎么起步」这条线先立住。

2. RDMA 三大核心优势拆解:零拷贝、内核旁路、CPU 卸载到底省在哪

2.1 传统协议栈的转发路径与瓶颈定位

要理解 RDMA 省了什么,得先看清传统网络一次收发的完整路径。以 TCP 为例,发送端应用调用send()后,数据从用户空间缓冲区拷贝到内核 socket 缓冲区,这是第一次拷贝;协议栈加上 TCP/IP 头,交给网卡驱动,驱动再通过 DMA 把数据搬到网卡内部存储,这是第二次拷贝。接收端反过来:网卡 DMA 到内核缓冲区,协议栈解析、校验、剥离头部,再拷贝到用户空间,又是一轮。整个过程 CPU 要处理中断、走协议栈、做上下文切换。

这套路径在万兆以下还能扛,到了 25G、100G 就顶不住了。瓶颈不在带宽本身,而在 CPU 被大量消耗在「搬运和解析」上。我见过一台 32 核机器跑 40G 网卡,光软中断就吃掉 8 个核,业务进程反而抢不到 CPU。RDMA 的思路很直接:既然 CPU 只是搬运工,那就让网卡硬件来干这活,CPU 只负责下命令。

2.2 零拷贝、内核旁路、CPU 卸载的机制与收益

RDMA 的三个核心优势,本质是三个不同层面的优化,别混为一谈。

零拷贝指的是数据不再在用户空间和内核空间之间来回搬。应用程序直接把数据放到注册好的缓冲区,网卡从这块内存 DMA 取走,中间没有协议栈参与的复制动作。注意,零拷贝不等于「一次拷贝都没有」,网卡到物理链路这一段该有的搬运还是有的,省掉的是软件栈里的内存复制。

内核旁路指的是应用从用户态直接操作网卡,不需要陷入内核做系统调用。传统send()每次都要从用户态切到内核态,这个上下文切换在低延迟场景里是实打实的开销。RDMA 的 verbs 接口让应用直接往 QP 里投递工作请求,绕开了内核。

CPU 卸载则是对远端而言的。RDMA 的 READ/WRITE 操作,远端 CPU 完全不知情——网卡收到请求,直接 DMA 读写指定内存,不产生中断、不惊动任何进程。这一点在内存数据库、分布式缓存场景里价值极大,远端机器的 CPU 可以专心跑业务。

提示:这三个优势不是所有 RDMA 操作都同时具备。SEND/RECV 需要远端提前 post 接收缓冲区,远端 CPU 仍要参与控制面;只有 READ/WRITE 这类单边操作才真正做到了远端 CPU 零参与。

2.3 什么业务该上 RDMA:从延迟、带宽、CPU 三个维度判断

文档里列了低延迟、高带宽、CPU 占用小三类场景,但实际选型时得量化。我的经验是看三个指标:一是 P99 延迟是否要求低于 10 微秒,TCP 协议栈本身就有几十微秒的抖动,这种场景 RDMA 几乎是唯一解;二是单机网络吞吐是否已经逼近网卡线速而 CPU 先到瓶颈,如果si占比超过 20% 且吞吐上不去,就该考虑;三是远端 CPU 是否被网络处理严重挤占,比如存储节点既要处理 IO 又要跑业务逻辑。

HPC 的 MPI 通信、金融行情分发、分布式存储的副本同步、云上虚拟化热迁移,这几类是 RDMA 的经典落地场景。反过来,如果业务本身是短连接、小包、请求模式不固定,RDMA 的连接管理开销反而可能得不偿失,这种时候老老实实用 TCP 更稳。

3. IB、RoCE、iWARP 三种协议怎么选:一张表看清组网成本与兼容性

3.1 三种协议的层次差异与硬件依赖

RDMA 是技术标准,落到协议层有三种实现,差别主要在「RDMA 报文跑在什么网络之上」。

Infiniband(IB)是从底层就为 RDMA 设计的独立网络,从网卡到交换机全套专用硬件。它的链路层、网络层、传输层都是自己的规范,性能最好、延迟最低,但组网成本高,交换机和网卡都得用 IB 专用设备,和现有以太网完全不兼容。

RoCE 是把 IB 的传输层报文封装进以太网帧里跑。它保留了 IB 的上层语义,底层换成以太网,所以能复用现有以太网交换机,只需要网卡支持 RoCE。RoCE 有两个版本:v1 基于以太网二层,不能跨三层路由;v2 封装在 UDP 里,可以跨三层,是现在的主流。

iWARP 则是把 RDMA 语义跑在 TCP 之上。它最大的好处是能复用现有 TCP/IP 基础设施,甚至部分场景可以纯软件实现。但代价是 TCP 协议栈本身的开销还在,性能优势被削弱,而且 iWARP 不支持 RDMA READ 之外的一些 IB/RoCE 特性。

3.2 组网成本、生态与选型决策表

维度InfinibandRoCE v2iWARP
底层网络IB 专用以太网 + UDPTCP/IP
交换机要求IB 专用交换机支持 PFC/ECN 的以太网交换机普通以太网交换机
网卡要求IB 网卡RoCE 网卡iWARP 网卡
跨三层路由支持支持支持
性能最优接近 IB相对较弱
运维复杂度高(专用网络)中(需调无损网络)低
典型场景HPC、超算数据中心、存储兼容性优先场景

选型上我的建议很直接:新建 HPC 集群、预算充足、追求极致延迟,上 IB;已有以太网基础设施、想平滑升级,选 RoCE v2,但要接受无损网络的调优成本;如果只是想在现有 TCP 环境里试水 RDMA,或者对性能要求没那么苛刻,iWARP 门槛最低。

3.3 RoCE v2 无损网络配置的关键参数

RoCE v2 最大的坑在「无损网络」。RDMA 假设网络不丢包,一旦丢包,重传机制和 TCP 完全不同,性能会断崖式下跌。所以 RoCE v2 组网必须配 PFC(优先级流控)和 ECN(显式拥塞通知)。

交换机侧要开启 PFC,给 RDMA 流量分配独立优先级,配置类似:

# 交换机侧示意:为优先级 3 开启 PFC,并配置 ECN priority-flow-control enable priority-flow-control priority 3 # ECN 阈值配置,超过阈值打标而非直接丢弃 ecn threshold 500000

网卡侧要设置对应的 DSCP 值和 PFC 优先级,以 Mellanox 网卡为例:

# 设置 RoCE 流量的 DSCP 为 26,映射到优先级 3 cma_roce_tos -d mlx5_0 -t 106 # 查看当前 PFC 配置 mlnx_qos -i eth2

参数说明:cma_roce_tos里的-t 106是 ToS 值,106 对应 DSCP 26,需要和交换机侧的优先级映射一致;mlnx_qos用来核对网卡是否真的把 PFC 开在了对应优先级上。这两边对不上,PFC 就是摆设,丢包照样发生。

注意:PFC 配置错误是 RoCE 性能翻车的头号原因。我见过交换机开了 PFC 但网卡 DSCP 没设,流量根本没走无损队列,压测时延迟抖动到毫秒级,排查了两天才发现是映射没对齐。

4. 从 WQ 到 CQ:RDMA 通信流程与 verbs 编程起步

4.1 WQ、QP、CQ 三大术语的关系梳理

RDMA 的术语体系是入门第一道坎,但理清了其实很顺。核心就三个东西:WQ、QP、CQ。

WQ(Work Queue)是工作队列,存放工作请求(WR)。应用要发数据,就往队列里投递一个 WR。队列分两种:SQ(Send Queue)管发送,RQ(Receive Queue)管接收。

QP(Queue Pair)就是 SQ 和 RQ 的配对。一次通信的两端各有一个 QP,发送端的 SQ 对应接收端的 RQ。QP 是 RDMA 通信的基本单位,连接建立、状态管理都围绕 QP 展开。

CQ(Completion Queue)是完成队列。工作请求处理完了,硬件往 CQ 里放一个完成事件(CQE),应用轮询 CQ 就知道哪个请求完成了、成功还是失败。

这三者的关系可以这样记:应用往 QP 的 WQ 里投 WR,硬件处理完后往 CQ 里放 CQE,应用轮询 CQ 收割结果。整个过程中,应用不碰协议栈,只和这三个队列打交道。

4.2 SEND/RECV 一次完整通信的软硬件交互

以最基础的 SEND/RECV 为例,走一遍完整流程。

接收端先准备:应用在 RQ 里 post 一个接收 WR,告诉硬件「我有一块缓冲区,等着收数据」。这个动作必须提前做,否则发送端发过来的数据没地方放,会触发 RNR(Receiver Not Ready)错误。

发送端发起:应用在 SQ 里 post 一个发送 WR,指定要发的数据地址和长度。硬件从内存 DMA 取数据,组装成 RDMA 报文,通过物理链路发出去。

接收端硬件收到报文,剥离头部和校验,DMA 把数据写进之前 post 的接收缓冲区,然后往 CQ 里放一个 CQE,通知应用「收到了」。同时硬件自动回一个 ACK 给发送端。

发送端收到 ACK,往自己的 CQ 里放 CQE,通知应用「发送完成」。

整个流程里,两端的 CPU 只在 post WR 和 poll CQ 时参与,中间的数据搬运和报文处理全是网卡硬件干的。这就是 RDMA 的威力所在。

4.3 用 rdma-core 写第一个 verbs 程序:环境准备与关键调用

rdma-core 是用户态 RDMA 编程的基础库,里面两个核心库:libibverbs 提供 verbs 接口,直接操作 QP、CQ、MR;librdmacm 在 verbs 之上封装了连接管理(CM),简化建连过程。

环境准备先确认网卡和驱动:

# 查看 RDMA 设备列表 ibv_devices # 查看设备详细信息,确认端口状态和链路速率 ibv_devinfo -d mlx5_0 # 确认 rdma-core 相关库已安装 ldconfig -p | grep ibverbs

如果ibv_devices能列出设备且ibv_devinfo里state是PORT_ACTIVE,说明环境就绪。

下面是一个最小的 verbs 程序骨架,展示资源创建的关键调用:

#include <infiniband/verbs.h> // 1. 获取设备列表,打开第一个设备 struct ibv_device **dev_list = ibv_get_device_list(NULL); struct ibv_context *ctx = ibv_open_device(dev_list[0]); // 2. 查询端口属性,拿到 LID、GID 等信息用于建连 struct ibv_port_attr port_attr; ibv_query_port(ctx, 1, &port_attr); // 3. 创建 PD(保护域),用于关联 QP 和 MR struct ibv_pd *pd = ibv_alloc_pd(ctx); // 4. 创建 CQ,参数 16 表示 CQ 深度 struct ibv_cq *cq = ibv_create_cq(ctx, 16, NULL, NULL, 0); // 5. 创建 QP,指定发送和接收 CQ struct ibv_qp_init_attr qp_attr = { .send_cq = cq, .recv_cq = cq, .qp_type = IBV_QPT_RC, // 可靠连接 .cap = { .max_send_wr = 16, .max_recv_wr = 16 } }; struct ibv_qp *qp = ibv_create_qp(pd, &qp_attr); // 6. 注册内存区域(MR),拿到 lkey/rkey char *buf = malloc(4096); struct ibv_mr *mr = ibv_reg_mr(pd, buf, 4096, IBV_ACCESS_LOCAL_WRITE | IBV_ACCESS_REMOTE_WRITE | IBV_ACCESS_REMOTE_READ);

逻辑说明:这段代码走的是「设备 → PD → CQ → QP → MR」的标准资源创建顺序。PD 是保护域,QP 和 MR 都必须挂在同一个 PD 下才能互相访问,这是权限隔离机制。IBV_QPT_RC指定可靠连接传输模式,类似 TCP。MR 注册时给的 access flag 决定了远端能对这个区域做什么操作,REMOTE_WRITE和REMOTE_READ是单边操作必需的。

参数说明:ibv_create_cq的第三个参数是 CQ 深度,太小会导致 CQE 溢出,一般按并发 WR 数量的 1.5 到 2 倍设置。max_send_wr和max_recv_wr是 QP 能容纳的未完成 WR 上限,压测高并发时要调大。MR 注册是有开销的,频繁注册注销会拖慢性能,常见做法是启动时一次性注册大块内存池。

提示:verbs 编程里资源创建顺序不能乱,销毁顺序则相反。QP 必须先于 CQ 销毁,MR 必须先于 PD 注销,否则会报错或资源泄漏。这个顺序我踩过坑,程序跑久了句柄耗尽,查了半天才发现是销毁顺序反了。

5. 避坑与排查:RDMA 落地最常见的五类问题

5.1 现象:ibv_devinfo 显示端口 DOWN,程序建连失败

原因:物理链路没通,或者网卡驱动没正确加载。IB 网络还要检查子网管理器(SM)是否运行,没有 SM 的 IB 网络端口起不来。

解决:先ibstat看物理层状态,确认线缆和光模块正常;IB 场景用sminfo确认 SM 在跑;RoCE 场景检查交换机端口是否 up、VLAN 配置是否正确。端口状态必须是PORT_ACTIVE才能建连。

5.2 现象:SEND 操作报 RNR 错误,接收端收不到数据

原因:接收端没有提前在 RQ 里 post 接收缓冲区,或者 post 的数量不够,发送端发太快把接收队列打空了。

解决:接收端要保证 RQ 里始终有足够的接收 WR。常见做法是收到一个 CQE 就立刻补 post 一个,形成循环。如果业务是突发流量,RQ 深度要按峰值并发设置,别按平均值算。

5.3 现象:RoCE 压测时延迟抖动大,吞吐上不去

原因:无损网络没配好,PFC 和 ECN 没生效,或者 DSCP 优先级映射不一致,RDMA 流量走了普通队列,丢包触发重传。

解决:按第 3 章的配置核对交换机 PFC 和网卡 DSCP 是否对齐;用mlnx_qos -i <dev>确认 PFC 优先级;压测时用ethtool -S看是否有 pause 帧和丢包计数。ECN 阈值设太低会频繁打标,设太高起不到流控作用,一般从链路带宽的 30% 到 50% 起调。

5.4 现象:程序运行一段时间后内存暴涨或句柄耗尽

原因:MR 注册后没注销,QP、CQ 创建后没销毁,资源泄漏。verbs 的资源不会自动回收,必须显式释放。

解决:严格按「QP → CQ → MR → PD → context」的顺序销毁,每个ibv_create_*都要有对应的ibv_destroy_*。建议把资源管理封装成 RAII 风格的函数,避免遗漏。MR 尽量复用,不要每次传输都注册新区域。

5.5 现象:RDMA WRITE 成功但远端读到的数据不对

原因:远端注册 MR 时给的 rkey 和实际使用的不一致,或者访问权限没开REMOTE_WRITE,或者地址偏移算错。

解决:核对建连时交换的 rkey 和远端地址是否和注册时一致;确认 MR 的 access flag 包含所需操作;WRITE 的远端地址要加上正确的偏移量。这类问题最隐蔽,因为 WRITE 是单边的,远端 CPU 不知情,出错也没有远端日志,只能靠发送端 CQE 的状态码和实际数据比对来定位。

6. 进阶技巧:用 perftest 验证 RDMA 性能与参数调优

环境搭好、程序能跑通之后,下一步是验证性能是否达标。别急着上业务,先用 perftest 工具套件把链路性能摸清楚,这是判断配置对不对、瓶颈在哪的最快手段。

perftest 里最常用的是ib_send_bw(带宽测试)和ib_send_lat(延迟测试),还有ib_write_bw、ib_read_lat等对应不同操作的版本。服务端先起:

# 服务端:监听,使用 mlx5_0 设备,RC 连接 ib_send_bw -d mlx5_0 -i 1 -F --report_gbits

客户端连接:

# 客户端:连接服务端 IP,跑 10 秒,输出带宽 ib_send_bw -d mlx5_0 -i 1 -F --report_gbits 192.168.1.100

参数说明:-d指定 RDMA 设备,多网卡机器必须明确指定;-i是端口号,一般 IB 是 1;-F表示不检查 CPU 频率,避免因降频报错中断测试;--report_gbits让结果以 Gbps 显示,比默认的 MB/s 直观。测延迟用ib_send_lat,它会跑多次取平均值和最大值,重点看 max 值,抖动大说明网络或配置有问题。

调优时几个关键参数值得反复试。一是 QP 数量和队列深度,-q指定 QP 数,-l指定消息大小,多 QP 并发能压出更高带宽,但队列太深会增加延迟。二是消息大小,小包看延迟、大包看带宽,分别测 2 字节和 1MB 两档,能看出链路在不同负载下的表现。三是 MTU,IB 网络设成 4096 能减少报文数量,RoCE 受以太网 MTU 限制一般 1500 或 9000,开 jumbo frame 对带宽提升明显。

我一般会跑一组对照:先测默认配置,再逐项调 MTU、队列深度、QP 数,每次只改一个变量,记录带宽和延迟变化。这样能快速定位哪个参数是当前瓶颈。有一次压测带宽始终卡在 80Gbps 上不去,最后发现是 MTU 没开 jumbo frame,改完直接跑到 95Gbps。

从那以后我每次新环境上线前,都强制先用 perftest 跑一遍基线,把带宽、延迟、抖动三个数记下来存档,后面业务出问题时有对照,能快速判断是网络退化还是业务自身问题。希望这份梳理能帮到你,少走点我当年踩过的弯路。

本文还有配套的精品资源,点击获取

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询