引言

在传统网络编程中,开发者在享受TCP/IP通用性的同时,也承受着它带来的性能枷锁。当CPU为了处理网络数据包而忙得不可开交时,一个根本性的问题浮现出来:为什么我们不能让数据直接从发送方的内存"飞"到接收方的内存,而不让CPU在中间当"搬运工"?

RDMA(Remote Direct Memory Access,远程直接内存访问)正是为了解决这个问题而生。本文将围绕RDMA技术的本质、数据在RDMA中的流动过程,以及它到底解决了什么问题三个维度,进行彻底而清晰的分析。


第一章:RDMA技术的本质

1.1 一个核心定义

RDMA的本质是:将网络数据传输从"CPU主导的软件流水线"转变为"硬件主导的内存直达通道"。

在传统网络中,CPU是数据传输的"总指挥"——它负责协议解析、数据拷贝、路由决策等所有环节。而RDMA的核心思想极其简洁有力:让网卡硬件直接读写用户态应用程序的内存,完全绕过操作系统内核。

1.2 实现这一本质的两大基石

基石一:内核旁路(Kernel Bypass)

应用程序通过用户态驱动(如libibverbs)直接与网卡硬件通信,无需通过系统调用进入内核。网卡的寄存器通过PCIe的MMIO(内存映射I/O)方式直接映射到用户态地址空间,应用程序可以像操作普通内存一样操作网卡。

基石二:内存注册与物理地址暴露

应用程序预先向网卡注册一段用户态内存区域(称为"内存注册",Memory Registration),网卡将这段内存的物理地址访问密钥(L_Key/R_Key)保存在内部的MPT(Memory Protection Table,内存保护表)中。此后,网卡可以直接通过物理地址读写这片内存,无需内核映射。

这两大基石的核心价值:数据路径上彻底消灭了内核的存在。


第二章:数据在RDMA中的流动过程

理解了本质之后,我们来看数据在RDMA技术中到底是如何流动的。这里以InfiniBand架构为例,展示完整的物理路径。

2.1 预备阶段:内存注册

在数据传输开始前,应用程序必须先完成内存注册,这是整个RDMA流程的"入场券"。

操作流程:

  1. 应用程序调用ibv_reg_mr(),传入用户态虚拟地址(VA)和长度
  2. 内核驱动将VA翻译成物理页地址(PFN)
  3. 物理地址、长度、权限位被写入网卡硬件的MPT(内容寻址存储器)
  4. 网卡返回L_Key(本地密钥)和R_Key(远程密钥)

此时的物理状态:

用户态内存页(物理地址 PA 0x10000000) 
    ↓ 注册后
网卡MPT中新增条目:{PA: 0x10000000, L_Key: 0x1234, R_Key: 0x5678, 权限: 读写}

本质:应用程序将自己的物理内存"钥匙"交给了网卡硬件。

2.2 发送方向的数据流动

场景:应用程序A要向远程服务器B发送数据。

Step 1:数据填充(用户态完成)

应用程序直接将数据写入已注册的内存区域(VA 0x7f1234560000)
该VA对应的物理地址为 PA 0x10000000

Step 2:下发发送指令(无系统调用)

应用程序调用 ibv_post_send()
    ↓(用户态驱动,无系统调用)
向网卡的SQ(Send Queue,发送队列)写入WQE(Work Queue Element)

WQE(工作队列元素)的结构:

struct wqe {
    uint64_t local_va;     // 0x7f1234560000(本地虚拟地址)
    uint32_t length;       // 4096字节
    uint32_t lkey;         // 0x1234(本地密钥)
    uint64_t remote_va;    // 目标服务器已注册内存的虚拟地址
    uint32_t rkey;         // 目标服务器的R_Key
};

注意:SQ通过PCIe MMIO映射到用户态,写入WQE是直接写硬件寄存器,不触发系统调用

Step 3:网卡硬件拉取数据(DMA Read)

网卡硬件轮询SQ,取到WQE
    ↓ 验证L_Key (0x1234)
查MPT表:L_Key 0x1234 → PA 0x10000000
    ↓ DMA引擎
网卡直接从物理地址 PA 0x10000000 读取4096字节数据

Step 4:硬件协议封装(完全硬件执行)
网卡硬件将原始数据封装成InfiniBand协议包,整个过程不涉及CPU:

[原始数据] 
    ↓ 传输层硬件(BTH:Base Transport Header,含PSN序列号)
    ↓ 网络层硬件(GRH:Global Route Header,类似IP)
    ↓ 链路层硬件(LRH:Local Route Header + CRC校验)
[完整的InfiniBand数据帧]

Step 5:发送到物理链路

网卡SerDes(串行解串器)将数据转换为高速串行信号
    ↓ 通过光纤/铜缆
进入InfiniBand交换机网络

发送路径的数据流动总结

用户态内存(PA) → PCIe总线 → 网卡DMA读取 → 网卡硬件封装 → 物理链路
(全程无CPU参与,无系统调用,无内存拷贝)

2.3 接收方向的数据流动

场景:远程服务器B发来一个InfiniBand数据包,目标是本机的某块已注册内存。

Step 1:物理层接收与链路层验证(硬件执行)

数据包从物理链路进入网卡
    ↓ 硬件解析LRH,确认是本机端口
    ↓ 硬件校验CRC和VCRC(变体CRC)
    ● 如果CRC出错:硬件自动触发链路层重传请求
    ● 如果通过:进入下一步

Step 2:传输层处理(硬件执行)

硬件解析GRH → 确定目标QP(Queue Pair,队列对)
    ↓ 解析BTH → 读取PSN(包序列号)
    ● 硬件检查PSN连续性
    ● 如果不连续:硬件自动发送NAK,等待重传
    ● 如果连续:进入下一步

Step 3:目标内存查找(硬件查表)

数据包中包含:远程R_Key + 远程VA
    ↓ 网卡硬件查MPT表
R_Key + VA → 映射到本机物理地址 PA 0x20000000
(这张MPT表在内存注册阶段已预先配置好)

Step 4:DMA写入(数据直达用户态内存)

网卡DMA引擎将数据净荷
    ↓ 直接写入物理地址 PA 0x20000000
这片物理地址对应的是应用程序已注册的用户态内存

Step 5:完成通知(轻量级)

网卡在CQ(Completion Queue,完成队列)中生成一个CQE
    ↓ 应用程序可以选择:
    ● 轮询模式(Polling):用户态直接读取CQ中的CQE
    ● 事件模式:网卡发出轻量级中断(MSI-X中断)

接收路径的数据流动总结

物理链路 → 网卡硬件解析 → 网卡DMA写入用户态内存(PA)
(全程无CPU参与,无内核协议栈,无内存拷贝)

2.4 数据流动的完整路径对比

为了让你更清晰地看到RDMA与传统网络的本质区别,这里用一个表格来对比两种路径:

数据流动环节 传统TCP/IP RDMA (InfiniBand)
发送方数据源头 用户态缓冲区 已注册的用户态物理内存
第一次网卡访问 系统调用拷贝到内核sk_buff DMA直接读取用户态物理地址
协议封装执行者 CPU软中断(TCP/IP栈) 网卡硬件流水线
接收方数据终点 内核sk_buff→Socket队列 直接DMA写入用户态物理内存
数据是否发生拷贝 是(内核→用户态拷贝) 否(零拷贝)
CPU在每个数据包上的参与度 高(校验、重排、窗口、ACK) 几乎为零(仅处理完成通知)

第三章:RDMA解决了什么问题

理解了RDMA的本质和数据流动方式后,我们来回答一个最关键的问题:RDMA到底解决了传统网络中的哪些根本性痛点?

3.1 问题一:内存拷贝导致的CPU开销

传统网络的困境:

在TCP/IP收包流程中,数据至少经历两次拷贝:

  1. 网卡DMA写入内核缓冲区(硬件拷贝,不消耗CPU)
  2. skb_copy_datagram_msg将数据从内核缓冲区拷贝到用户缓冲区(CPU拷贝)

第二次拷贝是纯CPU操作,每1GB数据的拷贝大约消耗0.51个CPU核心的运算能力。在100Gb/s的网络下,仅拷贝开销就需要消耗510个CPU核心。

RDMA的解决方案:

通过内存注册,网卡直接读写用户态物理内存,完全消除了内核到用户态的拷贝。数据从网卡进入内存的那一刻,就已经在用户态地址空间中。

量化价值

  • 单机CPU利用率:传统网络在100Gb/s下需占用60%+ CPU → RDMA仅需5%以内
  • 数据延迟:传统网络微秒级延迟(30-50μs) → RDMA亚微秒级延迟(1-3μs)

3.2 问题二:操作系统内核协议栈的处理延迟

传统网络的困境:

Linux内核的TCP/IP协议栈是一个软件实现的复杂状态机。每个数据包都要经历:

  1. 链路层MAC解析
  2. IP层路由查找、分片重组
  3. TCP层序列号检查、重排序、滑动窗口更新、ACK生成

这些全部由CPU在软中断上下文中执行。对于小包(如64字节),协议栈开销甚至超过了数据传输本身的时间。

RDMA的解决方案:

InfiniBand将整个传输层的可靠性机制(序列号、确认、重传、窗口、乱序重组)完全卸载到网卡硬件。网卡内部有专用的处理器和逻辑电路,在一个时钟周期内完成原本需要数百条CPU指令的工作。

可靠性机制的硬件实现对比

传统TCP机制 CPU执行方式 RDMA硬件实现方式
序列号与确认 软中断计算ack_seq 硬件维护PSN,自动回复ACK/NACK
超时重传 内核定时器,软中断触发 硬件计时器,自动重传
滑动窗口 CPU更新窗口值 链路层基于信用的流控(硬件)
校验和 CPU累加计算 硬件计算CRC(覆盖头部和数据)
乱序重组 sk_out_of_order_queue链表处理 硬件重排序缓冲区,按PSN排序交付

3.3 问题三:系统调用导致的上下文切换

传统网络的困境:

每一次sendrecv系统调用都会触发:

  1. 用户态(Ring 3)→ 内核态(Ring 0)的切换
  2. CPU缓存(TLB、L1/L2 Cache)的部分失效
  3. 系统调用本身的开销(约100ns~1μs)

对于小包高频场景(如金融交易、数据库事务),系统调用开销成为主要瓶颈。

RDMA的解决方案:

通过用户态驱动(如libibverbs),应用程序可以直接操作网卡硬件寄存器(通过MMIO映射),下发WQE和读取CQE都不经过系统调用。数据路径上彻底消除了用户态/内核态的切换

量化价值

  • 单次操作延迟:系统调用~1μs → RDMA用户态操作~0.1μs
  • 每秒操作数(IOPS):传统网络~50万 → RDMA~300万+

3.4 综合对比:RDMA解决了什么

性能维度 传统TCP/IP RDMA (InfiniBand) RDMA带来的提升
端到端延迟 20-50μs 1-3μs 10-50倍
CPU利用率(100Gb/s) 60%+ <5% 释放50%+ CPU
IOPS(小包) ~50万 ~300万+ 6倍+
内存拷贝次数 2次+ 0次 消除拷贝
系统调用次数 每个包1-2次 0次(完全旁路) 消除上下文切换

第四章:总结

RDMA技术的本质是将数据路径上的"CPU软件接力"替换为"硬件直达专线"。它通过两个核心机制实现这一目标:

  1. 内存注册:让网卡直接持有用户态内存的物理地址,使数据无需经过内核中转
  2. 内核旁路:通过用户态驱动和MMIO映射,让应用程序直接与网卡硬件通信

在数据流动层面,RDMA实现了从"用户态内存→网卡→网络→网卡→用户态内存"的纯硬件路径,中间没有任何CPU参与、没有任何系统调用、没有任何内存拷贝。

在解决的问题层面,RDMA彻底消除了传统网络的三重枷锁

  • 内存拷贝 → 零拷贝技术,释放CPU
  • 协议栈开销 → 硬件卸载,降低延迟
  • 系统调用 → 内核旁路,提升吞吐

一句话总结:RDMA让CPU从"数据搬运工"回归"计算引擎",实现了网络传输从"软件定义"到"硬件定义"的革命性转变。

Logo

openEuler 是由开放原子开源基金会孵化的全场景开源操作系统项目,面向数字基础设施四大核心场景(服务器、云计算、边缘计算、嵌入式),全面支持 ARM、x86、RISC-V、loongArch、PowerPC、SW-64 等多样性计算架构

更多推荐