在 RDMA 系统中,一个非常典型的通信模式是:

RDMA Write
    ↓
RDMA Write
    ↓
RDMA Write-with-Immediate
    ↓
Remote CQE(Remote CQE 不会再发回 Server A)

它的设计思想非常简单:

先把数据写到远端内存,再通过 Write-with-Immediate 告诉远端:“数据已经准备好了,可以用了。”

例如:

Sender                                      Receiver
  │                                             │
  │ RDMA Write: 4 MB Tensor                     │
  ├────────────────────────────────────────────>│ Remote Buffer
  │                                             │
  │ Write-with-Immediate: READY                 │
  ├────────────────────────────────────────────>│
  │                                             │
  │                                      Generate CQE
  │                                             │
  │                                      Application wakes up
  │                                             │
  │                                      Read 4 MB Tensor

这个机制看起来简单,但对传统 RNIC 来说,实际上提出了一个非常重要的要求:

RNIC 必须保证:在远端应用收到 Write-with-Immediate 的 Completion Notification 之前,前面的 RDMA Write 数据已经按照要求到达并对远端可见。

否则就会出现严重的数据一致性问题。


1. 为什么需要 Write-with-Immediate

普通 RDMA Write 的特点是:

Sender
   │
   │ RDMA Write
   ▼
Remote Memory

数据可以直接写进远端内存。

但有一个问题:

远端 CPU 怎么知道这次 Write 已经完成?

普通 RDMA Write 通常不会主动给远端应用生成一个 Receive Completion。

因此可能出现:

Remote Buffer

什么时候更新完成?

CPU:不知道

一种方式是让 CPU 不停 Poll:

while (buffer->flag != READY) {
    // spin
}

但这样效率不高。

因此 RDMA 提供了:

RDMA Write with Immediate

它同时完成两件事情:

                Write-with-Immediate

Sender RNIC
      │
      ├─────────────── Data ──────────────→ Remote Memory
      │
      └──────── Immediate Data ───────────→ Remote CQ

也就是说:

  1. 写入远端 Memory;

  2. 在远端产生 Completion;

  3. CQE 中携带一个 32-bit Immediate Data。

例如:

Immediate = 0x00000001

可以解释为:

Tensor #1 is ready

2. 为什么常见的是:

Write
  ↓
Write
  ↓
Write-with-Immediate

而不是每次都使用 Write-with-Immediate?

假设需要传输一个 4 MB Tensor。

可以先:

WQE 1:
RDMA WRITE
Address = Buffer + 0 MB
Length  = 1 MB

WQE 2:
RDMA WRITE
Address = Buffer + 1 MB
Length  = 1 MB

WQE 3:
RDMA WRITE
Address = Buffer + 2 MB
Length  = 1 MB

WQE 4:
RDMA WRITE
Address = Buffer + 3 MB
Length  = 1 MB

最后:

WQE 5:
RDMA WRITE WITH IMM
Immediate = READY

于是接收端只需要收到一次通知:

CQE:
Immediate = READY

就知道:

前面的 4 MB 数据全部完成

因此 Write-with-Immediate 经常被当成一种:

Doorbell / Notification Mechanism

即:

Data
Data
Data
Data
 ↓
Doorbell

3. 真正困难的问题:不能让“通知”跑到“数据”前面

假设 Sender 发:

WQE 1 = RDMA Write(DATA)

WQE 2 = Write-with-Immediate(READY)

WQE(Work Queue Entry)软件交给 RNIC 的一张“工作指令单”

从应用程序角度看:

DATA
 ↓
READY

但底层实际上有很多异步组件:

Application
     │
     ▼
Send Queue
     │
     ▼
RNIC Pipeline
     │
     ▼
Network
     │
     ▼
Remote RNIC
     │
     ▼
PCIe
     │
     ▼
Host Memory

于是存在一个危险场景。

比如:

Packet carrying DATA
        ↓
Remote RNIC
        ↓
PCIe Write
        ↓
Host Memory

与此同时:

Immediate packet
        ↓
Remote RNIC
        ↓
CQE

如果 RNIC 不提供严格的排序保证,就可能出现:

Time ─────────────────────────────>

Immediate arrives
       │
       ▼
CQE generated
       │
       ▼
CPU reads buffer

                    DATA DMA still in progress
                              ↓
                          Memory updated

于是 CPU 会读到:

Old Data

而不是:

New Data

这显然是不允许的。

所以传统 RNIC 必须实现:

Data-before-Notification ordering


4. 第一层保证:Send Queue WQE Ordering

假设:

SQ(在 RDMA 里,SQ 和 RQ 是一个 QP(Queue Pair)里的两条工作队列)
# 一个 QP = 一条发送队列 SQ + 一条接收队列 RQ,再加上一套通信状态。

WQE #100
RDMA Write

WQE #101
RDMA Write

WQE #102
Write-with-Immediate

对于同一个可靠连接 QP,例如:

RC QP

RNIC 必须按照 WQE 的顺序处理。

逻辑关系为:

WQE 100
    ↓
WQE 101
    ↓
WQE 102

不能变成:

WQE 102
    ↓
WQE 100
    ↓
WQE 101 

因此 RNIC 内部需要维护:

QP Context
    │
    ├── SQ Producer Index
    ├── SQ Consumer Index
    ├── Current WQE
    ├── PSN
    ├── Outstanding Requests
    └── Completion State

这些状态通常就需要占用 RNIC 的片上 SRAM。


5. 第二层保证:Packet Sequence Number

一个大型 RDMA Write 不会只变成一个网络包。

例如:

1 MB RDMA Write

可能被拆成:

Packet PSN 1000
Packet PSN 1001
Packet PSN 1002
...
Packet PSN 1200

然后:

Write-with-Immediate

可能继续使用:

PSN 1201

形成:

PSN:

1000
1001
1002
...
1200
1201  ← Write-with-Immediate

因此 Receiver RNIC 可以知道:

如果 1201 到了
但是 1199 没到

那么不能直接认为前面的数据已经完成

对于传统 RC Transport:

Expected PSN = 1199

收到:

1201

说明:

存在 Gap

需要进行:

NAK
Retransmission
Recovery 

因此 PSN 本质上提供了一套:

Transport-level ordering


6. 第三层保证:Remote RNIC 的 WQE/Packet 状态

真正复杂的是 Remote RNIC。

假设收到:

PSN 100
DATA

PSN 101
DATA

PSN 102
WRITE_WITH_IMM

Remote RNIC 不能简单地:

收到 102
   ↓
马上生成 CQE

而必须确保:

PSN 100
   ↓
DMA complete / visibility requirement satisfied

PSN 101
   ↓
DMA complete / visibility requirement satisfied

PSN 102
   ↓
Write-with-Imm completion
   ↓
CQE

因此 RX RNIC 内部需要维护很多状态:

RC QP Context

Expected PSN
Last ACKed PSN
Current Message State
DMA State
Receive WQE State
Immediate State
CQ State

所以:

Ordering

并不是“网络天然就有”。

而是 RNIC ASIC 里大量状态机共同实现出来的。


7. 第四层:PCIe Ordering

这里开始进入真正的硬件问题。

Remote RNIC 收到数据之后,还要通过:

PCIe DMA

把数据写进 Host DRAM。

例如:

RNIC
 │
 │ PCIe Memory Write
 ▼
Host DRAM

所以完整链路其实是:

Network packet
      ↓
RNIC RX
      ↓
PCIe DMA
      ↓
Memory Controller
      ↓
DRAM

与此同时,RNIC 还可能:

Generate CQE
       ↓
PCIe Write
       ↓
Completion Queue

所以存在两类 PCIe Write:

A:
Data DMA
→ Remote Buffer

B:
CQE DMA
→ Completion Queue

关键要求是:

B 不能在语义上超越 A。

否则:

CQE visible

但

Data not yet visible

应用就会读到旧数据。

因此 RNIC 必须利用:

  • PCIe ordering rules

  • DMA engine ordering

  • internal pipeline barriers

  • completion scheduling

确保:

DATA visibility
      ↓
CQE visibility

8. 所以真正的 Write → Write-with-Imm 链条是

简化来看:

Sender Application
      │
      ▼
┌─────────────────┐
│ Sender RNIC     │
│                 │
│ WQE 1 WRITE     │
│ WQE 2 WRITE_IMM │
└────────┬────────┘
         │
         │ ordered packets
         ▼
┌─────────────────┐
│ Network         │
│                 │
│ PSN 100         │
│ PSN 101         │
│ PSN 102         │
└────────┬────────┘
         │
         ▼
┌─────────────────────────┐
│ Receiver RNIC           │
│                         │
│ PSN checking            │
│ Reassembly              │
│ DMA scheduling          │
│ Ordering state          │
└──────────┬──────────────┘
           │
           │ PCIe DMA
           ▼
      Remote Memory
           │
           │ data visible
           ▼
┌─────────────────────────┐
│ Receiver RNIC           │
│                         │
│ Generate CQE            │
│ Immediate = READY       │
└──────────┬──────────────┘
           │
           ▼
      Completion Queue
           │
           ▼
      Remote CPU
           │
           ▼
       Read Data

最核心的顺序是:

Data Transfer
      ↓
Data Visibility
      ↓
Immediate Notification
      ↓
Application Access

9. 为什么这个机制特别消耗 RNIC SRAM

这和现代 AI RNIC 论文讨论的:

hardware resource constraints

直接相关。

为了维护这种严格的可靠、有序传输,传统 RNIC 对每个 QP 都可能保存:

QP Context
───────────────────

SQ state

RQ state

Expected PSN

Send PSN

ACK state

Retry state

Timeout state

Outstanding WQEs

DMA state

Completion state

RDMA Read state

Atomic state

Write-with-Imm state

假设一个 QP Context 需要:

几百 Byte

如果支持:

1,000,000 QPs

理论状态规模就可能达到:

数百 MB

显然不能全部放在最昂贵的高速 SRAM 中。

因此传统 RNIC 经常需要复杂的:

On-chip SRAM Cache
        +
Host DRAM Context

层级。


10. 为什么 AI Cloud 给了 RNIC 新的优化机会

传统 RNIC 设计目标是:

General-purpose RDMA

因此必须考虑很多场景:

RDMA Write
RDMA Write-with-Imm
RDMA Read
Send
Receive
Atomic
Large number of QPs
Reliable Transport
Ordering
Retry
...

但是 AI 网络的行为高度规律。

例如 AI Collective 可能大量使用:

RDMA Write
Send/Recv
Write-with-Immediate

而某些复杂 Verbs 很少使用。

因此论文作者会问:

能不能减少:

Rare RDMA Verbs
Complex connection state
Some legacy semantics

            ↓

释放硬件资源

            ↓

增加:

Per-packet spraying
Credit state
Path state
Reordering
Congestion control

这就是很多新型 AI RNIC 的设计哲学:

传统 RNIC:

更多“通用性”

        ↓

AI RNIC:

牺牲部分极少使用的通用能力

        ↓

换取更多:

Multipath
Congestion Control
Credit
Reordering

11. Write-with-Immediate 和 Send/Receive 有什么区别?

这也是很容易混淆的一点。

SEND

Sender Buffer
      │
      │ SEND
      ▼
Receiver RNIC
      │
      ▼
Receive Buffer

Receiver 必须提前:

Post Receive WQE

RDMA Write

Sender
   │
   │ WRITE
   ▼
Receiver Memory

Sender 直接指定:

Remote Address
rkey

远端 CPU 不直接参与。


RDMA Write-with-Immediate

可以理解成:

RDMA Write
     +
Remote Notification

即:

Data
  ↓
Remote Memory

同时

Immediate
  ↓
Remote CQE

因此它特别适合:

Data Plane
    +
Doorbell

这种设计。


12. 一个典型 AI / Storage 使用方式

例如 Sender 要把 Tensor 写给 Receiver:

Tensor = 64 MB

可以:

WR 1
WRITE 16 MB

WR 2
WRITE 16 MB

WR 3
WRITE 16 MB

WR 4
WRITE 16 MB

WR 5
WRITE_WITH_IMM
IMM = Tensor_ID_123_READY

Receiver 只需要 Poll CQ:

poll_cq();

if (wc.opcode == RDMA_WRITE_WITH_IMM &&
    wc.imm_data == TENSOR_123_READY) {

    process_tensor(buffer);
}

而无需:

不停检查 64 MB Tensor 是否到齐

13. 一个非常重要的边界:同一个 QP

这种 ordering 最容易保证的是:

Same RC QP

例如:

QP 7:

WRITE A
   ↓
WRITE B
   ↓
WRITE_WITH_IMM

存在明确的顺序关系。

但如果:

QP1:
WRITE DATA

QP2:
WRITE_WITH_IMM

那么:

QP1 ─────────────→
QP2 ───────→

两个 QP 在 RNIC 内部可能走不同:

Queue
Scheduler
Pipeline
Path

此时不能简单依赖:

程序提交顺序

推导:

远端可见顺序

因此:

需要 ordering guarantee 时,应明确通信是否在同一个 QP/ordering domain 中。


14. Fence 也不要和这个问题混淆

RDMA 中还有:

IBV_SEND_FENCE

但它不是简单地说:

“所有 WRITE 后面都必须加 Fence。”

Fence 主要用于某些前序操作,例如:

RDMA Read
Atomic

存在返回数据/依赖关系时,约束后续 Work Request 的执行。

对于普通:

RDMA Write
    ↓
RDMA Write-with-Immediate

在同一 RC QP 内,基本的发送顺序和可靠传输语义本身就非常关键。

所以不要把:

Write → Write-with-Imm ordering

简单解释成:

靠 Fence 实现

两者不是一回事。


15. 为什么 Per-Packet Spraying 会让这件事情变复杂?

传统 RNIC 假设:

一个 QP
   ↓
一条 ECMP Path

所以:

P1 → Path A
P2 → Path A
P3 → Path A
P4 → Path A

网络中的 packet 顺序相对容易维护。

但如果使用:

Per-packet spraying

可能:

P1 → Path A ────────────────→

P2 → Path B ────────→

P3 → Path C ──────────→

Receiver 实际收到:

P2
P3
P1

这就直接打破了传统 RNIC 很重要的:

in-order packet arrival assumption

而传统 Write → Write-with-Immediate 又要求:

DATA
  ↓
READY

因此现代支持 packet spraying 的 RNIC 必须额外增加:

Out-of-order handling
        ↓
Packet tracking
        ↓
Selective retransmission
        ↓
Reordering
        ↓
Completion ordering

才能最终保证:

即便 Packet Arrival 是:

P3 P1 P2 P5 P4

应用看到的语义依然是:

WRITE
 ↓
WRITE
 ↓
WRITE_WITH_IMM
 ↓
CQE

这就是为什么:

Per-packet spraying 本身不难,“既 spraying 又保持 RDMA 原有语义”才是真正难的地方。


16. 一张图总结传统 RNIC 的工作

Application
    │
    │
    │  WRITE
    │  WRITE
    │  WRITE_WITH_IMM
    ▼
┌────────────────────────────┐
│         Sender RNIC        │
│                            │
│ SQ Ordering                │
│ WQE State                  │
│ PSN Allocation             │
│ Retry State                │
└──────────────┬─────────────┘
               │
               ▼
             Network
               │
               ▼
┌────────────────────────────┐
│        Receiver RNIC       │
│                            │
│ PSN Checking               │
│ In-order Processing        │
│ DMA Ordering               │
│ Write Visibility           │
│ CQE Ordering               │
└──────────────┬─────────────┘
               │
        ┌──────┴──────┐
        │             │
        ▼             ▼
   Remote DRAM       CQE
        │             │
        └──────┬──────┘
               │
               ▼
          Application

保证:

DATA visible
     ↓
READY notification

总结

传统 RNIC 中:

RDMA Write
     ↓
RDMA Write-with-Immediate

本质上是一种非常常见的:

Data + Doorbell

通信模型。

为了保证:

“收到 Doorbell”
        =
“前面的数据已经可以安全使用”

RNIC 必须维护:

WQE Ordering
      +
PSN Ordering
      +
Reliable Delivery
      +
DMA Ordering
      +
Memory Visibility
      +
Completion Ordering

因此传统 RNIC 需要大量:

QP state
Packet state
DMA state
Retry state
Completion state

而这些状态最终会消耗宝贵的:

On-chip SRAM

这也解释了为什么现代 AI RNIC 论文如此强调:

如何在保持传统 RDMA 语义的同时,引入 per-packet spraying、credit-based congestion control 和 out-of-order transport,而又不能让 RNIC SRAM 与状态复杂度爆炸。