用RDMA实现文件传输

发布时间:2026/11/5 9:02:33

用RDMA实现文件传输 一、概述我们上一篇博客介绍了RDMA的相关概念本博客在此基础之上使用 verbs 编程实现 RDMA 文件传输演示代码已开源(Githubrdma-sendfile。如果你还不了解QP、WR、MR等 RDMA基本要素可以先花五分钟看看RDMA要素介绍。RDMA有IB、RoCE、iWARP三种协议然而上层的用户接口都是VerbsVerbs 可以看作HCA对主机提供的RDMA功能接口。RDMA 文件传输主要涉及两个部分的编码控制消息的传递文件数据的传输RDMA 提供了单边模式、双边模式两种工作模式对应send/recv、write/read 四种操作它们的特点和使用场景我们可以总结如下维度双边操作Send/Recv单边操作RDMA Read/Write远端CPU参与需要预先发布Recv WR不需要完全无感完成通知双方都产生CQE仅发起方产生CQE需要的信息只需本地缓冲区需要远端地址 rkey适用消息大小小消息控制类大消息数据类典型应用控制消息、元数据交换批量数据传输所以在我们的 RDMA 文件传输助手实现中控制消息的传递使用双边模式 send/recv而数据传输则使用单边的 write。主要的思路是先建链并使用双边模式传递控制消息然后复用链路进行单边模式 write 文件传输。二、控制消息传递控制消息: remote_addr、rkey要搞清楚控制消息传递如何实现我们先要搞清楚所谓的控制消息到底有什么我们最终需要通过单边模式write来实现大批量的数据传输主机写入远端内存的之前需要知道远端内存缓冲区地址和rkey这也就是RDMA文件传输助手中最关键的控制消息。双边模式并不需要提供远端地址和rkey就可以进行通信只需要远端预先发布recv WR我们可以根据这个特点进行元数据交换然后主机根据拿到的元数据进行单边write操作。RDMA 的 send和recv 的工作流程如下:初始化双方打开RDMA设备分配PD、注册MR并获取对应的lkey创建QP、CQ等//建链与初始化staticvoidinitialize_connection(structrdma_cm_id*cm_id){structibv_pd*pdibv_alloc_pd(cm_id-verbs);//分配PDstructibv_comp_channel*channelibv_create_comp_channel(cm_id-verbs);//创建完成事件通道structibv_cq*cqibv_create_cq(cm_id-verbs,1024,NULL,channel,0);//创建CQstructibv_qp_init_attrqp_attr{.send_cqcq,.recv_cqcq,.qp_typeIBV_QPT_RC,.cap{.max_send_wr1024,.max_recv_wr1024,.max_send_sge1,.max_recv_sge1}};rdma_create_qp(cm_id,pd,qp_attr);//创建QPconn_manger_t*conncalloc(1,sizeof(*conn));conn-pdpd;conn-qpcm_id-qp;conn-cqcq;conn-channelchannel;posix_memalign((void**)conn-recv_buffer,4096,CTRL_BUF_SIZE);posix_memalign((void**)conn-send_buffer,4096,CTRL_BUF_SIZE);//注册MRconn-recv_mribv_reg_mr(pd,conn-recv_buffer,CTRL_BUF_SIZE,IBV_ACCESS_LOCAL_WRITE|IBV_ACCESS_REMOTE_WRITE);conn-send_mribv_reg_mr(pd,conn-send_buffer,CTRL_BUF_SIZE,IBV_ACCESS_LOCAL_WRITE|IBV_ACCESS_REMOTE_READ);cm_id-contextconn;}远端预先建构并发布recv WR并将recv WR推入RQ中staticintpost_recv(conn_manger_t*conn){//构建recv WRstructibv_sgesge;memset(sge,0,sizeof(sge));sge.addr(uintptr_t)conn-recv_buffer;sge.lengthCTRL_BUF_SIZE;sge.lkeyconn-recv_mr-lkey;//lkey用于操作本地的MRstructibv_recv_wrrecv_wr,*bad_recv_wrNULL;memset(recv_wr,0,sizeof(recv_wr));recv_wr.wr_id(uintptr_t)conn;recv_wr.sg_listsge;recv_wr.num_sge1;conn-recv_outstanding1;//将recv WR推送到RQif(ibv_post_recv(conn-qp,recv_wr,bad_recv_wr)){conn-recv_outstanding0;perror(ibv_post_recv);return-1;}return0;}说明SGEScatter/Gather Element用于向硬件描述一块内存区域structibv_sge{uint64_taddr;// 内存缓冲区的起始虚拟地址uint32_tlength;// 缓冲区长度字节数uint32_tlkey;// 本地内存密钥由注册MR时获得};本机构建send WR包含控制消息将send WR推入SQ中staticintpost_send(conn_manger_t*conn,uint32_tlength){if(length0||lengthCTRL_BUF_SIZE)return-1;//构建send WRstructibv_sgesge;memset(sge,0,sizeof(sge));sge.addr(uintptr_t)conn-send_buffer;sge.lengthlength;sge.lkeyconn-send_mr-lkey;//lkey操作本地MRstructibv_send_wrsend_wr,*bad_send_wrNULL;memset(send_wr,0,sizeof(send_wr));send_wr.wr_id(uintptr_t)conn;send_wr.opcodeIBV_WR_SEND;//操作码IBV_WR_SENDsend_wr.send_flagsIBV_SEND_SIGNALED;send_wr.sg_listsge;send_wr.num_sge1;conn-send_outstanding1;//将send WR推送到SQif(ibv_post_send(conn-qp,send_wr,bad_send_wr)){conn-send_outstanding0;perror(ibv_post_send);return-1;}returnwait_send_done(conn);}RDMA硬件完成通信产生WC本机和远端轮询CQ回收WCstaticintpoll_cq_batch(conn_manger_t*conn){structibv_wcwcs[POLL_BATCH];intnibv_poll_cq(conn-cq,POLL_BATCH,wcs);//轮询CQ,获取一批WC//遍历检查WC状态for(inti0;in;i){structibv_wc*wcwcs[i];if(wc-status!IBV_WC_SUCCESS){conn-send_outstanding0;conn-recv_outstanding0;conn-write_inflight0;continue;}//操作码对应if(wc-opcodeIBV_WC_RDMA_WRITE){//这个部分是单边write 消费WC用的先不需要管intcredits(int)wc-wr_id;if(credits0)credits1;conn-write_inflight-credits;if(conn-write_inflight0)conn-write_inflight0;}elseif(wc-opcodeIBV_WC_SEND){//WC回收计数清除conn-send_outstanding0;}elseif(wc-opcodeIBV_WC_RECV){//同上conn-recv_outstanding0;}}returnn;}三、文件数据传输我们通过双边模式交换控制消息远端地址、rkey等之后现在主机发送端拥有了足够的信息执行单边write了前面我们已经介绍了双边模式下使用的函数其中许多都可以重复使用比如PD分配与MR的注册、轮询CQ等。单边数据write的过程如下分配 PD注册待传输数据的 MR用 chunks 批量构建send WR将 MR 切成很多个 chunks用SGE向RDMA硬件描述每块 chunk 的内存区域将已经取得的远端地址remote_addr和rkey等写入WR中批量推入SQ多个WR inflight。staticintpost_rdma_file(conn_manger_t*conn){size_toffset0;size_tsizeconn-src_size;uint32_tlkeyconn-src_mr-lkey;//用chunks批量构建WRwhile(offsetsize){//write窗口满了while(conn-write_inflightWR_WINDOW){cq_wait_progress(conn);}// 计算本次分块长度size_tremainsize-offset;uint32_tlen(remainCHUNK_SIZE)?CHUNK_SIZE:(uint32_t)remain;structibv_sgesge{.addr(uint64_t)(uintptr_t)(conn-src_bufoffset),.lengthlen,.lkeylkey};structibv_send_wrsend_wr{.wr_id1,.opcodeIBV_WR_RDMA_WRITE,//操作码是IBV_WR_RDMA_WRITE.send_flagsIBV_SEND_SIGNALED,.sg_listsge,.num_sge1,.wr.rdma{.remote_addrconn-remote_addroffset,.rkeyconn-remote_rkey}};conn-write_inflight;ibv_post_send(conn-qp,send_wr,NULL);offsetlen;}while(conn-write_inflight0){if(cq_wait_progress(conn)0)return-1;}return0;}RDMA硬件完成发送产生WC轮询CQ回收WC//poll_cq_batch() 中处理单边write的分支if(wc-opcodeIBV_WC_RDMA_WRITE){intcredits(int)wc-wr_id;if(credits0)credits1;conn-write_inflight-credits;//inflight的减去完成的WC数目if(conn-write_inflight0)conn-write_inflight0;}四、测试我使用了两台虚拟机使用siwSoft-iWARP 。siw 是 Linux 内核中一个纯软件实现的 RDMA 设备驱动它允许你在标准以太网卡上运行 RDMA 应用无需专用的 RDMA 网卡硬件进行测试以下结果仅供参考测试场景吞吐量结论跨机 perftest~12 MB/s官方工具测 siw 跨机性能上限受限于软件模拟 TCP/IP 协议栈实际传输~9 MiB/s与官方基准同一量级代码实现无明显性能缺陷
延伸阅读

更多相关文章

2026/11/4 23:09:08

2026防刷投票系统怎么选?5个实用标准,正式评选更公平

2026 年办投票活动,刷票是最影响活动效果的问题,尤其是正式评选,一旦刷票失控,结果就失去公信力,还容易引发争议。判断一个防刷投票系统靠不靠谱,不用懂复杂技术,看 5 个实用标准就行&#xff0…

2026/11/1 4:29:55

rancher v2.6.5 部署rancher-monitor (已监控k8s v1.23.12)

安装说明: rancher需要安装的rancher monitoring和prometheus的node exporter, rancher monitoring用来监控ranhcer里各个pods的运行状态,node exporter则用来监控裸机的运行状态rancher monitoring和prometheus的node exporter,相…

2026/11/3 9:21:26

Python实现多文件夹文件汇总:递归遍历与重名冲突处理实战

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/11/5 8:53:18

【后端开发】FastAPI基础

2026.6.21 一、代码 1.导包 from fastapi import FastAPI # from ... import ...手动配置的方法: 终端输入:(确保终端提示符前有 (.venv) 标记) pip install fastapi uvicorn2.创建实例 FastAPI实例app app FastAPI()3.定义接口 …

2026/11/5 8:48:17

【Java基础知识】字面量与变量

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/11/5 8:48:17

kafka--基础知识点--0

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/11/5 8:48:17

快速上手playwight

在自动化测试和网页爬虫的领域,Selenium 曾是无可争议的霸主。然而,随着现代 Web 应用越来越复杂(大量使用 React、Vue、单页应用等),传统的测试工具开始显得有些力不从心。今天,我们要聊的是由微软开源的现…

2026/11/4 12:38:23

面向复杂光照与角度的宠物面部识别鲁棒性增强策略

在智慧养宠时代,基于视觉的宠物身份识别技术正逐步从实验室走向家庭应用。然而,与配合度高的人类不同,宠物是典型的“非合作生物识别对象”——它们不会主动配合摄像头调整姿态,更无法控制光照环境。实际应用中,我们常…

2026/11/4 21:04:25

SSM电子书店源码全解析:结构、原理、部署与排错实战

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/11/5 0:02:07

多智能体协作系统架构设计与实践优化

1. 多智能体协作系统的时代背景2017年Transformer架构的诞生彻底改变了人工智能的发展轨迹。当行业还沉浸在单一大模型带来的性能突破时,Anthropic的研究团队已经将目光投向了更前沿的领域——如何让多个智能体通过协作产生超越单体能力的系统智能。这就像交响乐团中…

2026/11/5 0:02:07

大模型系统性入门实战指南:从原理到部署微调的全链路路线

提到大模型的系统性入门,我先说个结论:这事真不难,难的是资料太散、路线太多,今天这个框架明天那个工具,新人很容易在“收藏夹吃灰”和“教程看到一半放弃”之间反复横跳。市面上关于大模型的内容少说有几十万篇&#…

2026/11/5 0:02:07

鸿蒙文件系统沙箱机制解析与开发实践

1. 鸿蒙文件系统沙箱机制深度解析作为一名从Android转向鸿蒙开发的工程师,我深刻体会到文件系统访问是迁移过程中最先遇到的"拦路虎"。在Android上运行良好的文件读写代码,在鸿蒙真机环境却频频出现文件写入后神秘消失或直接抛出权限拒绝错误的…

2026/11/4 12:38:23

面向复杂光照与角度的宠物面部识别鲁棒性增强策略

在智慧养宠时代,基于视觉的宠物身份识别技术正逐步从实验室走向家庭应用。然而,与配合度高的人类不同,宠物是典型的“非合作生物识别对象”——它们不会主动配合摄像头调整姿态,更无法控制光照环境。实际应用中,我们常…

2026/11/4 21:04:25

SSM电子书店源码全解析:结构、原理、部署与排错实战

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

还想了解更多?直接咨询顾问

免费诊断 + 免费方案 + 透明报价。

全国咨询热线400-8866-253
免费获取方案
☎咨询二维码 ☎ ↑