SoftRoCE 实战:无硬件 RDMA 环境下的功能验证与性能调优

发布时间:2026/10/17 9:31:14
SoftRoCE 实战:无硬件 RDMA 环境下的功能验证与性能调优 1. 为什么要在普通环境里折腾 SoftRoCE第一次接触 SoftRoCE 是在一个内部测试环境里当时手头只有几台普通服务器网卡是再普通不过的千兆口没有支持 RDMA 的专用硬件。但业务侧又确实需要验证一套基于 RDMA 的通信逻辑比如零拷贝、内核旁路、单边操作这些特性。买专用网卡和交换机成本高、周期长于是 SoftRoCE 就成了最现实的切入点。SoftRoCE 全称是 Software RDMA over Converged Ethernet它是 RDMA 协议栈在软件层面的实现。简单说就是把本来应该由专用硬件网卡完成的 RDMA 语义用软件的方式跑在普通以太网卡上。它不需要网卡支持 RoCE也不需要交换机做无损以太网配置只要内核支持就能跑起来。代价也很明显性能远不如硬件 RDMA延迟高、吞吐低、CPU 占用大但它的价值在于功能验证、开发调试和教学演示。这篇文章适合几类人看一是手头没有 RDMA 硬件但需要验证 RDMA 编程模型的开发者二是想理解 RDMA 通信机制、但又不想一上来就啃硬件手册的运维或后端同学三是需要在 CI 环境里跑 RDMA 相关测试的工程团队。我会从整体设计思路讲起把内核模块加载、设备配置、性能调优、常见故障排查这些环节都拆开说清楚尽量让不同基础的人都能照着复现。需要提前说明的是SoftRoCE 的性能数据不要拿去做生产容量规划它的意义在于功能验证和逻辑调试。我实测下来它的延迟通常在几十微秒到上百微秒级别和硬件 RDMA 的亚微秒级完全不在一个量级。但如果你只是想跑通一个 RDMA 读写程序或者验证一套基于 verbs 的通信框架它完全够用。2. SoftRoCE 的整体设计与核心思路拆解2.1 软件 RDMA 到底在软件里模拟了什么要理解 SoftRoCE得先知道硬件 RDMA 网卡干了哪些事。硬件 RDMA 网卡的核心能力包括队列对Queue PairQP管理、完成队列Completion QueueCQ管理、内存注册Memory RegistrationMR、保护域Protection DomainPD以及单边操作RDMA Read/Write的硬件卸载。这些操作在硬件上由网卡芯片直接完成CPU 只需要下发工作请求Work RequestWR然后等完成事件就行。SoftRoCE 做的事情就是把这些原本由网卡芯片完成的逻辑全部搬到内核软件层来实现。它通过内核模块rdma_rxe注册一个软件 RDMA 设备这个设备在用户态看来和真实的 RDMA 网卡没有区别一样有设备节点、一样能跑 verbs 接口。用户程序调用ibv_post_send之类的接口时请求会进入软件驱动由内核线程完成数据搬运和协议封装最后通过普通以太网卡发出去。这里的关键设计在于SoftRoCE 复用了 Linux 内核已有的 RDMA 子系统RDMA subsystem也就是ib_core那一套。它只是提供了一个软件化的 provider把底层传输交给普通网络栈。这样做的好处是上层 verbs 接口完全不用改同一套代码既能在硬件 RDMA 上跑也能在 SoftRoCE 上跑切换成本极低。2.2 为什么选择 SoftRoCE 而不是其他方案在没有硬件 RDMA 的情况下想验证 RDMA 逻辑其实有几条路。一条是用 TCP socket 自己模拟 RDMA 语义但这只能模拟行为无法验证真实的 verbs 编程模型另一条是用一些用户态的 RDMA 模拟库但这类库往往接口不完整和内核子系统脱节还有一条就是 SoftRoCE它是内核原生支持的接口最完整和真实 RDMA 的差异最小。我选 SoftRoCE 的核心理由有三个。第一是接口一致性用户态程序不需要任何改动librdmacm和libibverbs都能直接用第二是内核态支持它走的是标准 RDMA 子系统能验证内核态 RDMA 相关的逻辑第三是部署简单不需要专用硬件普通服务器装个内核模块就能跑。当然它也有明显的短板。性能是最大的问题因为所有数据搬运都要经过 CPU 和内核网络栈零拷贝的优势基本没了。另外它依赖内核版本不同内核版本上rdma_rxe模块的稳定性和功能支持程度有差异。还有一个坑是它默认走 UDP 封装对 MTU 和网络质量比较敏感配置不当容易出现丢包和性能骤降。2.3 整体架构分层与数据流向SoftRoCE 的架构可以分成四层来看。最上层是用户态 verbs 接口也就是libibverbs和librdmacm提供的 API第二层是内核 RDMA 子系统ib_core负责设备管理、PD、MR、QP 这些核心对象的生命周期第三层是rdma_rxe软件驱动负责把 RDMA 操作翻译成普通网络包最底层是普通以太网卡和内核网络栈。数据流向大致是这样的用户程序提交一个 RDMA Write 请求请求通过ib_core进入rdma_rxerdma_rxe把数据封装成 RoCE 格式的 UDP 包然后通过普通网卡发出去。对端收到包后内核网络栈识别出这是 RoCE 包交给rdma_rxe处理rdma_rxe解析出 RDMA 语义把数据写入目标内存最后生成完成事件。整个过程对用户程序透明用户程序只看到 WR 提交和 CQ 完成。这个数据流里最耗时的环节是内核网络栈的处理和内存拷贝。硬件 RDMA 之所以快是因为它绕过了内核网络栈直接在网卡和用户内存之间搬运数据。SoftRoCE 做不到这一点所以性能差距主要就体现在这里。3. 核心细节解析与实操要点3.1 内核模块加载与设备创建的关键细节SoftRoCE 的核心内核模块是rdma_rxe但在加载它之前需要先确保ib_core和ib_uverbs已经就位。大多数现代发行版的内核都自带这些模块但有些精简内核可能没有编译进去需要提前确认。加载模块的命令很直接modprobe rdma_rxe加载完成后可以用rdma link查看当前 RDMA 链路状态。这时候通常还没有任何 SoftRoCE 设备需要手动创建一个。创建命令是rdma link add rxe0 type rxe netdev eth0这里的rxe0是设备名eth0是底层承载的普通网卡。这条命令的含义是在eth0上创建一个名为rxe0的软件 RDMA 设备。创建成功后ibv_devices就能看到rxe0这个设备了。这里有几个细节容易踩坑。第一netdev指定的网卡必须是 up 状态否则创建会失败第二设备名不要和已有设备冲突建议用rxe前缀加编号第三如果底层网卡有多个 IPSoftRoCE 默认会用第一个需要显式指定时可以通过rdma link的其他参数调整。我遇到过创建成功但无法通信的情况最后发现是底层网卡没配 IP或者防火墙拦了 UDP 端口。3.2 内存注册与保护域的操作要点RDMA 编程里内存注册MR是最基础也最容易出问题的环节。因为 RDMA 要求内存被 pin 住不能被换出所以注册的内存区域必须是物理连续的或者至少是锁定在物理内存里的。SoftRoCE 虽然不依赖硬件网卡但 MR 的语义是一样的。注册 MR 的典型流程是先分配内存可以用malloc也可以用mmap然后调用ibv_reg_mr注册。注册时需要指定访问权限比如IBV_ACCESS_LOCAL_WRITE、IBV_ACCESS_REMOTE_WRITE、IBV_ACCESS_REMOTE_READ这些。权限给多了有安全风险给少了操作会失败需要根据实际用途精确设置。struct ibv_mr *mr ibv_reg_mr(pd, buf, size, IBV_ACCESS_LOCAL_WRITE | IBV_ACCESS_REMOTE_WRITE | IBV_ACCESS_REMOTE_READ);这里有个经验注册的内存大小最好是页大小的整数倍虽然内核会自动对齐但手动对齐能减少内部碎片。另外注册大量小内存块会消耗很多 MR 资源SoftRoCE 的 MR 数量上限受内核参数限制可以通过rdma system相关命令查看和调整。我建议把多个小对象合并到一个大 MR 里用偏移量来区分这样既省资源又方便管理。还有一个坑是内存对齐。有些 verbs 操作对地址对齐有要求比如原子操作要求 8 字节对齐。如果地址不对齐操作会直接失败而且错误信息往往不直观。我的做法是在分配内存时就按 64 字节对齐这样绝大多数操作都不会有对齐问题。3.3 队列对与完成队列的配置逻辑队列对QP是 RDMA 通信的核心对象每个 QP 包含一个发送队列和一个接收队列。创建 QP 时需要指定 QP 类型常见的有 RCReliable Connection、UCUnreliable Connection、UDUnreliable Datagram。SoftRoCE 对这几种类型都支持但 RC 用得最多因为它提供可靠传输。创建 QP 的代码大致如下struct ibv_qp_init_attr attr { .send_cq send_cq, .recv_cq recv_cq, .cap { .max_send_wr 128, .max_recv_wr 128, .max_send_sge 1, .max_recv_sge 1, }, .qp_type IBV_QPT_RC, }; struct ibv_qp *qp ibv_create_qp(pd, attr);这里的max_send_wr和max_recv_wr是队列深度决定了能同时挂多少个未完成的 WR。设太小会导致提交失败设太大会占用更多内存。我的经验是先从 128 开始根据实际并发量调整。max_send_sge和max_recv_sge是散射聚集元素的数量SoftRoCE 对多 SGE 的支持不如硬件网卡建议先用 1确认没问题再往上加。完成队列CQ的创建相对简单但要注意 CQ 的大小要能容纳所有关联 QP 的完成事件。如果 CQ 溢出完成事件会丢失程序会卡在等待完成的地方。我一般会把 CQ 大小设成所有 QP 队列深度之和再加一些余量。QP 创建后还需要经历几个状态迁移RESET、INIT、RTR、RTS。每个状态迁移都需要通过ibv_modify_qp设置相应参数。RC 类型的 QP 在 RTR 状态需要设置对端的 QPN、LID、GID 等信息这些信息需要通过带外方式交换。SoftRoCE 的 GID 是基于底层网卡 IP 生成的交换 GID 时要注意区分 IPv4 和 IPv6 格式。4. 实操过程与核心环节实现4.1 环境准备与依赖检查在开始之前先确认环境满足基本要求。内核版本建议 4.9 以上太老的内核对rdma_rxe支持不完整。检查内核模块是否存在modinfo rdma_rxe如果提示模块不存在说明内核没编译这个模块需要换内核或者重新编译。确认ib_core、ib_uverbs、rdma_rxe三个模块都能正常加载。用户态需要安装libibverbs、librdmacm、rdma-core这些包不同发行版包名略有差异。# 以常见发行版为例 yum install rdma-core libibverbs librdmacm # 或者 apt install rdma-core libibverbs-dev librdmacm-dev安装完成后用ibv_devinfo查看设备列表。如果还没有创建 SoftRoCE 设备这个命令可能只显示硬件设备或者为空。创建 SoftRoCE 设备后应该能看到rxe0及其详细属性包括支持的 QP 类型、最大 MR 数量、最大 QP 数量等。网络方面确保底层网卡 up 且有 IP两台机器之间能互相 ping 通。SoftRoCE 默认使用 UDP 端口 4791防火墙需要放行这个端口。如果是在容器环境里跑还要注意网络命名空间的问题SoftRoCE 设备是绑定在特定 netns 里的跨 netns 通信需要额外配置。4.2 双机通信的完整配置流程假设有两台机器 A 和 B底层网卡分别是eth0IP 分别是192.168.1.10和192.168.1.11。配置步骤如下。在 A 和 B 上分别加载模块并创建 SoftRoCE 设备modprobe rdma_rxe rdma link add rxe0 type rxe netdev eth0然后用ibv_devices确认设备存在用rdma link show查看链路状态。接下来需要确认 GID用show_gids或者ibv_devinfo -v查看。SoftRoCE 的 GID 通常对应底层网卡的 IPA 的 GID 里应该包含192.168.1.10对应的条目B 的对应192.168.1.11。写一个简单的测试程序A 作为服务端B 作为客户端。服务端先创建 PD、MR、CQ、QP然后进入 RTR 状态等待连接。客户端创建自己的资源后通过带外方式比如 TCP socket交换 QPN、GID、MR 的 rkey 和地址然后客户端把 QP 迁移到 RTS 状态发起 RDMA Write。这里的关键是带外交换的信息要完整。需要交换的包括QPN队列对编号、GID全局标识、MR 的rkey远程密钥和addr远程地址。少任何一个对端都无法正确发起操作。我建议把这些信息打包成一个结构体通过 TCP 一次性发送避免多次交互。4.3 性能测试与参数调优记录功能跑通后下一步是看性能。SoftRoCE 的性能测试可以用ib_write_bw、ib_write_lat这些工具它们属于perftest套件。安装后直接运行即可# 服务端 ib_write_bw -d rxe0 # 客户端 ib_write_bw -d rxe0 192.168.1.10我实测的数据是在千兆网卡上SoftRoCE 的带宽大概在 100 到 200 Mbps 之间延迟在 50 到 100 微秒。这个数据受很多因素影响包括 CPU 性能、内核版本、MTU 设置等。调优方面有几个方向可以尝试。第一是调大 MTU把底层网卡 MTU 设成 9000 能显著减少包数量提升吞吐第二是调整内核网络参数比如增大 socket buffer、关闭不必要的网络特性第三是绑定 CPU把 SoftRoCE 的内核线程绑到固定 CPU 上减少上下文切换。我试过把 MTU 从 1500 调到 9000带宽大概提升了 30% 左右。还有一个容易被忽略的点是中断亲和性。SoftRoCE 处理网络包时会触发中断如果中断都集中在一个 CPU 上会成为瓶颈。可以通过irqbalance或者手动设置/proc/irq/*/smp_affinity来分散中断。这个调整在高负载场景下效果比较明显。5. 常见问题与排查技巧实录5.1 设备创建失败与链路异常排查最常见的问题是rdma link add失败报错信息可能是No such device或者Operation not supported。前者通常是底层网卡名写错了或者网卡没 up后者多半是内核模块没加载全或者内核版本不支持。排查顺序是先ip link show确认网卡存在且 up再lsmod | grep rxe确认模块加载最后dmesg | tail看内核日志有没有相关报错。另一个常见现象是设备创建成功但ibv_devinfo看不到端口信息或者端口状态是 DOWN。这通常是因为底层网卡没有 IP或者 GID 表为空。SoftRoCE 的端口状态依赖底层网卡状态底层网卡 down 了SoftRoCE 端口也会 down。解决办法是确保底层网卡有 IP 且能正常通信。还有一种情况是设备创建后一段时间自动消失这往往是底层网卡状态变化导致的。比如网卡被重启、IP 被移除SoftRoCE 设备会跟着消失。如果业务依赖 SoftRoCE建议把创建命令做成开机自启或者用 systemd 管理并在网卡状态变化时自动重建。5.2 通信失败与超时问题定位通信失败的表现形式很多最常见的是ibv_post_send返回成功但 CQ 一直等不到完成事件最后超时。这种问题排查起来比较麻烦因为涉及两端。我的排查思路是分层次定位先确认底层网络通不通再确认 GID 和 QPN 交换是否正确最后看 QP 状态迁移是否成功。底层网络排查最简单直接ping对端 IP再用tcpdump抓 UDP 4791 端口的包。如果抓不到包说明请求根本没发出去可能是 QP 状态不对或者路由有问题。如果能抓到包但对端没响应可能是对端 GID 配错了或者对端防火墙拦了包。QP 状态迁移失败也是常见问题。ibv_modify_qp返回错误时错误码往往能说明问题。比如EINVAL通常是参数不合法检查 QPN、GID 这些字段ENOMEM是资源不足可能是 QP 数量超限。我遇到过 RTR 迁移失败最后发现是 GID 索引写错了SoftRoCE 的 GID 表里可能有多个条目要选对底层网卡对应的那个。还有一个隐蔽的坑是 MTU 不匹配。SoftRoCE 的 MTU 和底层网卡 MTU 是联动的如果两端 MTU 不一致大包会被分片或者丢弃表现为小消息正常、大消息超时。解决办法是确保两端底层网卡 MTU 一致并且 SoftRoCE 的 MTU 不超过底层网卡的 MTU。5.3 常见问题速查表问题现象可能原因排查方法解决方式设备创建失败网卡名错误或未 upip link show确认网卡状态修正网卡名确保网卡 up端口状态 DOWN底层网卡无 IPip addr查看 IP给底层网卡配置 IP通信超时防火墙拦截 UDP 4791tcpdump抓包放行 UDP 4791 端口QP 迁移失败GID 或 QPN 错误检查交换的信息重新交换并核对 GID 索引大消息失败MTU 不匹配查看两端 MTU统一 MTU 设置性能极低中断集中或 MTU 小top看 CPU 分布分散中断调大 MTU设备自动消失底层网卡状态变化dmesg看日志用脚本监控并自动重建5.4 几个我踩过的坑和独家技巧第一个坑是内核版本差异。我在一个较老的内核上跑 SoftRoCE发现rdma link add命令不存在后来才知道那个内核的rdma工具版本太老需要用rxe_cfg这个旧工具。不同内核和工具版本的命令差异挺大建议先确认工具版本再查对应文档。第二个坑是内存注册失败。有一次注册一个很大的 MR一直返回ENOMEM查了半天发现是ulimit -l限制太小锁定内存不够。RDMA 的 MR 需要锁定物理内存ulimit -l决定了单个进程能锁定的内存上限。解决办法是调大ulimit -l或者减少单次注册的内存大小。第三个技巧是关于调试的。SoftRoCE 的内核模块支持动态调试可以通过echo 1 /sys/module/rdma_rxe/parameters/debug打开调试日志然后dmesg就能看到详细的处理过程。这个日志在排查协议层问题时非常有用能看到每个包的收发和处理结果。不过日志量很大生产环境慎用。第四个技巧是关于性能的。如果只是做功能验证不需要追求性能可以把 QP 队列深度设小一点减少内存占用。但如果要做压力测试建议把队列深度设大并且用多个 QP 并行这样能更好地利用多核 CPU。我试过用 4 个 QP 并行吞吐比单 QP 提升了将近一倍。6. 从功能验证到持续集成的延伸思路SoftRoCE 最有价值的场景其实是持续集成。在没有 RDMA 硬件的 CI 环境里用 SoftRoCE 可以跑通 RDMA 相关的单元测试和集成测试保证代码在真实硬件上运行前逻辑是正确的。我所在的团队就把 SoftRoCE 集成到了 CI 流水线里每次提交代码都会自动跑一遍 RDMA 通信测试。具体做法是在 CI 的容器里加载rdma_rxe模块创建 SoftRoCE 设备然后跑测试用例。需要注意的是容器需要特权模式因为加载内核模块需要权限。另外容器网络要配置好确保 SoftRoCE 设备能在容器内正常创建和使用。如果 CI 环境不支持特权容器可以考虑用虚拟机或者裸机 runner。测试用例的设计上我建议覆盖几个关键场景基本 RDMA Write/Read、带立即数的操作、原子操作、错误处理路径。错误处理路径特别重要因为 RDMA 的错误往往比较隐蔽提前在 SoftRoCE 上验证能避免很多线上问题。比如故意传错 rkey看程序是否能正确捕获错误并恢复。还有一个延伸方向是用 SoftRoCE 做教学演示。RDMA 编程门槛高很大一部分原因是硬件环境难获取。用 SoftRoCE 可以在普通笔记本或者虚拟机上搭建 RDMA 环境学生可以直观地看到 QP 状态迁移、CQ 事件、MR 注册这些概念的实际效果。我在内部做技术分享时就用过这种方式反馈比纯讲理论好很多。最后再分享一个小技巧如果需要在多台机器之间快速搭建 SoftRoCE 环境可以写一个简单的脚本把模块加载、设备创建、IP 配置、防火墙放行这些步骤都自动化。脚本里加上状态检查每一步失败就报错退出这样能避免手工操作遗漏。我用这个脚本把环境搭建时间从十几分钟压缩到了不到一分钟而且不容易出错。

关于本文作者

来自尧图内容编辑团队

尧图内容编辑团队 内容团队

尧图内容编辑团队

本文由尧图网络内容编辑团队执笔。团队由资深项目经理、前端工程师与设计师组成,所有内容均来自亲手交付的真实项目,先讲清问题、再给出可落地的解法。尧图深耕北京网站建设十年,服务过京华建材集团、智造科技等各行业客户,把一线经验沉淀为可复用的行业观察。

  • 十年建站经验,覆盖建材、制造、服务、文创等
  • 项目经理把关选题与事实准确性
  • 工程师与设计师联合撰写专业细节
  • 统一编辑规范,保证文风与排版一致
  • 每月复盘转化数据,迭代选题方向

延伸阅读

相关资讯与近期热门内容

深度阅读推荐

建站决策前值得细读的三篇

网站改版的5个关键决策
2024-08-12

网站改版的5个关键决策

什么时候该改版、改到什么程度、如何避免流量掉光,京华建材集团改版复盘给出答案。

获取专属建站方案

看完文章,把您的行业与预算告诉我们,免费获取一份量身定制的官网建设方案与报价。

立即免费咨询