简介这份资源是面向RDMA初学者与高性能网络开发者的C语言编程示例源码包围绕InfiniBand Verbs核心API展开帮助读者在缺少完整工程参考的情况下动手理解RDMA通信机制。包内共18个文件以8个.c源文件与3个.h头文件为主体配合3个Makefile构建脚本、3个txt说明及1个md文档压缩包约19KB体量轻便却覆盖了从基础客户端/服务端到读写、文件传输的递进式示例。内容涉及RDMA上下文初始化、队列对与完成队列的创建绑定、内存区域注册、工作请求提交与完成事件处理等关键环节并给出资源释放的完整流程。已有271人学习适合希望掌握libibverbs用法、降低网络通信延迟与CPU占用的开发者对照研读也可作为高性能计算、大数据传输场景的入门实践素材。1. 从一份 RDMA 源码说起为什么“角落里的极客”值得你花时间很多人第一次接触 RDMA是在机房调ibv_post_send的时候代码跑通了带宽却只有理论值的三分之一perfquery里一堆port_xmit_discards然后开始怀疑人生。这份名为the-geek-in-the-corner-master_rdma_源码的东西本质上就是一位常年蹲在机房角落的工程师把自己从 verbs 接口到内核态驱动、从内存注册到完成队列轮询的整套理解用可编译、可运行的源码形式摊开给你看。它解决的不是“RDMA 是什么”这种科普问题而是“我照着文档写出来的代码为什么跑不满、为什么偶发超时、为什么内存一注册就报Cannot allocate memory”这类只有真正上过机器才会遇到的落地问题。适合谁适合已经能写 socket、想把手里的分布式存储、KV 缓存、参数服务器或者自研 RPC 从 TCP 迁到 RDMA 的工程师也适合被rdma_cm事件回调绕晕、想找一份能逐行对照的参考实现的人。源码这个词在热搜里天天出现但真正能让你少走三个月弯路的往往是这种带血泪注释的工程代码而不是又一份 hello world。2. 先把 verbs 编程模型立住从“能跑”到“跑得对”的四个对象2.1 保护域、内存区域与队列对谁管谁谁不能跨谁RDMA 的 verbs 接口看起来对象很多但真正决定你代码能不能跑对的核心只有四个ibv_context设备上下文、ibv_pd保护域、ibv_mr内存区域、ibv_qp队列对。很多新手翻车的地方在于把ibv_mr注册到错误的ibv_pd上编译能过运行时报Bad address因为硬件在地址翻译阶段发现这个 MR 的 lkey 不属于当前 QP 所在的 PD。源码里通常会把pd作为所有资源的根mr和qp都挂在它下面这不是风格问题是硬件隔离要求。注册 MR 时最容易被忽略的是access标志。只做发送端IBV_ACCESS_LOCAL_WRITE就够要做 RDMA Read/Write必须加IBV_ACCESS_REMOTE_READ或IBV_ACCESS_REMOTE_WRITE。少写一个标志对端rkey校验直接失败返回Remote access error而你在本地日志里什么都看不到这就是典型的“黑匣子”时刻。struct ibv_pd *pd ibv_alloc_pd(ctx); struct ibv_mr *mr ibv_reg_mr(pd, buf, size, IBV_ACCESS_LOCAL_WRITE | IBV_ACCESS_REMOTE_WRITE | IBV_ACCESS_REMOTE_READ); if (!mr) { // errno 通常是 ENOMEM 或 EPERM // ENOMEM 多半是 ulimit -l 太小不是物理内存不够 perror(ibv_reg_mr); }参数说明buf建议用posix_memalign按 4KB 对齐未对齐的缓冲区在部分网卡上会触发隐式内存拷贝带宽直接腰斩size不要超过ulimit -l限制默认 64KB 在现代场景下完全不够源码里一般会提示你改/etc/security/limits.conf里的memlock。2.2 队列对的状态机RESET 到 RTS 之间到底发生了什么QP 状态迁移是 RDMA 编程里最像“玄学”的部分。RESET - INIT - RTR - RTS四步每一步要填的字段不一样填错就卡在ibv_modify_qp返回EINVAL。源码里通常会把这段封装成一个函数但你要理解它为什么这么填。INIT 阶段要设置qp_access_flags和pkey_indexRTR 阶段要填对端的lid、qpn、psn以及本端的rq_psnRTS 阶段才是真正能收发的时候。最容易踩的坑是psn不匹配发送端sq_psn和对端rq_psn必须一致否则第一个包就被丢弃表现为ibv_poll_cq一直返回 0程序卡死。源码里一般会用一个固定的PSN 0x12345做演示生产环境建议随机化避免连接复用时的序列号混淆。struct ibv_qp_attr attr {0}; attr.qp_state IBV_QPS_INIT; attr.pkey_index 0; attr.port_num 1; attr.qp_access_flags IBV_ACCESS_REMOTE_WRITE; ibv_modify_qp(qp, attr, IBV_QP_STATE | IBV_QP_PKEY_INDEX | IBV_QP_PORT | IBV_QP_ACCESS_FLAGS); attr.qp_state IBV_QPS_RTR; attr.path_mtu IBV_MTU_1024; // 必须两端一致 attr.dest_qp_num remote_qpn; attr.rq_psn 0x12345; attr.max_dest_rd_atomic 1; attr.min_rnr_timer 12; ibv_modify_qp(qp, attr, IBV_QP_STATE | IBV_QP_AV | IBV_QP_PATH_MTU | IBV_QP_DEST_QPN | IBV_QP_RQ_PSN | IBV_QP_MAX_DEST_RD_ATOMIC | IBV_QP_MIN_RNR_TIMER);参数说明path_mtu两端必须一致一端 1024 一端 4096 会导致 RTR 阶段直接失败min_rnr_timer是接收端没准备好时发送端等待的时间设太小会频繁触发 RNR NAK设太大则延迟高12 对应约 1ms是常见折中。2.3 完成队列与轮询为什么你的 CPU 跑满了带宽却上不去ibv_poll_cq是忙轮询不睡觉所以一个线程死循环轮询会把一个核跑满。源码里如果只开一个 QP单核轮询通常能跑到 90Gbps 以上但如果你同时跑业务逻辑CPU 就成了瓶颈。常见做法是批量提交、批量收割一次ibv_post_send提交多个 WR然后一次ibv_poll_cq收割多个 CQE减少 doorbell 次数。另一个坑是 CQE 的status字段。很多人只看wc.status IBV_WC_SUCCESS但忽略了vendor_err。当 status 是IBV_WC_REM_ACCESS_ERR时vendor_err里往往藏着对端网卡的具体错误码不看这个就只能靠猜。源码里一般会把wc.vendor_err打印出来这是排查远端错误的关键线索。3. 把源码跑起来编译、建链、打流的最小闭环3.1 编译依赖与 Makefile 里必须检查的三个变量拿到源码第一步不是make而是确认环境。RDMA 用户态依赖libibverbs和librdmacm头文件在rdma/目录下。很多发行版默认不装开发包ibv_create_qp会提示找不到符号。# Debian/Ubuntu 系 apt-get install -y libibverbs-dev librdmacm-dev rdma-core # RHEL/CentOS 系 yum install -y libibverbs-devel librdmacm-devel rdma-core-devel # 确认设备存在 ibv_devices ibv_devinfo -v | grep -E fw_ver|state|rateMakefile 里要检查CFLAGS是否包含-I/usr/include/rdmaLDFLAGS是否链接了-libverbs -lrdmacm。如果编译报undefined reference to ibv_alloc_pd九成是链接顺序问题把-libverbs放在源文件之后。3.2 用 rdma_cm 建链事件回调里最容易漏掉的两个分支源码里如果用了rdma_cm建链过程是事件驱动的。服务端rdma_listen后依次收到RDMA_CM_EVENT_CONNECT_REQUEST、RDMA_CM_EVENT_ESTABLISHED客户端rdma_resolve_addr后收到RDMA_CM_EVENT_ADDR_RESOLVED、RDMA_CM_EVENT_ROUTE_RESOLVED、RDMA_CM_EVENT_ESTABLISHED。最容易漏的是RDMA_CM_EVENT_ADDR_ERROR和RDMA_CM_EVENT_ROUTE_ERROR。这两个分支不处理程序在地址解析失败时会静默卡住既不报错也不退出。源码里一般会在default分支里打印事件类型并退出这是保命写法。switch (event-event) { case RDMA_CM_EVENT_CONNECT_REQUEST: // 服务端新建 qp关联 event-id build_qp(event-id); rdma_accept(event-id, NULL); break; case RDMA_CM_EVENT_ESTABLISHED: // 两端都到这里才能开始 post_send start_io(event-id); break; case RDMA_CM_EVENT_ADDR_ERROR: case RDMA_CM_EVENT_ROUTE_ERROR: // 不处理这两个程序会卡在 resolve 阶段 fprintf(stderr, cm event error: %d\n, event-event); exit(1); default: break; }参数说明rdma_accept的第二个参数可以传rdma_conn_param里面responder_resources和initiator_depth决定了对端能发起的 RDMA Read 数量设 0 会导致对端 Read 失败。3.3 打流验证用 ib_send_bw 和 ib_write_bw 定位瓶颈源码跑通后别急着上业务先用perf工具打流。ib_send_bw测的是 SEND/RECVib_write_bw测的是 RDMA Write。两者带宽差异能帮你判断是 QP 配置问题还是网卡本身限制。# 服务端 ib_write_bw -d mlx5_0 -a -F --report_gbits # 客户端 ib_write_bw -d mlx5_0 -a -F --report_gbits 192.168.1.10如果ib_write_bw能跑满线速而你的源码跑不满问题一定在代码里要么是 MR 没对齐要么是每次只提交一个 WR要么是轮询和提交在同一个线程里互相阻塞。源码里一般会提供一个--batch参数把提交和收割分开这是从“能跑”到“跑满”的关键一步。4. 避坑与排查五个让 RDMA 程序“时好时坏”的经典问题4.1 现象程序偶发卡死poll_cq 永远返回 0原因发送端sq_psn和对端rq_psn不一致或者path_mtu两端不匹配。前者导致第一个包被静默丢弃后者导致 RTR 阶段失败但错误被忽略。解决在ibv_modify_qp后检查返回值不要假设一定成功两端打印psn和mtu做比对。源码里一般会把这两个值写进日志生产环境建议加校验。4.2 现象ibv_reg_mr 返回 NULLerrno 是 ENOMEM原因ulimit -l限制的是锁页内存不是物理内存。默认 64KB注册一个 1MB 的 MR 就失败。解决临时ulimit -l unlimited永久改/etc/security/limits.conf加* soft memlock unlimited和* hard memlock unlimited重启会话生效。注意容器环境里这个限制可能被 cgroup 覆盖需要在容器启动参数里加--ulimit memlock-1。4.3 现象RDMA Write 成功但对端读到的数据是旧的原因RDMA Write 是“写内存”不保证对端 CPU 缓存一致性。如果对端用普通 load 读这块内存可能读到 cache 里的旧值。解决对端在收到完成通知后用ibv_post_recv之外的方式做内存屏障或者改用 SEND/RECV 让对端 CPU 参与。源码里如果做双向通信一般会在 Write 后跟一个 SEND 做通知这是常见做法。4.4 现象多 QP 场景下带宽不升反降原因多个 QP 共享同一个 CQ轮询时锁竞争或者 cacheline bouncing。另一个可能是网卡 PCIe 带宽被多个 QP 的 doorbell 写满。解决每个 QP 独立 CQ或者用ibv_create_cq_ex配合ibv_wc_read_*做批量收割。源码里如果支持多 QP一般会提供--num-qp参数建议从 1 开始逐个加观察带宽拐点。4.5 现象rdma_cm 建链成功但第一次 post_send 返回 ENOMEM原因rdma_conn_param里的responder_resources设太小或者 QP 的max_send_wr在创建时设成了 0。解决创建 QP 时cap.max_send_wr至少设 128cap.max_recv_wr至少 128rdma_conn_param里responder_resources和initiator_depth根据实际 Read 并发数设置一般 4 到 16 之间。5. 从源码到生产把 RDMA 接进现有系统的三个进阶技巧5.1 用事件通道替代忙轮询把 CPU 还给业务忙轮询延迟最低但 CPU 占用 100%。生产环境里如果 QPS 不高可以用ibv_create_comp_channel配合ibv_get_cq_event让内核在 CQE 到达时通知你。代价是延迟从微秒级升到十微秒级但 CPU 占用降到接近 0。struct ibv_comp_channel *ch ibv_create_comp_channel(ctx); struct ibv_cq *cq ibv_create_cq(ctx, 128, NULL, ch, 0); ibv_req_notify_cq(cq, 0); // 等待事件 struct ibv_cq *ev_cq; void *ev_ctx; ibv_get_cq_event(ch, ev_cq, ev_ctx); ibv_ack_cq_events(ev_cq, 1); ibv_req_notify_cq(ev_cq, 0); // 收割 struct ibv_wc wc[16]; int n ibv_poll_cq(ev_cq, 16, wc);参数说明ibv_create_cq的第四个参数是 comp_channel传 NULL 就是纯轮询ibv_req_notify_cq的第二个参数 0 表示下一个 CQE 就通知1 表示 CQ 空时才通知后者能减少通知次数但延迟略高。5.2 内存池化避免每次请求都 reg_mribv_reg_mr是重操作涉及页表锁定和网卡地址翻译表更新。高频场景下每次请求都注册新 MR延迟会从微秒级飙到毫秒级。常见做法是启动时预注册一大块内存用rkey和偏移量做分配源码里一般会实现一个简单的 slab 分配器。方案注册时机延迟适用场景每次请求 reg_mr请求到达时高低频、大块传输预注册内存池启动时低高频、小块传输动态 MR 扩展池不足时中负载波动大5.3 用 rdma_cm 的连接复用降低建链开销短连接场景下每次rdma_connect都要走一遍地址解析和 QP 状态迁移开销在百微秒级。如果业务是请求-响应模式建议复用连接用 SEND/RECV 做请求RDMA Write 做响应避免每次重建 QP。源码里如果支持连接池一般会维护一个id到qp的映射空闲超时才释放。我自己的习惯是任何 RDMA 程序上线前先用ib_write_bw打满线速再跑 24 小时稳定性测试最后才接业务。这套流程帮我省掉了至少三次半夜被叫起来查port_xmit_discards的后悔药。希望帮到你。本文还有配套的精品资源点击获取
企业数字化 ERP 产品动态
相关推荐
海思IVE遮挡检测硬件级实现原理与实战 /* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/9/28 2:09:55
ESP32-CAM工业级图像传输实战:稳、快、省、抗干扰 /* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/9/28 2:09:54
IMU标定工具对比与实战指南:imu_tk、imu_utils、kalibr_allan详解 /* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/9/28 2:09:54
Python搭建QQ聊天机器人极简教程 随着QQ粉丝群管理需求的不断增长,简单的群管工具难以满足复杂的信息响应和自动化需求。现有的自动回复机器人虽然功能强大,但其高昂的年费成为不少用户的顾虑。因此,通过搭建一个自定义机器人来实现自动回复,成为解决这一问题的有效途径。
基于此需求,本文介绍了使用go-c… · 2026/9/28 2:14:08
Python整理百度云盘文件大量重复无用文件 百度云盘容量有限,当文件数量逐渐增多,空间很容易被填满。删除重复文件可以帮助释放大量空间。通过获取云盘缓存目录并使用Python脚本来整理数据,可以高效识别重复文件并避免手动操作的繁琐。
此方法基于 sqlite3 和 pandas 进行数据处理,简单快捷。 文章目录 云盘数据整理… · 2026/9/28 2:14:07
Python实现将图片转化为具有视觉震撼效果的字符图 字符画是一种将图片转化为字符的艺术表现形式,它通过字符的密度和排列来模拟图片的色彩和形状效果。这种技术不仅在视觉上充满了创造力,还在文字处理领域展示了字符的丰富表现力。通过Python,可以将图片转换为字符画,生成具有视觉冲击力的字符艺术。
本文将通过具体步骤和… · 2026/9/28 2:13:48
Python实现将目录下的图片合并成PDF文件 在图像处理和文档管理中,经常需要将一系列图片文件合并为PDF格式,以便于传输、存档和阅读。Python凭借其丰富的第三方库,为图像处理和PDF操作提供了便捷的解决方案。
本文将详细介绍如何通过Python脚本,将目录中的所有图片合并为一个PDF文件,内容包括从基础环境配置到代码… · 2026/9/28 2:13:48
Python实现文件移动到指定文件夹 在编程过程中,经常需要对文件进行整理和管理,将不同类型的文件分类存放在指定文件夹中。Python提供了强大的文件操作模块,使得文件的移动操作变得简单高效。这篇教程将详细讲解如何使用Python实现将文件移动到指定文件夹的功能,帮助理解并掌握文件操作的基本方法和常见应用… · 2026/9/28 2:13:47
【PyQt】PyQT6制作一个Django项目启动器 在现代的桌面和Web应用开发中,Python以其简单高效的特点获得了广泛的应用。通过集成PyQt和Django框架,将桌面应用的便捷操作与Django项目的后端处理相结合,不仅能够提升用户体验,更能显著提高开发的便利性和效率。
本文将聚焦于如何构建一个基于PyQt的Django项目启动器,实… · 2026/9/28 2:13:40
MATLAB雷达信号脉冲压缩仿真:LFM线性调频、匹配滤波与距离分辨率实现 简介:这套Matlab仿真工具完整呈现雷达信号脉冲压缩过程,从线性调频(LFM)信号生成、目标回波仿真到匹配滤波压缩处理均有可运行代码支撑,面向电子信息工程、计算机、数学等专业学生,适用于课程设计、期末大作… · 2026/9/27 0:00:01
汕头网站建设制作厂家避坑指南:5大注意事项救急 汕头网站建设制作厂家避坑指南:5大注意事项救急 改个需求建站公司拖一周,这种憋屈事我见得太多了。 很多汕头老板找本地建站团队,签合同前看着方案挺美,一上线就变脸。 今天不聊虚的,直接拆解找 汕头网站建设制作厂家 时的5个核心 注意事项… · 2026/9/27 0:00:01
多模态虚假新闻检测实战:BERT+ResNet双塔与对比学习 简介:基于PyTorch的多模态虚假新闻检测项目完整代码包,面向自然语言处理与计算机视觉交叉方向的开发者、科研人员及毕业设计选题者,解决社交媒体中文本与图像联合识别虚假新闻的问题。系统以BERT预训练模型提取文本语义特征,以Res… · 2026/9/27 0:00:01
制作网页比较方便的软件怎么选?一文搞懂避坑指南 制作网页比较方便的软件怎么选?一文搞懂避坑指南 很多老板一上来就问:做个网站多少钱?但我反问他:你的域名买了吗?服务器租了吗?他一脸懵。这就是典型的“域名服务器搞不懂”。别急,今天咱们不聊虚的,直接 一文搞懂 那些让你头秃的技术名词。… · 2026/9/28 0:00:06
婚恋网站实战案例:避开3个高价坑,省钱50%还能跑赢流量 婚恋网站实战案例:避开3个高价坑,省钱50%还能跑赢流量 找婚恋网站建站公司,最怕的就是被坑高价。很多同行跟我吐槽,报价单上写得模棱两可,功能栏里全是“高级定制”、“专属UI”,结果落地全是套壳。今天不聊虚的,直接甩几个我经手的 实战案例… · 2026/9/28 0:00:19
济南做网站多少钱:3个案例拆解,防黑源码下载全攻略 济南做网站多少钱:3个案例拆解,防黑源码下载全攻略 上周济南一个做建材的老板找我,脸都绿了。他的官网首页弹出了赌博广告,后台被植入了挖矿脚本。他慌得问我:“网站被黑挂马不知道怎么办?能不能直接找之前的外包公司要源码下载,看看哪里被动了手脚?… · 2026/9/28 0:00:25