4、RDMA基础概念:IB与RoCE的区别、QP、MR、CQ
好,咱们进入RDMA的核心概念部分。说实话,很多搞AI训练的同学一开始接触RDMA,都会被IB、RoCE这些缩写搞晕。我当年第一次调分布式训练时,也踩过不少坑。今天咱们就把这些基础概念掰开揉碎,讲清楚。
4.1 IB(InfiniBand)与RoCE(RDMA over Converged Ethernet)的区别
先说说这两个东西的本质区别。IB和RoCE,说白了就是RDMA的两种实现方式。IB是专用网络,RoCE是跑在以太网上的。
核心区别一句话:IB是专用硬件,RoCE是复用现有以太网。
IB(InfiniBand)
IB从设计之初就是为了高性能计算。它有自己的交换机、网卡、线缆,甚至有自己的协议栈。我最早接触IB是在一个超算项目里,当时觉得这玩意儿真贵,但性能也确实猛。
- 优点:延迟极低(1-2微秒),带宽高(200Gbps起步),有硬件级的流控和拥塞控制
- 缺点:贵,贵,贵。而且需要专门的IB交换机,不能和普通以太网混用
- 适用场景:大规模AI训练集群、HPC超算中心
RoCE(RDMA over Converged Ethernet)
RoCE分v1和v2两个版本。现在主流是RoCE v2,它把RDMA封装在UDP/IP里,可以跑在标准以太网上。嗯,这里要注意,RoCE对网络质量要求很高,丢包会严重影响性能。
- 优点:成本低,复用现有以太网基础设施,部署灵活
- 缺点:需要PFC(优先级流控)等机制保证无损,配置复杂
- 适用场景:中小规模集群、预算有限的项目
| 对比项 | IB | RoCE v2 |
|---|---|---|
| 延迟 | 1-2微秒 | 3-5微秒 |
| 带宽 | 200-400Gbps | 100-200Gbps |
| 成本 | 高 | 中 |
| 兼容性 | 专用 | 兼容以太网 |
| 部署复杂度 | 中 | 高(需调优PFC) |
我的建议:如果预算充足,AI训练集群首选IB。如果预算有限,RoCE v2也能用,但一定要做好网络调优。我曾经在一个RoCE集群上因为PFC配置不当,导致训练速度还不如TCP,折腾了两天才找到原因。
4.2 QP(Queue Pair)—— RDMA通信的基本单元
QP是RDMA通信的核心概念。你想想看,传统网络通信是socket,RDMA里就是QP。每个QP包含两个队列:发送队列(SQ)和接收队列(RQ)。
为什么叫Queue Pair?因为发送和接收是成对出现的。我刚开始学的时候,总以为一个QP只能和一个对端通信。其实不是,一个QP可以和一个对端建立连接,但你可以创建多个QP来和多个对端通信。
QP的状态机:RESET → INIT → RTR(Ready to Receive)→ RTS(Ready to Send)→ 错误/关闭
在实际的AI训练中,每个GPU通常对应一个QP。比如你有8张卡,每张卡都要和其他7张卡通信,那就需要创建7个QP。嗯,这里有个小技巧:可以用一个QP池来管理,避免频繁创建销毁。
// 创建QP的伪代码示例
struct ibv_qp_init_attr qp_attr;
memset(&qp_attr, 0, sizeof(qp_attr));
qp_attr.send_cq = cq; // 发送完成队列
qp_attr.recv_cq = cq; // 接收完成队列
qp_attr.qp_type = IBV_QPT_RC; // 可靠连接类型
qp_attr.cap.max_send_wr = 16; // 最大发送WR数
qp_attr.cap.max_recv_wr = 16; // 最大接收WR数
struct ibv_qp *qp = ibv_create_qp(pd, &qp_attr);
if (!qp) {
// 处理错误
}
注意:QP的数量不是越多越好。每个QP都会占用内存资源,我见过有人为了追求并发创建了上千个QP,结果内存爆了。一般建议每个GPU对端创建1-2个QP就够了。
4.3 MR(Memory Region)—— 内存注册
MR是RDMA能直接访问内存的关键。传统网络通信,数据要从用户态拷贝到内核态。RDMA不一样,它直接操作注册过的内存区域。
说白了,MR就是告诉网卡:「这块内存你可以直接读写,不用经过CPU」。我刚开始做RDMA开发时,最常犯的错误就是忘了注册内存,结果网卡访问不到数据,报各种奇怪的错误。
MR的关键属性:
- 虚拟地址(virt_addr)
- 长度(length)
- LKey(本地访问密钥)
- RKey(远程访问密钥)
注册MR的流程很简单:
// 注册内存区域
struct ibv_mr *mr = ibv_reg_mr(
pd, // 保护域
buffer, // 内存地址
size, // 大小
IBV_ACCESS_LOCAL_WRITE | // 本地写权限
IBV_ACCESS_REMOTE_WRITE | // 远程写权限
IBV_ACCESS_REMOTE_READ // 远程读权限
);
if (!mr) {
// 注册失败,检查权限和内存对齐
}
避坑指南:我曾经因为内存没有对齐到页边界,导致MR注册失败。记住,注册MR的内存最好用posix_memalign分配,对齐到4KB或更大的页。另外,MR注册后不要随意释放内存,否则网卡还在访问,会触发段错误。
4.4 CQ(Completion Queue)—— 完成通知机制
CQ是RDMA的「消息中心」。每次RDMA操作完成后,网卡会把完成状态放到CQ里。应用程序通过轮询或事件通知来获取这些完成信息。
你想想看,如果没有CQ,你怎么知道数据发送完了?接收方什么时候收到数据了?CQ就是干这个的。
CQ的工作模式:
- 轮询模式(Polling):CPU不断检查CQ,适合延迟敏感场景
- 事件模式(Event):有完成事件时通知CPU,适合CPU资源紧张场景
在AI训练中,我一般用轮询模式。因为训练时GPU计算和通信是流水线并行的,CPU闲着也是闲着,不如让它轮询CQ,减少延迟。
// 轮询CQ的典型代码
struct ibv_wc wc[8]; // 一次可以取多个完成事件
int ne = ibv_poll_cq(cq, 8, wc);
for (int i = 0; i < ne; i++) {
if (wc[i].status != IBV_WC_SUCCESS) {
// 处理错误
printf("CQ error: %s\n", ibv_wc_status_str(wc[i].status));
continue;
}
// 处理完成事件
switch (wc[i].opcode) {
case IBV_WC_SEND:
// 发送完成
break;
case IBV_WC_RECV:
// 接收完成
break;
case IBV_WC_RDMA_WRITE:
// RDMA写完成
break;
}
}
性能陷阱:CQ的大小要设置合理。太小会导致完成事件丢失,太大会浪费内存。我一般设置为QP数量的2-4倍。另外,轮询CQ时不要用while(1)死循环,最好加个超时机制,防止CPU空转。
4.5 四个概念的关系
最后,咱们捋一捋这四个概念的关系。QP是通信通道,MR是数据缓冲区,CQ是通知机制。它们配合起来才能完成一次RDMA通信。
举个例子:你要把GPU上的梯度数据发送到另一台机器。
- 先把梯度数据所在的内存注册成MR
- 创建一个QP连接到对端
- 通过QP发起RDMA写操作,指定MR的地址和长度
- 操作完成后,CQ里会有一个完成事件
- 你从CQ里取出事件,确认数据发送成功
我的经验:刚开始做RDMA开发时,建议先跑通一个简单的ping-pong程序。就是A发数据给B,B收到后再发回来。这个过程中你会深刻理解QP、MR、CQ是怎么配合的。我曾经用这个方式帮团队排查出一个MR权限配置错误的问题,省了两天调试时间。
好了,这一章的基础概念就讲到这里。下一章咱们会深入RDMA的通信模式,包括Send/Recv和RDMA Read/Write的区别,以及如何在AI训练中选型。