rdma_bench框架解析:RDMA基准测试与性能调优实践
2026/9/7 9:59:09 网站建设 项目流程

简介:一套来自USENIX ATC论文的rdma_bench开源框架,定位于帮助RDMA与InfiniBand网络性能研究人员、内核驱动开发者快速搭建依赖InfiniBand HCA硬件的基准测试工作台,评估不同硬件、驱动(如Mellanox OFED或上游驱动)及消息大小下的性能表现,解决RDMA调优缺少统一验证工具的问题。资源共226个文件,压缩包仅325KB,其中以C和C++源码实现RDMA核心逻辑,.sh脚本承担环境准备与批量实验,Makefile及autotools配置(configure.ac、Makefile.am)负责构建,Markdown文档辅助说明,整体结构紧凑清晰,便于阅读和二次开发。代码覆盖QP、verbs、CQ等verbs层关键模块,并提供多种典型测试场景,包括32字节/384字节消息量、多机/多虚拟机并发读写等配置,能够直接复现ATC论文中的性能实验,也可作为深入理解RDMA编程模型、消息队列与内存注册机制的实战素材。目前已有373人学习该资源,对具备网络编程基础、希望系统研究RDMA性能与调优策略的中高级开发者尤为合适。

1. 项目整体设计思路与定位解析

1.1 rdma_bench到底解决了什么问题

做RDMA相关开发的人,尤其是刚入门或者从传统TCP网络切换过来的,一定会经历一段非常痛苦的时期。明明硬件手册看了、API文档背了、示例代码跑了,但真正到自己写应用,或者调试性能瓶颈的时候,总感觉隔着什么东西。这里的核心问题在于:RDMA不是简单的“换一种API调用”,而是一套完全不同于传统内核网络栈的交互模型。很多性能问题不是靠猜就能定位的,必须得动手去测量。

rdma_bench这个项目的价值就在于:它把RDMA开发中最常见、最核心的几种操作模式,做成了一个一个的基准测试工具集。你可以直接运行它,观察不同模式下带宽、时延、CPU占用率的关键指标,在真实的硬件上把RDMA的“性子”摸清楚。

我自己第一次大规模使用RDMA是在一个分布式存储的项目里,机器间的网络从万兆TCP升级到RoCEv2,刚开始以为就是换模块而已。结果性能不仅没上去,还有反常态的抖动。后来就是把RDMA相关的基准工具一个个跑下来,才定位到是注册内存、连接方式以及消息大小这几处选择有严重问题。

这个项目为什么叫“框架”而不是“工具包”?因为它不单单给你几个命令去测数据,它给出了一套可以扩展、可以改动、可以二次开发的骨架代码。你在上面不只是跑结果,而是可以修改参数、增加类型、记录自定义日志,把基准测试变成你理解RDMA行为和做性能调优的入口。

1.2 框架的核心技术栈与选型考量

rdma_bench最常见的实现语言是C和C++,这是有原因的。RDMA本身是一个对性能和底层控制要求极其苛刻的技术,虽然有一些高级语言绑定(比如Python通过Pyverbs),但真正想要精确控制WQE(工作队列元素)、CQ(完成队列)、注册内存这些细节,C/C++仍然是绝对主力。

在框架的架构上,它不是一个复杂的分布式系统,也不涉及集群调度。它本质上是一组围绕libibverbs实现的benchmark集合,通过合理的代码组织,把不同的测试行为隔离成独立模块,同时共享一套连接管理、参数解析和时间统计的底层逻辑。

如果非要和其他RDMA相关开源项目做一个类比,可以这样看:有些项目侧重于提供高性能通信库(比如开源的rdma-core),有些项目侧重于上层应用接口(比如Horovod的RDMA支持),而rdma_bench的任务非常纯粹,它就是一块“试金石”,让你在部署RDMA网络之后,能够快速回答三个问题:

  1. 当前环境下不同连接方式(RC、UC、UD)能跑到什么水平?
  2. 在什么消息大小区间内,带宽可以打满?在什么区间内,时延是最低的?
  3. 如果应用遇到性能瓶颈,是出在网络硬件、驱动设置,还是应用代码结构上?

这就决定了框架的设计必须遵循几个原则:模块解耦、参数可配、结果可重复。任何一次基准测试如果无法复现,那它的参考价值就大打折扣了。

1.3 框架对初学者和资深工程师的不同价值

对于初学者来说,rdma_bench像是一本可运行的入门教材,很多让人摸不着头脑的概念,比如什么是ibv_post_send、什么是sge(散播-聚集列表)、什么是完成事件,在这些代码里会具象化。你不是在背定义,而是看着代码和实际运行结果去理解它。

对于资深工程师来说,它的价值更偏向于调优参考和回归测试工具。比如我需要验证代码在做某种改动后性能没有掉,或者同一套代码在不同固件版本下表现是否有差异,直接跑一遍基准就够了。而且在网络上没有统一流控方案时,通过多次基准可以暴露很多隐藏的拓扑和配置问题。

我个人觉得,凡是做RDMA应用、RDMA网络运维、高性能计算以及分布式存储相关的人,都应该在自己的工具箱里保留这样一套框架。它的学习曲线远比想象中平缓,因为它把复杂的东西浓缩成了几个清晰的命令,上手速度非常快。

2. 核心细节解析与实操要点

2.1 环境准备与依赖安装

在真正动手运行rdma_bench之前,首先要确认你的环境能够支持RDMA。这里说的支持分三层:硬件层、驱动层、软件层。

硬件层就是网卡,不管是Mellanox(现在叫NVIDIA Networking)、Intel还是其他厂家的卡,必须确认支持RDMA能力。如果用的是RoCE(RDMA over Converged Ethernet),还需要交换机或者网卡的DCQCN/PFC等流控机制配合,否则运行结果会有很多意外的性能毛刺。

驱动层上,常见的是MLNX_OFED驱动,它把内核模块和用户态库一起打包。安装时要注意版本匹配,不同内核版本对驱动版本有要求。驱动装完以后,用ibstat或者ibv_devinfo命令核实一下端口状态,确认link层是InfiniBand还是Ethernet,MTU是多少,这些都直接影响通信性能。

软件层主要就是libibverbs和librdmacm两个库,后者不是必需,但大多数示例都会用到它来简化连接管理。在Ubuntu/Debian系统上,命令行安装就可以:

sudo apt-get install -y libibverbs-dev librdmacm-dev ibverbs-utils rdma-core

如果你需要自己编译新版rdma-core,源码构建过程中要格外留意内核头文件的版本,这一步容易翻车。如果是CentOS/RHEL系列,则需要通过yum安装类似的包组,并确认内核中有对应模块被加载。

注意:强烈建议在做基准测试之前,先跑一下官方自带的简单示例,比如ib_write_bw或者ibv_rc_pingpong,确认通信本身没有故障。否则后面遇到性能异常,会很难区分是框架问题还是环境问题。

2.2 关键参数解析与实验设计思路

运行rdma_bench绝不是简单地把命令敲下去、等结果打印出来就完事了。它的每类测试都设置了大量参数,理解这些参数背后的意义,才能设计出有价值的实验。

连接类型是最关键的参数之一,RC(可靠连接)提供可靠传输和有序交付,适合大多数应用场景;UC(不可靠连接)减少了确认开销,适合可以容忍偶发丢包的应用;UD(不可靠数据报)则更像UDP,不具备连接的概念,支持多对多通信。框架分别提供测试,不是单纯为了炫技,而是让你能对比不同可靠级别带来的性能差异。

消息大小和数据块大小是另一个重点。很多初次接触的人会忽略“带宽随消息大小变化”这一特点。RDMA走的是绕过内核的路径,适合中大消息的高吞吐传输,而小消息的优势在于时延极低,但吞吐并不占优。你需要在一组典型的SGE配置下,扫描多个消息大小,比如从2字节到1MB逐步递增,画出带宽-消息大小曲线,这样应用该用多少字节的批量传输,一下子就有数了。

并发度(queue depth)在高性能场景下几乎是决定性参数。它表示发送端可以同时驻扎在网卡队列里的请求数量。调大queue depth可以让网卡始终有活干,抵消网络往返等待时间的影响,尤其对时延敏感型和带宽饱和型应用差异巨大。但并非越大越好,过大会占用过多内存,而且可能造成完成事件的批量积压,反而提高单请求的平均时延。

另外还有一些实现细节,比如是否使用Fork支持、是否开启自适应路由(adaptive routing)、是否启用统计输出(all_pingpong等),这些都要在做实验规划时一并考虑。一个好的实验设计应该只改变一个变量,固定其余变量,这样每次对比才有说服力。

2.3 代码结构里值得学习的精妙设计

打开rdma_bench这类项目,你会看到清晰的目录划分,每个测试类型都有对应的独立文件。这种划分不只是为了方便阅读,更是为了编译优化时不会被无关代码干扰。

在底层,几乎所有测试都绕不开几件事:创建QP(Queue Pair)、注册MR(Memory Region)、准备缓冲区、发起发送/接收请求、等待完成事件。框架往往把这些操作封装成通用函数,而把不同测试的差异留在上层。

我建议仔细阅读下发送路径的实现,理解sge、num_sge、wr_id这些字段的赋值逻辑。wr_id在完成事件里会被返回,通常我们把请求的上下文指针存进去,这样可以从完成队列事件里干净地反解出用户数据。这种编码技巧在实际业务里特别常见,也很实用。

还有一个值得关注的是“时间测量”的实现方式。高性能环境下,用clock_gettime(CLOCK_MONOTONIC)已经是比较常规的做法,但需要小心是否统计了建立连接等准备阶段的开销。好的benchmark会把握手阶段和正式测量阶段严格分离,确保测量区间干净。

3. 实操过程与核心环节实现

3.1 编译项目和基础烟雾测试

拿到项目源码后的第一件事是查看README和Makefile,确认编译所需的依赖是否齐全,然后用make命令完成构建。构建过程中常遇到的问题包括头文件路径找不到、缺少链接库,这些只要把libibverbs-dev安装正确,基本都能避免。

编译成功后,先在单机环境下做一次基础环回测试。很多人会疑惑RDMA是不是必须要有两台机器,实际上在配备了支持Loopback的RDMA网卡时,本机两个QP之间的通信是可以测试的。这一步的意义在于验证安装正确性和基本代码可用性,不用急着上真实集群。

举例来说,如果编译出了一个叫ib_write_bw的测试程序,先在单机上通过指定同一台机器的IP或者GID方式,启动server和client,跑一个小规模的消息收发。如果这里都能出现异常,那大概率是网卡配置或者驱动有问题,后面的一切都无从谈起。

3.2 双机环境下跑的带宽测试全流程

双机测试是更贴近实际场景的验证方式。假设两台服务器都连接在同一台支持无损以太网的交换机下,且已经配置好IP。

第一步是打开ibv_devinfo,确认两端网卡状态正常,端口state为Active,物理state为LinkUp。第二步是在server端启动测试程序,监听某个端口:

./ib_write_bw -d mlx5_0 -p 43855 --report_gbits

-d参数指定使用哪块网卡设备,由于可能有多个设备,准确指定才不会选错。--report_gbits是让结果以Gb/s为单位输出,这样便于直接和网络标称速率做对比。

第三步是在client端发起测试,指定server的IP地址和端口,同时把消息大小和运行时长等参数带上:

./ib_write_bw -d mlx5_0 -p 43855 192.168.1.10 --size=65536 --duration=30

运行结束后,输出会包括每秒的带宽、平均带宽以及CPU使用情况等信息。如果结果远低于预期,首先检查MTU设置,再看流控是否开启,最后看是否有丢包导致的退避现象。曾经遇到过一种情况,测出来的带宽只有理论值的60%,排查了很久才发现是交换机的PFC配置在特定拥塞场景下起了反作用。

3.3 时延测试的细节门道

时延测试比带宽测试更敏感,也更难测准。时延的高低不仅受网络硬件制约,还受软件路径长度影响。比如进程是否绑定CPU核心、中断是否均衡、页表是否被换出,都会造成微秒级别的波动。

做时延测试时,一个重要技巧是把测试消息大小设得很小,比如2字节或者4字节,目的是测量协议本身的基延迟,而不是传输大块的耗时。另一个技巧是增加迭代次数,让统计样本足够多,否则个别异常值会影响平均结果。

rdma_bench这类工具的时延测试通常会附带“往返时延”的数学摘要,包括平均值、最小最大和百分位数。这里最重要的是理解百分位数的价值:平均值好看并不代表系统稳定,高百分位(如p99)偏大说明存在长尾延迟,这在分布式训练同步、数据库远程读写里是致命的。

我实际测试过多次,在机架内两台机器上,RC模式2字节的往返时延稳定在1.5微秒左右,RDMA write比send/recv模式又低一截。这些数字和网络拓扑、交换芯片都有关系,不同环境下差异可能会非常大,所以不要盲目照搬别人的基准数据。

3.4 结果分析常用方法

拿到原始测试数据之后,很多人的第一反应是看那个average值,然后得出结论。这种做法过于粗糙,因为RDMA高性能链路上,平均值会掩盖大量细节。更推荐的做法是保存每次迭代的原始样本,在代码里或者导出后用Python脚本绘图。

带宽曲线可以用折线图观察“拐点”,这个拐点往往对应网卡从单请求处理转到流水线处理的过渡区间。时延曲线则通常呈现一个“平台+上升段”,平台区间的消息大小才适合低时延小包通信。

多次运行取中位数或者均值,同时记录方差,是去除噪声的标准做法。另外,一定要留意有没有重传计数(可以通过ethtool或者rdma statistic查询),一旦有重传,任何基准结果的真实性都要打上问号。

4. 常见问题与排查技巧实录

4.1 测试结果反复不稳定的排查思路

这是所有RDMA性能测试里最折磨人的问题。同一套命令,第一次跑出95Gbps,第二次只有60Gbps,第三次又变回90Gbps。遇到这种情况,请不要第一个怀疑网卡坏了,而是按照下面的顺序逐层排查。

第一层是CPU频率和调度,RDMA虽然不占用太多CPU,但libibverbs的用户态轮询模式对CPU绑定很敏感,建议用taskset把测试进程绑到固定物理核心上,同时对端也做同样操作。

第二层是PCIe链路,用lspci -vvv检查网卡所在的PCIe链路速度和宽度,如果因为插槽规格或者BIOS设置导致了降速,这会造成带宽上限直接被卡死。

第三层是网络拥塞和流控,RoCE网络尤其依赖无损保障。如果有突发流量,就可能触发PFC暂停帧,此时网卡统计里的rx_pause、tx_pause计数飙升,性能自然不稳。使用ibstat或者内核里的perf净计数,可以看到这些关键数据。

最重要的一条经验:在跑正式基准时,尽量让测试机的网卡和CPU处于独占状态,关闭那些会周期性唤醒的服务、定时任务,哪怕是系统日志轮转,都可能制造微小的噪声。

4.2 连接失败类问题的定位方法

server端已经就绪,client端却报连接超时或者拒绝,常见原因有这么几类。

GID索引不匹配是RDMA特有的问题。如果是RoCEv2模式,两端必须使用正确的GID index,也就是承载在哪个VLAN或者哪条路由上。在多网卡环境中用--gid-index参数指定,能避免很多莫名其妙的问题。

防火墙和ARP/ICMP也很关键。有些环境下测试机启用了安全组,会拦截非标准端口的TCP包,从而导致rdmacm的连接建立失败。先快速用ping确认基本的IP连通性,再排查防火墙规则。

子网管理器的问题多发生在InfiniBand环境里,如果两端不在同一个子网或者子网管理器没有正确启动,表现为端口Active了但无法通信。此时用ibswitches或者iblinkinfo看看设备是否被发现。

4.3 结果偏低时的硬件与配置自查清单

我把这类问题整理成一张速查表,方便直接对照排查:

检查项操作方法常见问题
MTUibv_devinfo查看mtu端到端MTU不一致会限制带宽
流控ethtool或厂商工具查看PFC缺少无损流控时大规模传输掉速
PCIe链路lspci -vvv确认Gen和Widthx8的卡插在x4的槽上带宽腰斩
CPU调频cpupower查看governor节能模式会导致长时延迟波动
固件版本ibv_devinfo查看firmware新旧固件在小消息性能上有差异
驱动版本modinfo mlx5_core查看version不同OFED版本性能差异明显

4.4 内存注册与缓存对齐的隐蔽坑

RDMA对内存注册的要求很高,缓冲区需要注册到网卡,之后由网卡直接访问物理内存。很多初写者在用框架跑出自己的测试程序时,结果往往不稳定,本质就是缓冲区没有对齐。

常见的关键是使用posix_memalign分配页对齐的内存,而不是普通的malloc。因为RDMA网卡通常要求缓冲区地址按页大小(比如4096)对齐,非对齐会导致注册失败或者性能下降。另外,如果缓冲区被操作系统换出到swap,网卡访问时就会触发缺页中断,延迟瞬间飙升。

在进程使用fork的时候,还要注意MR的继承和kern页表的处理。RDMA的MR是进程资源的延伸,fork后如果没有办理对应处理,子进程使用MR时可能直接crash。这些细节虽然琐碎,但往往就是线上故障的根源。

5. 工具选型解析与实战经验补充

5.1 rdma_bench与其他工具的对比

做RDMA性能测试,其实市面上还有其他工具可选,比如Perftest、qperf、ib_send_bw等。很多人会问,rdma_bench相比这些有什么优势。

Perftest是Mellanox官方维护的测试合集,安装方便,很多驱动包自带。它在标准参数测试上非常可靠,但如果想扩展新测试类型,需要自己修改它的源码,结构上略显得有些复杂。rdma_bench的定位更偏向灵活性和学习属性,适合在此基础上做二次开发,或者用来理解RDMA的原语行为。

qperf则是一个网络性能测试的通用工具,支持TCP、SCTP,也支持RDMA,但它更偏黑盒测试,细节不如rdma_bench这种东西让你看清内部实现。如果只是快速打个分,qperf足够了;如果要做深入研究,rdma_bench这种开放框架价值更高。

5.2 什么时候可以把基准数据当作权威依据

这不是一个技术问题,而是心态问题。基准数据只能代表你设置的这个场景的表现,它不能自动代表“这个网卡有多快”,更不能代表“某个应用能跑多快”。任何RDMA应用的性能都取决于写代码的人是否充分利用了RDMA的特性:是否批量提交请求、是否避免不必要的内存拷贝、是否用对了RDMA操作类型。

曾经在一个项目里,用rdma_bench量出来的写带宽很高,但业务应用的数据结构散乱,每次发送前还要做一次memcpy拼装,最终性能直接掉了一个量级。后来改用了注册持久化缓冲区,在业务写入时直接就地序列化,效果立刻不一样了。这个例子足以说明,基准测试是用来指导设计、验证接口的,最终的优化还是要落实到应用层协议和编程模型上。

5.3 后续扩展方向和自定义测试的开发思路

如果项目本身满足不了你的特定需求,完全可以在这个框架的骨架上长出更多的测试节点。比如,在分布式存储场景里,你可能想模拟“远端读、本地写”的混合模式,这时候可以基于single和bidirectional两种例子,扩展出一个混合测试。

新测试的核心逻辑和现有例子差别不大,无非就是准备好QP、注册MR、组织WQE、处理完成事件,改变的只有请求类型的比例和触发节奏。把这几个环节拆分好,新测试的代码量其实很少。

另一个非常有用的扩展方向是“长时间稳定性测试”。标准基准都跑几十秒,但生产环境经常要连续运行几天,这时候可以加一个日志输出和周期性统计的功能,方便观察是否有性能随时间衰减的情况。这个扩展对实际运维非常实用,能帮你提前发现散热导致的降频、网络设备性能劣化等问题。

6. 应用场景联动与影响范围分析

6.1 RDMA基准测试在AI分布式训练中的价值

最近几年RDMA的大规模普及,很大一部分原因是分布式深度学习训练对网络通信的要求越来越苛刻。数据并行训练时,每个step结束之后,所有GPU都要同步梯度,这个AllReduce操作对带宽和时延都高度敏感。

在这种场景下,预先用rdma_bench量好当前集群的通信底数,是一个很有价值的操作。如果底数带宽不足,训练扩展性一定受限;如果时延抖动大,训练完成时间就会有不可预测的波动。而且一旦训练性能出现回退,跑一遍基准可以快速判断是不是网络变化导致的,为定位问题省下大量时间。

有一个真实的例子,某团队在将训练框架从TCP切换到RoCE之后,整体吞吐没有明显提升,回看基准结果才发现小消息的时延在新网络上反而更高。后面排查到是驱动中某些tuning没有开启,调整后才释放了真正的实力。基准测试在整个过程中起到了航标灯的作用。

6.2 存储领域的高吞吐低时延验证

分布式存储是另一个RDMA应用大户,尤其是NVMe over Fabric、分布式块存储这类场景。存储系统的IO路径上,每多一次毫秒级延迟都会直接影响上层数据库的性能,所以RDMA引入后的第一步也是先打好底数。

rdma_bench测得的是纯粹的硬件通道能力,存储软件基于它可以做更现实的修正。比如,块大小4KB时延是否在可接受范围、64KB顺序写能否跑满网络带宽,这些都是存储引擎设计时的核心参数。提前用基准测试界定边界,能有效避免架构选型阶段做太多拍脑袋决策。

6.3 网络运维领域的巡检与回归体系

除开发场景外,rdma_bench在运维领域的用处也很大。很多高性能计算和AI平台的运维团队需要确保集群网络持续处于健康状态。最简单的方式就是定时跑一小组基准用例,把带宽、时延、重传计数等关键指标保存下来,建立历史基线。

一旦某天有作业反馈性能下降,调出一段时间的基准趋势图,就能迅速判断究竟是应用负载变化、网络微突发,还是硬件开始劣化。这种“性能基线巡检”的思路,配合告警阈值设置,在运营层面相当有效。

在我个人的运维习惯里,新上线一批机器前必跑一轮完整的带宽和时延扫描,把每台设备的性能标签记录在案。这个习惯避免了后续在故障排查时“既要知道是不是硬件问题,又拿不出历史数据对比”的尴尬。

6.4 对行业人才培养和新手入门的帮助

最后想谈谈它对学习和人才培养的价值。RDMA的代码样例公开多年,但大多数场合只是零散的片段,很难让人形成系统认识。rdma_bench这种框架把各种原语用法集合在一个完整的、可运行的项目里,分成清晰的递进路径,非常适合作为教学材料。

新手从最简单的pingpong跑起,看着“消息发出去再收回来”的流程,再到多QP并发、事件管理、统计输出,一套流程走完,RDMA的开发思路基本就建立起来了。比起读十篇博客,亲自跑、亲手改、把结果和猜想对照,学到的东西要扎实得多。我始终认为,好的开发工具和好的教材是同一件事,rdma_bench就走在两者交汇的位置上。

回看这些年的项目经历,RDMA看似复杂,但只要有一个趁手的框架、一套清晰的方法论,并且真正花时间去理解每一条曲线背后的硬件行为,它其实完全是可以被“驯服”的。希望这篇内容能帮你减少一些迷茫,在RDMA的性能迷雾里找到自己的坐标系。

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

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

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

立即咨询