RDMA와 RoCE v2 완전정리: 커널을 건너뛰는 네트워크는 어떻게 동작하는가
GPU 클러스터를 다루기 시작하면 반드시 마주치는 단어가 RDMA다. NCCL(NVIDIA Collective Communications Library) 로그에 IB가 찍히고, 스토리지 벤더는 NVMe-oF를 말하고, 네트워크 팀은 PFC 얘기를 꺼낸다. 이 글은 그 조각들이 어떻게 하나의 그림으로 이어지는지를, 용어 하나 빼놓지 않고 정리한 기록이다.
순서는 이렇게 잡았다. 먼저 RDMA가 무엇인지 보고, 어떤 객체들로 동작하는지 뜯어본 다음, RoCE가 그중 어떤 구현인지 위치를 잡는다. 이어서 왜 설정이 까다로운지를 짚고, 마지막으로 서버와 스위치에서 실제로 뭘 만지는지로 넘어간다.
약어가 많이 나오는 분야다. 모르는 약어가 보이면 맨 끝의 약어 사전을 보면 된다. 본문에 나온 것은 전부 거기 정리해두었다.
RDMA(Remote Direct Memory Access) 는 한 서버의 메모리에서 다른 서버의 메모리로, CPU와 OS 커널을 거치지 않고 네트워크 카드가 직접 데이터를 옮기는 기술이다.
flowchart TD
subgraph S["송신 서버"]
A1["애플리케이션 버퍼"]
A2["소켓 send 시스템콜<br/>유저→커널 컨텍스트 스위치"]
A3["커널 소켓 버퍼<br/>메모리 복사 1회"]
A4["TCP/IP 스택<br/>세그먼트 분할·체크섬·혼잡제어"]
A5["드라이버 → NIC 링 버퍼<br/>DMA"]
A1 --> A2 --> A3 --> A4 --> A5
end
A5 -->|"이더넷 프레임"| B1
subgraph R["수신 서버"]
B1["NIC 수신 → 인터럽트 발생"]
B2["softirq / NAPI 폴링"]
B3["TCP/IP 스택 처리<br/>재조립·순서정렬·ACK"]
B4["커널 소켓 버퍼"]
B5["recv 시스템콜<br/>메모리 복사 1회 + 컨텍스트 스위치"]
B6["애플리케이션 버퍼"]
B1 --> B2 --> B3 --> B4 --> B5 --> B6
end
비용이 발생하는 지점이 셋이다.
| 비용 | 내용 |
|---|---|
| 메모리 복사 | 유저 버퍼 ↔ 커널 버퍼 사이 복사. 100Gbps를 채우려면 초당 12.5GB를 복사해야 한다 |
| 컨텍스트 스위치 | 시스템콜마다 유저/커널 모드 전환. 캐시와 TLB가 오염된다 |
| 프로토콜 처리 | 체크섬, 세그먼트 분할, 순서 정렬, 혼잡 제어를 전부 CPU가 한다 |
| 인터럽트 | 패킷마다 인터럽트가 뜨면 CPU가 인터럽트 처리에만 매달린다 |
경험칙으로 1Gbps당 1GHz의 CPU가 필요하다는 말이 있다. 100Gbps NIC를 소켓으로 꽉 채우려면 코어 여러 개를 통째로 네트워크에 헌납해야 한다는 뜻이다.
flowchart TD
subgraph SS["송신 서버"]
C1["애플리케이션 버퍼<br/>사전에 등록(pin)된 메모리"]
C2["Work Request를<br/>Send Queue에 직접 기록<br/>커널 개입 없음"]
C3["RNIC이 doorbell을 보고<br/>버퍼를 직접 DMA 읽기"]
C1 -.->|"주소만 알려줌"| C2
C2 --> C3
end
C3 -->|"RoCE / InfiniBand 패킷"| D1
subgraph RR["수신 서버"]
D1["RNIC이 패킷 수신"]
D2["헤더의 가상주소·rkey 해석<br/>전송 프로토콜을 NIC이 직접 처리"]
D3["애플리케이션 버퍼에<br/>직접 DMA 쓰기"]
D4["수신 측 CPU는<br/>아무것도 하지 않음"]
D1 --> D2 --> D3 -.-> D4
end
style D4 fill:#f1f5f9,stroke:#94a3b8,color:#0f172a,stroke-dasharray: 5 5
핵심 특성 세 가지로 요약된다.
- Zero-copy: 커널 버퍼를 거치는 복사가 없다. NIC이 애플리케이션 버퍼를 직접 읽고 쓴다
- Kernel bypass: 애플리케이션이 커널을 거치지 않고 NIC의 큐에 직접 명령을 넣는다
- CPU offload / Transport offload: 순서 보장, 재전송, ACK 같은 전송 계층 처리를 NIC 하드웨어가 담당한다
결과적으로 지연이 수십 마이크로초에서 1~2μs 수준으로 떨어지고, 100G 이상을 CPU 코어 하나 이하로 채운다.
RDMA의 전제는 NIC이 물리 주소로 DMA를 한다는 것이다. 그런데 리눅스는 페이지를 언제든 스왑하거나 옮길 수 있다. NIC이 DMA 하는 도중에 페이지가 이동하면 엉뚱한 메모리를 덮어쓴다.
그래서 RDMA를 쓰려면 사전에 Memory Registration(MR) 을 해야 한다.
flowchart LR
M1["ibv_reg_mr 호출"] --> M2["해당 페이지를 pin<br/>스왑아웃·이동 금지"]
M2 --> M3["가상주소 → 물리주소<br/>변환 테이블을 NIC에 등록"]
M3 --> M4["lkey / rkey 발급"]
M4 --> M5["이후 NIC이<br/>커널 없이 직접 접근 가능"]
- lkey (local key): 내 NIC이 내 로컬 버퍼에 접근할 때 쓰는 열쇠
- rkey (remote key): 상대방 NIC이 내 버퍼에 접근할 때 제시해야 하는 열쇠. 이 값을 상대에게 알려줘야 원격 접근이 가능하다. 사실상 접근 권한 토큰이므로 보안 경계가 여기에 있다
메모리 등록은 비싼 연산(pin + 테이블 등록)이라, 실무에서는 애플리케이션 시작 시 큰 버퍼를 한 번 등록해두고 재사용한다.
RDMA 프로그래밍 인터페이스를 verbs라고 부른다. 소켓 API에 대응하는 개념이다. verbs가 다루는 객체들의 관계는 이렇다.
flowchart TB
DEV["Device / HCA<br/>물리 RDMA 카드"] --> CTX["Context<br/>디바이스 사용 세션"]
CTX --> PD["PD (Protection Domain)<br/>격리 단위. 같은 PD 안의<br/>MR과 QP만 서로 접근 가능"]
PD --> MR["MR (Memory Region)<br/>등록된 메모리 영역<br/>lkey / rkey 보유"]
PD --> QP["QP (Queue Pair)<br/>통신 종단점. 소켓에 해당"]
CTX --> CQ["CQ (Completion Queue)<br/>완료 통지 큐"]
QP --> SQ["SQ (Send Queue)<br/>내가 보낼 작업"]
QP --> RQ["RQ (Receive Queue)<br/>받을 준비 버퍼"]
SQ --> WQE1["WQE (Work Queue Element)<br/>작업 요청 하나"]
RQ --> WQE2["WQE"]
CQ --> CQE["CQE (Completion Queue Element)<br/>작업 완료 결과"]
SQ -.->|"완료되면"| CQ
RQ -.->|"완료되면"| CQ
| 용어 | 설명 |
|---|---|
| HCA (Host Channel Adapter) | RDMA 카드 자체. 이더넷 쪽에서는 RNIC(RDMA NIC) 이라고 부른다 |
| verbs | RDMA API. libibverbs 라이브러리로 제공된다. 소켓의 socket/bind/send 자리에 ibv_create_qp/ibv_post_send 같은 함수가 온다 |
| QP (Queue Pair) | Send Queue와 Receive Queue의 쌍. 통신 종단점이며 소켓에 대응한다. QP 번호(QPN)로 식별한다 |
| WQE (Work Queue Element) | “이 버퍼를 저기로 보내라” 같은 작업 요청 하나. WR(Work Request)이라고도 한다. 흔히 “우키”라고 읽는다 |
| CQ / CQE | 작업 완료를 알리는 큐와 그 항목. 폴링하거나 이벤트로 받는다 |
| doorbell | 애플리케이션이 큐에 WQE를 넣은 뒤 NIC의 MMIO 레지스터를 두드려 “일감 생겼다”고 알리는 동작 |
| PD (Protection Domain) | MR과 QP를 묶는 격리 단위. 다른 PD의 메모리에는 접근할 수 없다 |
| GID (Global Identifier) | 128비트 주소. RoCE v2에서는 IP 주소를 매핑해서 쓴다. IPv4는 IPv4-mapped IPv6 형태로 들어간다 |
| LID (Local Identifier) | InfiniBand 서브넷 안의 16비트 지역 주소. RoCE에는 없다 |
| PKey (Partition Key) | InfiniBand의 논리 분할. VLAN과 비슷한 역할 |
| RDMA-CM | 연결 수립을 돕는 Connection Manager. IP 주소 기반으로 QP 정보를 교환해준다. 이게 없으면 QPN·GID를 애플리케이션이 직접 주고받아야 한다 |
RDMA를 이해하는 핵심 갈림길이다.
flowchart TB
subgraph TWO["Two-sided (SEND / RECV)"]
direction LR
T1["송신: SEND 요청"] -->|"데이터"| T2["수신: 미리 RECV를<br/>걸어둬야 함"]
T2 --> T3["수신 CPU가<br/>완료를 인지함"]
end
subgraph ONE["One-sided (RDMA WRITE / READ)"]
direction LR
O1["송신: 상대 주소 + rkey를<br/>헤더에 담아 전송"] -->|"데이터 + 목적지 주소"| O2["수신 NIC이<br/>해당 주소에 직접 씀"]
O2 --> O3["수신 CPU는<br/>개입도 인지도 안 함"]
end
style O3 fill:#f1f5f9,stroke:#94a3b8,color:#0f172a
| 동작 | 유형 | 설명 |
|---|---|---|
| SEND / RECV | two-sided | 수신 측이 미리 RECV WQE를 올려둬야 한다. 안 올려두면 RNR(Receiver Not Ready) 에러가 난다 |
| RDMA WRITE | one-sided | 상대 메모리에 직접 쓴다. 상대 CPU는 모른다 |
| RDMA READ | one-sided | 상대 메모리를 직접 읽어온다 |
| ATOMIC (CAS / FAA) | one-sided | Compare-and-Swap, Fetch-and-Add를 원격 메모리에 원자적으로 수행. 분산 락 구현에 쓴다 |
| WRITE with IMM | 혼합 | WRITE를 하면서 4바이트 즉치값을 같이 보내 수신 측에 완료를 알린다. 순수 one-sided의 “상대가 모른다”는 문제를 우회하는 흔한 패턴 |
one-sided 연산이 RDMA의 진짜 무기다. 수신 서버의 CPU가 100% 사용 중이어도 원격 메모리 접근은 그대로 동작한다.
flowchart LR
RC["RC<br/>Reliable Connected"] --> RC1["신뢰성 O, 1:1 연결<br/>모든 연산 지원<br/>가장 많이 쓰임"]
UC["UC<br/>Unreliable Connected"] --> UC1["재전송 없음, 1:1<br/>거의 안 씀"]
UD["UD<br/>Unreliable Datagram"] --> UD1["비연결, 1:N 가능<br/>SEND만 지원<br/>MPI 대규모 통신에 사용"]
DC["DCT<br/>Dynamically Connected"] --> DC1["NVIDIA 확장<br/>RC의 신뢰성 + UD의 확장성"]
노드가 N개면 RC는 QP가 N²로 늘어나 메모리를 잡아먹는다. 이 QP 폭발 문제 때문에 대규모 클러스터에서 UD나 DCT를 쓴다. NCCL도 규모에 따라 전략을 바꾼다.
QP는 생성 직후 바로 못 쓴다. 정해진 순서로 상태를 올려야 한다.
stateDiagram-v2
[*] --> RESET: ibv_create_qp 로 생성
RESET --> INIT: 포트·PKey·접근권한 설정
INIT --> RTR: Ready To Receive. 상대 QPN·GID·MTU 지정
RTR --> RTS: Ready To Send. PSN·타임아웃·재시도 횟수 지정
RTS --> SQD: Send Queue Drain. 일시 정지
SQD --> RTS: 재개
RTS --> ERR: 에러 발생
RTR --> ERR: 에러 발생
ERR --> RESET: 복구는 RESET부터 다시
RTS --> [*]: destroy_qp
note right of RTR
여기서 상대방 정보가 필요하다.
그래서 사전에 out-of-band로
QPN·GID·PSN을 교환해야 한다.
end note
핵심은 RTR로 가려면 상대 QP의 정보를 이미 알고 있어야 한다는 점이다. 그래서 RDMA 연결은 항상 TCP나 RDMA-CM 같은 별도 경로로 정보를 먼저 교환한다. 이 과정을 out-of-band exchange라고 부른다.
sequenceDiagram
autonumber
participant AppA as 서버 A 앱
participant NicA as 서버 A RNIC
participant Net as 네트워크
participant NicB as 서버 B RNIC
participant AppB as 서버 B 앱
Note over AppA,AppB: 1단계 준비 (커널 경유, 느림, 1회만)
AppA->>AppA: ibv_open_device / alloc_pd
AppA->>AppA: ibv_reg_mr - 버퍼 pin, lkey·rkey 발급
AppA->>AppA: ibv_create_cq / create_qp - QP는 RESET 상태
AppB->>AppB: 동일하게 준비
Note over AppA,AppB: 2단계 정보 교환 (TCP 또는 RDMA-CM)
AppA->>AppB: QPN, GID, PSN, 버퍼 주소, rkey
AppB->>AppA: QPN, GID, PSN, 버퍼 주소, rkey
Note over AppA,AppB: 3단계 QP 상태 전이
AppA->>NicA: modify_qp RESET → INIT → RTR → RTS
AppB->>NicB: modify_qp RESET → INIT → RTR → RTS
Note over AppA,AppB: 4단계 데이터 전송 (커널 미경유, 빠름, 반복)
AppA->>NicA: WQE를 SQ에 기록 후 doorbell
NicA->>NicA: 등록된 버퍼를 DMA로 직접 읽음
NicA->>Net: RoCE v2 패킷<br/>BTH + RETH(주소·rkey) + 페이로드
Net->>NicB: 전달
NicB->>NicB: rkey 검증 후 목적지 버퍼에 직접 DMA 쓰기
NicB-->>NicA: ACK (RC 모드)
NicA->>AppA: CQ에 CQE 기록
AppA->>AppA: ibv_poll_cq 로 완료 확인
Note over AppB: RDMA WRITE였다면 서버 B의 CPU는<br/>이 전송을 전혀 알지 못한다
준비 단계는 느리고 커널을 거치지만 한 번만 한다. 데이터 단계는 커널을 완전히 우회한다. 이 분리가 RDMA 성능의 본질이다.
RDMA는 개념이고, 실제로 배선에 태우는 방식이 세 가지다.
flowchart LR
subgraph IB["InfiniBand"]
direction LR
IB1["RDMA verbs"] --> IB2["IB Transport"] --> IB3["IB Network"] --> IB4["IB Link<br/>credit 기반 무손실"] --> IB5["전용 IB<br/>케이블·스위치"]
end
flowchart LR
subgraph RCE["RoCE v2"]
direction LR
R1["RDMA verbs"] --> R2["IB Transport<br/>동일한 전송계층 재사용"] --> R3["UDP / IP<br/>포트 4791"] --> R4["Ethernet<br/>PFC로 무손실 흉내"] --> R5["일반 이더넷<br/>스위치"]
end
flowchart LR
subgraph IW["iWARP"]
direction LR
W1["RDMA verbs"] --> W2["MPA / DDP / RDMAP"] --> W3["TCP<br/>손실 허용·재전송 내장"] --> W4["IP / Ethernet"] --> W5["일반 이더넷<br/>스위치"]
end
| InfiniBand | RoCE v2 | iWARP | |
|---|---|---|---|
| 물리 계층 | 전용 IB 스위치·케이블 | 일반 이더넷 | 일반 이더넷 |
| 전송 계층 | IB Transport | IB Transport (그대로) | TCP |
| 캡슐화 | 없음 | UDP/IP, 목적지 포트 4791 | TCP |
| 무손실 요구 | 링크 credit으로 원천 보장 | PFC로 만들어야 함 | 불필요 (TCP가 처리) |
| 라우팅 | 서브넷 매니저(SM)가 관리 | 표준 IP 라우팅. L3를 넘어감 | 표준 IP 라우팅 |
| 성능 | 최상 | IB에 근접 | 다소 낮음 |
| 설정 난이도 | 중간 (SM 필요) | 높음 | 낮음 |
| 주 벤더 | NVIDIA(구 Mellanox) 사실상 독점 | 다수 | Chelsio, Intel X722 |
flowchart LR
subgraph V1["RoCE v1 · 사실상 사장됨"]
direction LR
A["Ethernet Header<br/>EtherType 0x8915"] --> B["GRH<br/>Global Route Header"] --> C["BTH"] --> D["Payload"] --> E["ICRC + FCS"]
end
flowchart LR
subgraph V2["RoCE v2 · 현재 표준"]
direction LR
G["Ethernet<br/>Header"] --> H["IP Header<br/>DSCP 마킹"] --> I["UDP Header<br/>dst 4791<br/>src = ECMP 엔트로피"] --> J["BTH<br/>Base Transport"] --> K["RETH<br/>가상주소·rkey·길이"] --> L["Payload"] --> M["ICRC + FCS"]
end
v1은 이더넷 프레임에 EtherType 0x8915로 바로 얹는다. 그래서 L2 브로드캐스트 도메인 안에서만 동작하고 라우터를 넘지 못한다. v2는 UDP/IP로 한 번 감싸서 표준 IP 라우팅을 타므로 데이터센터 전체로 확장된다. 라우팅이 된다는 뜻에서 RRoCE(Routable RoCE)라고도 부른다.
| 헤더 | 의미 |
|---|---|
| BTH (Base Transport Header) | 목적지 QPN, opcode(SEND/WRITE/READ), PSN(Packet Sequence Number)이 들어간다. RDMA 전송의 핵심 헤더 |
| RETH (RDMA Extended Transport Header) | one-sided 연산에만 붙는다. 상대 메모리의 가상 주소, rkey, 길이가 여기 담긴다 |
| PSN | 패킷 순서 번호. 이게 어긋나면 재전송이 발생한다 |
| ICRC | RDMA 계층의 무결성 검사값. 이더넷 FCS와 별개다 |
| UDP source port | 실제 포트가 아니라 QP별로 계산한 해시값을 넣는다. 스위치의 ECMP(Equal-Cost Multi-Path, 같은 비용의 여러 경로에 해시로 분산시키는 라우팅)가 이 값으로 경로를 고른다 |
UDP 4791은 외워둘 만하다. 방화벽이나 ACL에서 이 포트가 막히면 RoCE가 안 붙는다.
RoCE v2의 전송 계층은 InfiniBand의 것을 그대로 가져왔다. IB의 물리 계층은 credit 기반이라 패킷이 애초에 버려지지 않는다. 그 위에서 만들어진 전송 계층이라 손실 대응이 원시적이다.
3장에서 RoCE의 이더넷 계층을 “PFC로 무손실 흉내”라고 적었다. 흉내라고 쓴 이유가 여기 있다. IB와 이더넷은 무손실을 만드는 방식이 근본적으로 다르다.
InfiniBand는 사전 허가 방식이다. 수신 측이 “버퍼 10칸 비었으니 10개까지 보내라”고 credit을 먼저 준다. 송신 측은 받아줄 공간이 확인된 만큼만 보낸다. 손실이 안 나는 게 아니라, 넘칠 상황 자체가 만들어지지 않는다.
이더넷과 PFC는 사후 정지 방식이다. 일단 보내고, 수신 버퍼가 차면 그제서야 멈추라고 말한다. 말한 시점부터 상대가 실제로 멈추기까지 시간이 걸리고, 그 사이 날아온 패킷을 받아둘 여유 공간이 따로 필요하다. 뒤에 나올 headroom이 그것이다.
| InfiniBand | 이더넷 + PFC | |
|---|---|---|
| 방식 | 사전 허가 (credit) | 사후 정지 (PAUSE) |
| 무손실 | 구조적으로 보장 | 설정을 제대로 했을 때만 |
| headroom 부족 시 | 해당 없음 | 그대로 드롭 |
| 고유 부작용 | 없음 | HOL 블로킹, PFC storm, deadlock |
결과물은 무손실처럼 보이지만 원리가 다르고 조건부다. 원래 손실을 전제로 설계된 배선 위에, 손실을 전제하지 않는 프로토콜을 올리는 일이라 그 간극을 사람이 설정으로 메워야 한다. RoCE 설정이 까다로운 근본 이유다.
flowchart TD
A["패킷 1개 손실"] --> B{"NIC 세대"}
B -->|"구형 (CX-4 등)"| C["Go-back-N 재전송<br/>손실 지점 이후 전부 재전송"]
B -->|"신형 (CX-6/7 등)"| D["Selective Repeat<br/>손실분만 재전송"]
C --> E["1% 손실에 처리량 50% 이상 붕괴<br/>손실이 재전송을 부르고<br/>재전송이 다시 혼잡을 부르는 악순환"]
D --> F["어느 정도 견딤"]
style E fill:#fdeaea,stroke:#e05656,color:#0f172a
그래서 RoCE는 네트워크를 무손실로 만들어야 한다. 그 도구가 PFC와 ECN이다. 두 메커니즘은 동작 범위가 다르며, 이 차이를 이해하는 게 RoCE 설정의 전부라고 해도 된다.
여기서부터 약어가 쏟아지므로 먼저 정리해둔다. 이 글의 나머지는 사실상 이 표를 풀어쓴 것이다.
| 약어 | 원래 이름 | 뜻 |
|---|---|---|
| PFC | Priority Flow Control (IEEE 802.1Qbb) | 우선순위별로 “잠깐 멈춰”를 보내 버퍼 넘침을 막는 흐름 제어. 케이블 한 구간에만 적용된다 |
| PAUSE | PFC가 실제로 보내는 프레임 | 정지 신호 그 자체. 직접 연결된 옆 장비에게만 가고 라우팅되지 않는다 |
| ECN | Explicit Congestion Notification | 패킷을 버리는 대신 IP 헤더의 비트를 세워 “혼잡하다”고 표시하는 방식 |
| CE | Congestion Experienced | 스위치가 혼잡할 때 찍는 ECN 표시값 |
| CNP | Congestion Notification Packet | CE 표시를 본 수신 서버가 송신 서버에게 되돌리는 “속도 줄여” 패킷 |
| DCQCN | Data Center Quantized Congestion Notification | ECN 마킹, CNP 생성, 속도 조절을 하나로 묶은 RoCE의 혼잡 제어 알고리즘 |
| hop-by-hop | 홉 단위 | 케이블 한 구간씩 옆으로만 전달되는 방식. PFC가 여기 해당 |
| end-to-end | 종단 간 | 출발지에서 목적지까지 직행하는 방식. DCQCN이 여기 해당 |
| flow | 흐름 | 같은 출발지·목적지·포트를 공유하는 하나의 통신 단위 |
flowchart TB
subgraph PFC["PFC · 링크 단위, hop-by-hop"]
direction TB
P1["스위치 A"] <-->|"PAUSE"| P2["스위치 B"] <-->|"PAUSE"| P3["서버"]
end
flowchart TB
subgraph ECN["DCQCN · 종단 간, end-to-end"]
direction TB
E1["송신 서버"] -->|"데이터"| E2["스위치가 ECN 마킹"] -->|"데이터"| E3["수신 서버"]
E3 -->|"CNP 되돌림"| E1
end
PFC는 즉각적이지만 무차별하다. 버퍼 넘침은 확실히 막는 대신 큐 전체를 세우기 때문에 누가 원인인지 가리지 못한다. DCQCN은 한 바퀴 도느라 느린 대신 정확하다. 진짜 원인이 되는 flow의 속도만 줄인다.
PFC는 응급처치, DCQCN은 근본 치료다. 둘 다 있어야 한다.
sequenceDiagram
autonumber
participant TX as 송신 측 포트
participant RX as 수신 측 포트 버퍼
TX->>RX: RoCE 데이터 (priority 3)
TX->>RX: RoCE 데이터
Note over RX: 버퍼가 XOFF 임계치 도달
RX-->>TX: PFC PAUSE 프레임<br/>priority 3, quanta = N
Note over TX: priority 3 큐만 전송 중단<br/>다른 priority는 계속 흐름
Note over RX: 그 사이 버퍼를 비움
Note over RX: XON 임계치 아래로 내려감
RX-->>TX: PFC PAUSE (quanta = 0)<br/>또는 타이머 만료
TX->>RX: 전송 재개
- priority 단위로 멈춘다는 게 기존 802.3x 글로벌 PAUSE와의 결정적 차이다. 글로벌 PAUSE는 링크 전체를 멈춰서 관리 트래픽까지 죽인다
- quanta: PAUSE 지속 시간 단위. 512비트 전송 시간에 해당한다
- 중요: PFC를 켤 때 글로벌 PAUSE(802.3x)는 반드시 꺼야 한다. 둘은 상호 배타적이며 같이 켜면 오작동한다
PFC PAUSE는 IP도 TCP도 아닌 L2 MAC(Media Access Control) Control 프레임이다. IP 헤더가 아예 없고 크기는 64바이트로 고정이다.
|
|
priority 3만 최대 시간 멈추라는 프레임이면 이렇게 채워진다.
|
|
quanta: 시간 단위
Time 필드의 단위는 초가 아니라 quanta다. 1 quanta는 해당 링크 속도로 512비트를 전송하는 시간이라, 링크가 빠를수록 같은 값이 짧은 시간이 된다.
| 링크 속도 | 1 quanta | 최대 정지 시간 (65535 quanta) |
|---|---|---|
| 10 Gbps | 51.2 ns | 약 3.35 ms |
| 25 Gbps | 20.48 ns | 약 1.34 ms |
| 100 Gbps | 5.12 ns | 약 335 μs |
Time이 0이 아니면 그만큼 정지(XOFF), 0이면 즉시 재개(XON)다. 실무에서 스위치는 한 번 크게 걸어두기보다, 혼잡이 지속되면 타이머 만료 전에 PAUSE를 갱신 발송하고 해소되면 quanta 0을 보내 즉시 풀어준다.
전 과정이 하드웨어에서 끝난다
스위치에서는 ASIC의 버퍼 관리 블록이 우선순위별 점유율을 감시하다가 XOFF 임계치에 닿으면 포트 MAC이 프레임을 만들어 보낸다. 서버에서는 NIC의 MAC이 프레임을 받아 해당 priority 큐의 송신 스케줄러를 세운다. 스위치 CPU도, 호스트 CPU도, 드라이버도, 커널도 개입하지 않는다. 반응이 마이크로초 단위로 나오는 이유이고, 소프트웨어가 끼면 headroom이 감당하지 못한다.
같은 이유로 tcpdump로는 PFC 프레임을 잡을 수 없다. NIC의 MAC 계층에서 소비되고 끝나 호스트 네트워크 스택까지 올라오지 않는다. PFC 문제는 패킷 캡처가 아니라 양쪽 카운터 대조로 본다.
목적지 MAC 01:80:C2:00:00:01 이 답이다. 이 주소는 IEEE 802.1D의 예약 멀티캐스트 대역(01:80:C2:00:00:00 ~ 01:80:C2:00:00:0F)에 속하고, 표준을 따르는 브리지는 이 대역의 프레임을 전달해서는 안 된다. 받으면 그 자리에서 소비하고 끝이다. PAUSE가 라우팅되지 않는 것은 관행이 아니라 프로토콜 설계에 못 박힌 규칙이다.
그래서 혼잡은 목적지에서 출발지로 한 칸씩 뒤로 번진다.
sequenceDiagram
autonumber
participant A as 서버 A
participant L1 as Leaf1
participant SP as Spine
participant L2 as Leaf2
participant B as 서버 B
A->>L1: RoCE 데이터
L1->>SP: 전달
SP->>L2: 전달
Note over L2: 서버 B 방향 버퍼가 참
L2-->>SP: PAUSE, Leaf2와 Spine 사이 링크
Note over SP: Spine 버퍼가 참
SP-->>L1: PAUSE, Spine과 Leaf1 사이 링크
Note over L1: Leaf1 버퍼가 참
L1-->>A: PAUSE, Leaf1과 서버 A 사이 링크
Note over A: 이제서야 서버 A가 멈춘다
Leaf2가 서버 A에게 직접 말하지 않는다. 옆 사람에게만 말하고, 그것이 역방향으로 한 칸씩 번져 결국 서버 A까지 도달한다. 고속도로 정체가 뒤로 밀리는 것과 같다.
문제는 5번 단계다. Spine이 Leaf1을 세울 때 그 링크의 priority 3 트래픽 전체가 멈춘다. 혼잡한 서버 B와 아무 상관 없는, 전혀 다른 목적지로 가던 통신까지 같이 멈춘다. PFC는 누가 원인인지 구분할 능력이 없다. 큐 단위로 뭉뚱그려 세울 뿐이다. 5.6에서 볼 victim flow의 정체가 이것이다.
반면 CNP는 일반 IP 패킷이라 스위치를 그냥 통과해 송신 서버까지 직행한다. 원인이 되는 flow만 정확히 조준할 수 있는 이유다.
| PAUSE (PFC) | CNP (DCQCN) | |
|---|---|---|
| 범위 | 링크 단위, 한 칸씩 | 종단 간, 직행 |
| 형태 | L2 제어 프레임 | 일반 IP 패킷 |
| 스위치 | 전달하지 않음 | 그냥 통과 |
| 메시지 | 이 큐 전체 멈춰 | 너 이 flow 속도 줄여 |
| 정확도 | 무차별 | 원인 지목 |
PAUSE는 방향도 양쪽이다. 링크의 수신 측이면 누구든 보낸다. 스위치가 서버 NIC에게 보내고, 스위치끼리도 주고받고, 서버의 수신 버퍼가 차면 서버 NIC이 스위치에게 보낸다. 스위치만 설정하면 절반만 한 것이고, 카운터를 tx_prio3_pause(내가 보낸 것)와 rx_prio3_pause(내가 받은 것)로 나눠 보는 이유도 여기 있다.
PAUSE 프레임을 보낸 순간부터 상대가 실제로 멈출 때까지 시간이 걸린다. 그 사이 날아오는 패킷을 받아둘 여유 버퍼가 headroom이다.
flowchart LR
subgraph BUF["수신 포트 버퍼"]
H["Headroom<br/>PAUSE 후 도착분 흡수용"]
X["XOFF 임계치"]
N["XON 임계치"]
D["일반 사용 영역"]
end
H -.->|"부족하면"| DROP["패킷 드롭 발생<br/>= 무손실 실패"]
style DROP fill:#fdeaea,stroke:#e05656,color:#0f172a
headroom에 필요한 크기는 이 네 가지의 합이다.
- 케이블 전파 지연 (왕복). 광케이블에서 대략 5ns/m, 100m면 왕복 1μs
- 송신 측 PAUSE 반응 시간 (MAC/PHY 처리)
- PAUSE 프레임 자체의 전송·수신 시간
- 현재 전송 중인 최대 프레임 (점보면 9KB)
그래서 스위치 설정에 케이블 길이를 넣는 항목이 있다. 서버 NIC 쪽에도 mlnx_qos --cable_len 이 있다. 케이블 길이를 실제보다 짧게 잡으면 headroom이 모자라 드롭이 나고, 무손실이 깨진다.
위 그림에는 아직 ECN 임계치가 없다. ECN을 다루고 나서 6.5에서 두 임계치의 순서 관계까지 포함한 전체 그림을 다시 본다. 실제 튜닝에서 가장 먼저 확인해야 하는 것이 그 순서다.
어느 priority를 lossless로 다룰지는 링크 양끝이 같은 값을 알고 있어야 한다. 한쪽만 알고 있으면 PFC는 아무 일도 하지 않는다. 방법은 둘이다.
DCBX (자동 협상)
Data Center Bridging Capability Exchange. LLDP에 얹혀 다니는 확장이다. 스위치와 NIC이 “priority 3이 no-drop”이라는 설정을 주고받는다. IEEE 방식(802.1Qaz)과 표준 제정 이전의 CEE 방식 두 갈래가 있고, 벤더 조합에 따라 서로 안 맞는 경우가 있다.
정적 설정
willing 비트를 0으로 두고 양쪽에 같은 값을 못 박는다. 협상 실패로 인한 비결정적 동작을 피하려고 프로덕션에서는 대개 이쪽을 택한다. 노드가 수십 대를 넘어가면 협상의 편의보다 전 노드 동일성이 훨씬 중요해진다.
|
|
flowchart TD
A["PFC 남용"] --> B["Head-of-Line Blocking<br/>느린 목적지 하나 때문에<br/>같은 큐의 다른 트래픽도 멈춤"]
A --> C["Congestion Spreading / PFC Storm<br/>PAUSE가 상류로 번져<br/>혼잡과 무관한 flow까지 정지<br/>= victim flow"]
A --> D["PFC Deadlock<br/>순환 의존이 생기면<br/>서로 영원히 기다림"]
D --> E["대책: PFC Watchdog<br/>일정 시간 이상 PAUSE 상태면<br/>큐를 강제로 비움"]
style B fill:#fdeaea,stroke:#e05656,color:#0f172a
style C fill:#fdeaea,stroke:#e05656,color:#0f172a
style D fill:#fdeaea,stroke:#e05656,color:#0f172a
PFC 카운터가 계속 올라간다면 이미 문제 상황이다. 정상 운영에서 PAUSE는 어쩌다 한 번 나와야 한다. 상시로 나오면 DCQCN이 제 역할을 못 하고 있다는 신호다.
패킷을 버려서 혼잡을 알리는 대신, IP 헤더의 ECN 비트 2개를 세워서 혼잡을 알린다. RoCE는 패킷을 버리면 안 되므로 이 방식이 필수다.
| ECN 코드포인트 | 값 | 의미 |
|---|---|---|
| Non-ECT | 00 |
ECN 미지원 트래픽 |
| ECT(1) | 01 |
ECN 지원 |
| ECT(0) | 10 |
ECN 지원 (RoCE가 주로 사용) |
| CE | 11 |
Congestion Experienced. 스위치가 혼잡 시 이 값으로 바꾼다 |
ToS 바이트 8비트의 구성이 이렇다.
7 6 5 4 3 2 1 0
+---+---+---+---+---+---+---+---+
| DSCP (6비트) | ECN(2) |
+---+---+---+---+---+---+---+---+
DSCP(Differentiated Services Code Point)는 트래픽 등급을 표시하는 6비트 값이고, 하위 2비트가 ECN이다. 그래서 DSCP 값에 4를 곱하면 ToS 값이 된다. DSCP 26이면 ToS 104, 여기에 ECT(0)=10(=2)을 더해 106을 쓰는 설정 예시를 자주 본다.
DCQCN(Data Center Quantized Congestion Notification) 은 ECN 마킹과 속도 조절을 묶은 알고리즘이다. 세 역할이 등장한다.
sequenceDiagram
autonumber
participant RP as 송신 NIC<br/>RP (Reaction Point)
participant CP as 스위치<br/>CP (Congestion Point)
participant NP as 수신 NIC<br/>NP (Notification Point)
RP->>CP: RoCE 패킷 전송. ECN 비트는 ECT(0)
Note over CP: 큐 길이가 WRED<br/>min 임계치 초과
CP->>CP: ECN 비트를 CE 로 변경<br/>패킷은 버리지 않음
CP->>NP: CE 마킹된 패킷 전달
Note over NP: CE 감지
NP-->>RP: CNP 생성 후 되돌림<br/>DSCP 48, priority 6
Note over NP: min_time_between_cnps 간격으로<br/>과도한 CNP 생성 억제
Note over RP: 전송률 감소<br/>alpha 값 기반 승산 감소
RP->>CP: 낮아진 속도로 전송
Note over RP: CNP가 한동안 안 오면<br/>Fast Recovery → Additive Increase<br/>→ Hyper Increase 순으로 회복
| 용어 | 설명 |
|---|---|
| CP (Congestion Point) | 혼잡이 발생한 스위치. ECN 마킹을 수행 |
| NP (Notification Point) | 수신 서버의 NIC. CE를 보고 CNP를 만들어 되돌린다 |
| RP (Reaction Point) | 송신 서버의 NIC. CNP를 받고 속도를 낮춘다 |
| CNP (Congestion Notification Packet) | 혼잡 신호 패킷. 페이로드 없는 작은 패킷이며 별도 우선순위로 보호해야 한다 |
| WRED | 스위치에서 큐 길이에 따라 확률적으로 마킹하는 방식. min/max 임계치와 마킹 확률로 설정 |
flowchart TD
A["수신 서버에 ECN(np) 설정 누락"] --> B["CE 마킹을 봐도 CNP를 안 만듦"]
B --> C["송신자는 혼잡을 모른 채<br/>계속 풀스피드 전송"]
C --> D["스위치 버퍼 계속 상승"]
D --> E["PFC PAUSE 발생"]
E --> F["PAUSE가 상류로 전파"]
F --> G["무관한 flow까지 느려짐<br/>fabric 전체 성능 붕괴"]
style A fill:#fdeaea,stroke:#e05656,color:#0f172a
style G fill:#fdeaea,stroke:#e05656,color:#0f172a
RoCE 클러스터에서 모든 노드는 송신자이자 수신자다. 따라서 np와 rp를 모든 노드에 전부 켜야 한다. 한 대만 빠져도 그 노드가 관련된 통신에서 문제가 시작된다.
CNP는 “혼잡하니 줄여라”는 신호다. 그런데 이 신호가 혼잡 때문에 지연되거나 버려지면 제어 자체가 무너진다. 그래서 이렇게 다룬다.
- 별도 우선순위(관례상 priority 6, DSCP 48)에 배치
- strict priority 스케줄링으로 최우선 전송
- PFC는 걸지 않는다. 혼잡 신호가 혼잡으로 막히는 자기모순을 피하기 위함이다. CNP는 작고 드물어서 lossy로 둬도 실무상 문제되지 않는다
여기서 자주 나오는 오해를 짚고 간다. PFC와 DCQCN은 둘 중 하나를 고르는 게 아니라 둘 다 켜는 것이다. 다만 역할이 다르다.
- DCQCN이 주 제어 장치다. 평상시 혼잡은 전부 여기서 처리되어야 한다
- PFC는 안전망이다. DCQCN이 미처 반응하지 못한 순간만 받아낸다
DCQCN은 폐루프다. 스위치가 마킹하고, 수신 서버까지 가고, CNP가 돌아오고, 그제서야 송신 속도가 내려간다. 최소 한 바퀴(RTT)가 필요하다. 그런데 마이크로버스트와 incast는 그 한 바퀴보다 빠르다. 여러 노드가 동시에 한 곳으로 쏘면 버퍼는 마이크로초 만에 찬다. 그 순간을 막는 것이 PFC의 존재 이유다.
그래서 설정의 핵심은 둘 중 무엇을 켜느냐가 아니라 임계치 순서다. 5.4의 버퍼 그림에 ECN 임계치까지 얹으면 전체 그림이 이렇게 완성된다.
flowchart TB
T["▲ 버퍼 점유율 높음"]
HR["headroom<br/>절대 침범 금지. 침범하면 드롭"]
XF["PFC XOFF 임계치<br/>여기까지 왔다면 이미 실패한 것"]
GAP["여유 구간"]
EMX["ECN max threshold<br/>거의 모든 패킷에 CE 마킹"]
EMN["ECN min threshold<br/>DCQCN이 여기서 먼저 개입해야 정상"]
NM["일반 사용 영역"]
B["▼ 버퍼 점유율 낮음"]
T --- HR --- XF --- GAP --- EMX --- EMN --- NM --- B
style T fill:#f1f5f9,stroke:#94a3b8,color:#0f172a
style B fill:#f1f5f9,stroke:#94a3b8,color:#0f172a
style HR fill:#fdeaea,stroke:#e05656,color:#0f172a
style XF fill:#fdeaea,stroke:#e05656,color:#0f172a
style GAP fill:#f1f5f9,stroke:#94a3b8,color:#0f172a
style EMX fill:#e7f6ec,stroke:#22a15d,color:#0f172a
style EMN fill:#e7f6ec,stroke:#22a15d,color:#0f172a
style NM fill:#f1f5f9,stroke:#94a3b8,color:#0f172a
ECN 임계치는 PFC XOFF 임계치보다 충분히 낮아야 한다. 순서가 뒤집히면, 즉 ECN 임계치가 PFC보다 높게 잡히면 DCQCN이 일할 기회를 얻기 전에 PFC가 먼저 터진다. 그러면 설정은 다 해놓고도 사실상 PFC만 켠 것과 같아진다. “왜 CNP도 나오는데 PAUSE가 계속 뜨지”의 흔한 원인이다.
하나만 켰을 때 벌어지는 일
| 구성 | 결과 |
|---|---|
| PFC만 | 동작은 한다. 하지만 송신 속도를 줄이는 주체가 없어 PAUSE가 상시로 터진다. congestion spreading, victim flow, HOL 블로킹, 최악은 deadlock. 8노드는 되는데 64노드에서 무너지는 전형 |
| DCQCN만 | 제어 루프가 도는 동안 버퍼가 넘쳐 드롭이 난다. 구형 NIC이면 go-back-N으로 처리량이 붕괴 |
| 둘 다 끄면 | 한가할 때는 잘 되다가 부하가 걸리면 무너진다 |
정상인지 판정하는 법
|
|
| 관측 | 해석 | 조치 |
|---|---|---|
| CNP 활발, PAUSE는 가끔 | 정상. DCQCN이 주로 일하고 PFC는 안전망 역할만 | 없음 |
| CNP 활발, PAUSE도 상시 | ECN 임계치가 너무 높다 | min/max threshold를 낮춘다 |
| CNP는 0, PAUSE만 상시 | DCQCN이 아예 안 돌고 있다 | roce_np/roce_rp 설정과 DSCP 매핑 확인 |
| 둘 다 조용 | 아직 혼잡이 없거나 마킹 자체가 안 되고 있다 | 부하를 준 상태에서 재측정 |
PFC 카운터는 0에 가까울수록 좋고, CNP 카운터는 돌고 있어야 정상이다. PFC가 자주 발동한다는 것은 소방차가 매일 출동한다는 뜻이지 소방 시스템이 잘 돌아간다는 뜻이 아니다.
14장에서 볼 selective repeat이나 AWS SRD처럼 의도적으로 PFC를 빼는 구성도 있지만, 그것은 NIC과 패브릭이 손실을 감내하도록 설계되었을 때의 이야기다. 일반적인 RoCE v2 구축이라면 둘 다 켜고, ECN 임계치를 조여 PFC 발동을 최소화하는 방향으로 튜닝한다.
flowchart TB
subgraph TXS["송신 서버"]
S1["애플리케이션 / NCCL"]
S2["RDMA 트래픽에<br/>DSCP 26 마킹"]
S3["prio 3 → TC 3 매핑"]
S4["PFC prio3 활성<br/>DCQCN rp 활성"]
S1 --> S2 --> S3 --> S4
end
subgraph LEAF1["Leaf 스위치 1"]
L1["trust dscp<br/>DSCP 26 → 큐 3"]
L2["큐 3: lossless, PFC on<br/>headroom 확보"]
L3["큐 3: WRED/ECN 임계치"]
L4["큐 6: CNP, strict priority, PFC off"]
L1 --> L2 --> L3
end
subgraph SPINE["Spine 스위치"]
SP1["동일한 trust / PFC / ECN 설정"]
SP2["ECMP: UDP src port로 분산"]
end
subgraph LEAF2["Leaf 스위치 2"]
L5["동일 설정"]
end
subgraph RXS["수신 서버"]
R1["PFC prio3 활성"]
R2["DCQCN np 활성<br/>CE 감지 시 CNP 생성"]
R3["CNP를 DSCP 48로 마킹"]
R1 --> R2 --> R3
end
S4 --> L1
L3 --> SP1 --> SP2 --> L5 --> R1
R3 -.->|"CNP 역방향 경로<br/>priority 6"| L4
L4 -.-> S4
style L4 fill:#cfe0f9,stroke:#2563eb,color:#0f172a
이 그림에서 한 칸이라도 설정이 빠지면 그 구간이 lossy가 된다. “8노드까지는 잘 되는데 16노드에서 무너진다”는 증상의 대부분이 특정 spine 포트나 특정 서버 한 대의 설정 누락이다.
RoCE 얘기를 하면 대부분 OS와 스위치만 다루는데, BIOS에서 잘못 잡혀 있으면 아무리 튜닝해도 성능이 안 나온다. NIC은 PCIe 장치이므로 PCIe와 전력 관리 설정이 그대로 성능에 반영된다.
flowchart TB
subgraph B1["PCIe 경로"]
A1["Max Payload Size (MPS)"]
A2["Max Read Request Size (MRRS)"]
A3["ASPM 전력 절감"]
A4["Above 4G Decoding"]
A5["ACS (Access Control Services)"]
A6["PCIe Gen 속도·레인 수"]
A7["Relaxed Ordering"]
end
subgraph B2["전력·클럭"]
C1["C-State (특히 C6)"]
C2["P-State / 전력 프로파일"]
C3["Uncore / Infinity Fabric 주파수"]
end
subgraph B3["메모리·NUMA"]
D1["Node Interleaving"]
D2["Sub-NUMA Clustering / NPS"]
D3["IOMMU (VT-d / AMD-Vi)"]
D4["SR-IOV"]
end
subgraph B4["캐시"]
E1["DDIO / DCA"]
end
| 항목 | 권장값 | 이유 |
|---|---|---|
| Max Payload Size (MPS) | Auto가 아니라 가능한 최대값(256B 또는 512B) | 한 TLP에 실리는 데이터가 커져 PCIe 오버헤드가 줄어든다. 경로상 최소값으로 협상되므로 슬롯과 카드 모두 확인 |
| Max Read Request Size (MRRS) | 4096 | NIC이 호스트 메모리를 읽어올 때 한 번에 요청하는 크기. 작으면 요청 횟수가 늘어 대역폭이 안 나온다 |
| PCIe ASPM (L0s/L1) | Disabled | 링크를 저전력 상태로 내렸다 올리는 데 마이크로초가 든다. RDMA의 지연 이점을 그대로 날린다 |
| Above 4G Decoding | Enabled | 큰 BAR 공간 할당에 필요. GPUDirect RDMA를 쓰면 필수 |
| Resizable BAR / Large BAR | Enabled | GPU 메모리 전체를 BAR로 노출해 P2P DMA를 가능하게 한다 |
| PCIe 링크 속도 | Gen4 또는 Gen5 고정, x16 확인 | 100G NIC은 Gen4 x16이 필요하다. x8 슬롯에 꽂으면 절반만 나온다 |
| Relaxed Ordering | Enabled (특히 AMD EPYC) | PCIe 트랜잭션 순서 제약을 완화해 처리량이 올라간다. AMD 플랫폼에서 체감 차이가 크다 |
| ACS (Access Control Services) | GPUDirect를 쓸 거면 Disabled | 아래 별도 설명 |
ACS 이슈는 따로 짚어야 한다.
flowchart LR
subgraph ON["ACS 활성 - GPUDirect 불가"]
G1["GPU"] --> RC1["Root Complex까지 올라감"] --> N1["NIC"]
X1["경로가 길어져 성능 저하<br/>또는 P2P 자체가 실패"]
end
subgraph OFF["ACS 비활성 - GPUDirect 가능"]
G2["GPU"] -->|"PCIe 스위치 내부 직접 전달"| N2["NIC"]
end
style X1 fill:#fdeaea,stroke:#e05656,color:#0f172a
ACS는 PCIe 장치 간 직접 통신(peer-to-peer)을 차단해 IOMMU 격리를 보장하는 보안 기능이다. 그런데 GPUDirect RDMA는 정확히 그 P2P DMA를 써야 동작한다. 그래서 GPU 노드에서는 ACS를 끄는 게 일반적이고, 대신 가상화 격리 수준이 낮아진다는 트레이드오프를 받아들이는 것이다. 베어메탈 학습 노드라면 대체로 수용 가능한 선택이다.
확인 명령:
|
|
| 항목 | 권장값 | 이유 |
|---|---|---|
| C-State (C6 등 deep C-state) | Disabled 또는 C1까지만 | 코어가 깊은 절전 상태에서 깨어나는 데 수십 μs가 든다. 지연 편차(jitter)의 주범 |
| 전력 프로파일 | Maximum Performance | OS의 governor 이전에 펌웨어 레벨에서 성능 모드로 고정 |
| Turbo Boost | 워크로드에 따라. 지연 일관성이 중요하면 끄고 클럭 고정 | 터보는 클럭이 출렁여 지연 편차를 만든다 |
| Uncore Frequency (Intel) / Infinity Fabric (AMD) | 최대 고정 | PCIe와 메모리 컨트롤러가 여기 물려 있다. 낮으면 I/O 성능이 그대로 떨어진다 |
지연 측정 시 p50은 좋은데 p99가 튄다면 거의 항상 C-state와 주파수 스케일링이 원인이다.
NUMA(Non-Uniform Memory Access)는 CPU 소켓마다 가까운 메모리가 다른 구조를 말한다. NIC도 특정 소켓에 붙어 있으므로, 프로세스와 NIC이 같은 노드에 있느냐가 성능을 크게 가른다.
| 항목 | 권장값 | 이유 |
|---|---|---|
| Node Interleaving | Disabled (= NUMA 유지) | 인터리빙을 켜면 NUMA 구조가 사라져 NIC 로컬 노드에 프로세스를 고정할 수 없다. RDMA는 NIC-메모리 지역성이 성능을 좌우한다 |
| Sub-NUMA Clustering (SNC) / NPS | 대개 끄거나 NPS1. 정교하게 핀 고정할 자신이 있으면 세분화 | 노드를 잘게 쪼개면 정렬이 어긋났을 때 손해가 크다 |
| IOMMU (VT-d / AMD-Vi) | SR-IOV나 컨테이너 격리가 필요하면 Enabled, 순수 베어메탈이면 성능상 pass-through | 활성 시 커널 파라미터에 iommu=pt 를 주면 DMA 변환 오버헤드를 줄일 수 있다 |
| SR-IOV | VF를 컨테이너·VM에 붙일 거면 Enabled | 쿠버네티스에서 RDMA를 쓰려면 보통 SR-IOV VF + device plugin 조합. 9.6 참고 |
| DDIO (Intel Data Direct I/O) / DCA | Enabled | NIC의 DMA 데이터를 DRAM이 아니라 LLC에 직접 넣어 지연을 줄인다. 다만 LLC를 잠식하므로 워크로드에 따라 확인 |
| Secure Boot | 서명 안 된 OFED 커널 모듈을 쓸 거면 걸림돌 | 필요하면 모듈에 서명하거나 Secure Boot를 끈다 |
|
|
NIC이 NUMA 0에 붙어 있는데 프로세스가 NUMA 1에서 돌면, 모든 DMA가 소켓 간 링크(UPI/Infinity Fabric)를 건너간다. 대역폭이 눈에 띄게 떨어지고 지연 편차가 커진다. GPU가 여럿인 노드에서는 GPU-NIC-CPU를 한 세트로 묶어 배치하는 게 정석이다.
|
|
show_gids 결과에서 v2로 표시된 항목의 인덱스를 애플리케이션이나 벤치마크에 넘겨야 한다. v1 인덱스를 쓰면 L3를 못 넘어 다른 랙과 통신이 안 된다.
L2 PCP가 아니라 DSCP trust를 권장한다. L3 라우팅을 넘어가도 마킹이 살아남기 때문이다. RoCE v2를 쓰는 이유 자체가 라우팅 가능성인데 L2 마킹을 쓰면 앞뒤가 안 맞는다.
관례적으로 이렇게 나눈다.
| 트래픽 | DSCP | Priority / TC | 큐 성격 |
|---|---|---|---|
| RoCE 데이터 | 26 | 3 | lossless, PFC on |
| CNP | 48 | 6 | strict priority, PFC off |
| 일반 TCP | 0 | 0 | lossy |
|
|
|
|
모든 노드가 송신자이자 수신자이므로 np와 rp를 둘 다 켠다. 세부 튜닝 파라미터는 /sys/class/net/$IFACE/ecn/roce_rp/ 아래에 있다.
| 파라미터 | 의미 |
|---|---|
rpg_ai_rate |
Additive Increase 단계의 증가폭 (Mbps) |
rpg_hai_rate |
Hyper Increase 단계의 증가폭 |
rpg_threshold |
다음 회복 단계로 넘어가기 위한 조건 횟수 |
rpg_min_rate |
감소의 하한. 너무 낮으면 회복이 느려진다 |
initial_alpha_value |
감소 비율을 결정하는 alpha 초기값 |
clamp_tgt_rate |
CNP 수신 시 target rate까지 같이 낮출지 여부 |
기본값이 대체로 무난하다. 대규모 incast(다대일 집중)에서 문제가 생길 때만 손대는 게 좋다.
MTU(Maximum Transmission Unit)는 한 번에 보낼 수 있는 최대 크기다. 이더넷 MTU와 RoCE가 쓰는 IB MTU는 별개 값이라 둘 다 확인해야 한다.
|
|
경로상 한 곳이라도 MTU가 작으면 그 값으로 떨어지거나 통신이 끊긴다. 스위치 MTU는 9216 정도로 넉넉히 잡는다.
포트를 여러 개 묶는 이야기다. 부르는 이름이 여럿인데 같은 것을 가리킨다. 서버 쪽에서는 본딩(bond0 같은 인터페이스), 스위치 쪽에서는 LAG(Link Aggregation Group), 양쪽이 협상하는 프로토콜은 LACP(802.3ad)다.
여기에 RoCE의 함정이 둘 있다.
첫째, 일반 본딩으로는 RDMA가 안 탄다. 본딩은 커널의 netdev 계층에서 동작하는데 RDMA는 그 계층을 통째로 건너뛴다. 평소처럼 bond0 를 만들어놓아도 RDMA 트래픽은 본딩을 인지하지 못한다. NIC 하드웨어가 본딩을 알아야 하고, 그래서 별도 기능이 필요하다.
NVIDIA는 RoCE LAG를 지원하지만 조건이 붙는다.
- 두 포트가 같은 카드 위에 있어야 한다. 카드 두 장을 묶으면 RoCE LAG는 동작하지 않는다
- 지원 모드가 제한적이다 (active-backup, balance-xor, 802.3ad)
- LAG가 걸리면 RDMA 디바이스 이름이
mlx5_bond_0형태로 바뀐다.NCCL_IB_HCA와 GID index를 다시 잡아야 한다
Broadcom bnxt_re 는 지원 범위가 드라이버 버전마다 다르므로 문서를 먼저 확인해야 한다.
둘째, LAG는 기대만큼 빨라지지 않는다. 10.5의 ECMP 편중과 같은 원리다. LAG는 flow 단위로 해시해 포트를 고르는데, RDMA는 flow 개수가 적고 QP 하나가 수십 Gbps를 혼자 쓴다.
flowchart LR
subgraph LAG["본딩 / LAG · 단일 QP는 포트 하나만 탄다"]
direction LR
Q["QP 하나"] --> B["bond0<br/>flow 해시로 포트 선택"]
B --> P1["포트 1<br/>100G 포화"]
B -.->|"안 씀"| P2["포트 2<br/>유휴"]
end
style P1 fill:#fdeaea,stroke:#e05656,color:#0f172a
style P2 fill:#f1f5f9,stroke:#94a3b8,color:#0f172a
100G 두 개를 묶어도 단일 연결 최대 처리량은 여전히 100G다. 그래서 GPU 클러스터에서는 본딩 대신 멀티레일을 쓴다. NIC마다 별도 서브넷을 주고 NCCL이 여러 NIC을 동시에 병렬로 쓰게 하는 방식이다.
flowchart LR
subgraph RAIL["멀티레일 · NIC마다 독립 경로"]
direction LR
N["NCCL"] --> R1["NIC 1 · 서브넷 A"]
N --> R2["NIC 2 · 서브넷 B"]
N --> R3["NIC 3 · 서브넷 C"]
N --> R4["NIC 4 · 서브넷 D"]
end
style N fill:#cfe0f9,stroke:#2563eb,color:#0f172a
style R1 fill:#e7f6ec,stroke:#22a15d,color:#0f172a
style R2 fill:#e7f6ec,stroke:#22a15d,color:#0f172a
style R3 fill:#e7f6ec,stroke:#22a15d,color:#0f172a
style R4 fill:#e7f6ec,stroke:#22a15d,color:#0f172a
| 본딩 / LAG | 멀티레일 | |
|---|---|---|
| 구성 | 논리 인터페이스 1개 | NIC마다 독립 |
| 단일 QP 처리량 | 포트 1개 속도 | 해당 없음 (여러 QP로 분산) |
| 합산 대역폭 | 해시 편중으로 손해 | 잘 나온다 |
| 이중화 | 자동 | 앱·라이브러리가 처리 |
| GPU 학습 | 잘 쓰지 않는다 | 표준 |
이중화가 목적이면 본딩, 대역폭이 목적이면 멀티레일이다. 둘을 섞어 쓰려다 RoCE LAG 조건에 걸려 시간을 버리는 경우가 많다.
멀티레일을 쓴다면 8.4의 NUMA 정렬을 NIC마다 해야 한다. GPU와 NIC을 같은 PCIe 스위치 아래로 짝지어 배치하고, NCCL에 사용할 디바이스를 명시한다.
|
|
파드 안에서 RDMA를 쓰려면 호스트의 RDMA 장치에 접근해야 하는데, 그냥 되지 않는다. 방식은 둘이다.
| 방식 | 특징 | 필요한 것 |
|---|---|---|
| SR-IOV | 물리 NIC을 VF로 쪼개 파드마다 전용 NIC을 준다. 격리가 강하다 | BIOS의 SR-IOV·IOMMU 활성, SR-IOV Network Device Plugin, Multus CNI, SR-IOV CNI |
| RDMA shared device plugin | 호스트의 물리 장치를 파드들이 공유한다. 구성이 단순하다 | RDMA device plugin |
파드 스펙에는 리소스로 선언한다.
|
|
자주 걸리는 함정 세 가지가 있다.
1. memlock 한계. 가장 흔하다. RDMA는 메모리를 pin 해야 하는데 컨테이너 기본 memlock 한계가 64KB라 ibv_reg_mr 이 “Cannot allocate memory” 로 실패한다.
|
|
IPC_LOCK 권한과 memlock ulimit 상향이 둘 다 필요하다.
2. VF는 PF의 QoS 설정을 물려받지 않는다. 호스트에서 trust dscp, PFC, ECN을 다 잡아놨어도 VF에는 별도로 적용해야 하는 경우가 있다. 이걸 놓치면 컨테이너 트래픽만 lossless 큐를 타지 못하고, 6.5에서 말한 조용히 무너지는 상황이 그대로 재현된다. 컨테이너 환경에서 특히 놓치기 쉬운 지점이다.
3. GPUDirect까지 쓰면 더 복잡하다. 드라이버, nvidia-peermem, device plugin, 토폴로지 인식이 전부 맞아야 한다. 수동으로 맞추기보다 NVIDIA Network Operator와 GPU Operator를 쓰는 편이 낫다. SR-IOV 구성과 드라이버 설치까지 함께 처리해준다.
sysfs 설정은 재부팅하면 날아간다. systemd 유닛이나 udev 룰로 고정한다.
|
|
노드가 수십 대를 넘어가면 Ansible이나 부팅 이미지에 넣어 전 노드 동일성을 보장하는 게 중요하다. 앞서 본 것처럼 한 대만 달라도 전체가 영향을 받는다.
벤더마다 문법은 다르지만 만져야 하는 항목은 동일하다.
flowchart TD
A["1. Trust DSCP<br/>서버가 찍은 마킹을 신뢰"] --> B["2. DSCP → Traffic Class 매핑<br/>26→TC3, 48→TC6"]
B --> C["3. TC3에 PFC 활성<br/>lossless 큐 지정"]
C --> D["4. 버퍼 / headroom 할당<br/>케이블 길이 반영"]
D --> E["5. TC3에 ECN/WRED 임계치"]
E --> F["6. TC6를 strict priority로<br/>PFC는 걸지 않음"]
F --> G["7. MTU 9216"]
G --> H["8. PFC Watchdog 활성"]
H --> I["9. ECMP 해시에<br/>UDP src port 포함"]
| 항목 | 왜 필요한가 | 빠뜨리면 |
|---|---|---|
| Trust DSCP | 기본값은 마킹을 못 믿고 0으로 덮어쓰는 경우가 많다 | 모든 RoCE 트래픽이 기본 큐로 떨어져 PFC/ECN이 전부 무의미해진다 |
| DSCP → TC 매핑 | 스위치 내부 큐로 연결하는 고리 | 마킹은 살아 있는데 lossless 큐로 안 들어간다 |
| PFC on TC3 | 무손실 보장 | 버퍼 넘칠 때 드롭 → go-back-N 폭발 |
| 버퍼·headroom | PAUSE 반응 시간 동안의 in-flight 흡수 | PFC를 켜도 드롭이 난다 |
| ECN/WRED | 근본적인 혼잡 제어. 임계치는 PFC XOFF보다 낮게(6.5 참고) | PFC만으로 버티다 storm 발생 |
| CNP 큐 strict priority | 혼잡 신호 보호 | 제어 루프가 늦어져 진동 발생 |
| MTU 9216 | 점보 프레임 통과 | 조각화 또는 드롭 |
| PFC Watchdog | deadlock 방지 | 순환 대기 시 fabric 전체 마비 |
| ECMP 해시 | 다중 경로 활용 | 특정 링크에만 몰려 폴라라이제이션 발생 |
|
|
Cumulus의 qos roce 프로파일은 위 항목들을 검증된 조합으로 묶어준다. 직접 하나하나 잡기보다 벤더 검증 프로파일에서 출발하는 것을 권한다.
! DSCP 신뢰 및 매핑
qos map dscp 26 to traffic-class 3
qos map dscp 48 to traffic-class 6
qos map traffic-class 3 to tx-queue 3
qos map traffic-class 6 to tx-queue 6
interface Ethernet1
qos trust dscp
mtu 9214
priority-flow-control on
priority-flow-control priority 3 no-drop
priority-flow-control watchdog action errdisable
!
! ECN 임계치
policy-map type qos ROCE
class tx-queue 3
random-detect ecn minimum-threshold 150 kbytes maximum-threshold 1500 kbytes
!
! CNP는 strict priority
tx-queue 6
priority strict
! lossless 클래스 정의
class-map type qos match-all ROCE
match dscp 26
class-map type qos match-all CNP
match dscp 48
policy-map type qos ROCE-CLASSIFY
class ROCE
set qos-group 3
class CNP
set qos-group 6
! 네트워크 QoS: no-drop 지정
class-map type network-qos ROCE-NQ
match qos-group 3
policy-map type network-qos ROCE-NQ-POLICY
class type network-qos ROCE-NQ
pause pfc-cos 3
mtu 9216
! 큐잉 및 ECN
policy-map type queuing ROCE-OUT
class type queuing c-out-8q-q3
bandwidth remaining percent 80
random-detect minimum-threshold 150 kbytes maximum-threshold 1500 kbytes ecn
class type queuing c-out-8q-q6
priority level 1
interface Ethernet1/1
priority-flow-control mode on
service-policy type qos input ROCE-CLASSIFY
! PFC watchdog
priority-flow-control watch-dog-interval on
RoCE는 flow 개수가 적다. GPU 8개짜리 노드 두 대가 통신하면 flow가 몇 개 안 되는데 각각이 수십 Gbps다. 이때 ECMP 해시가 겹치면 특정 링크만 포화되고 나머지는 논다.
flowchart TB
subgraph BAD["해시 편중"]
B1["flow A"] --> BL1["Link 1<br/>포화"]
B2["flow B"] --> BL1
B3["flow C"] --> BL1
BL2["Link 2<br/>유휴"]
BL3["Link 3<br/>유휴"]
end
subgraph GOOD["엔트로피 확보"]
G1["flow A"] --> GL1["Link 1"]
G2["flow B"] --> GL2["Link 2"]
G3["flow C"] --> GL3["Link 3"]
end
style BL1 fill:#fdeaea,stroke:#e05656,color:#0f172a
대응 방법은 셋이다.
- UDP source port 엔트로피: RoCE는 QP마다 src port를 다르게 계산한다. 스위치 ECMP 해시에 L4 포트를 반드시 포함시킨다
- QP 개수 늘리기: NCCL의
NCCL_IB_QPS_PER_CONNECTION을 올려 flow를 인위적으로 늘린다 - Adaptive Routing: 스위치가 링크 부하를 보고 동적으로 경로를 바꾼다. InfiniBand와 NVIDIA Spectrum-X가 지원한다
포트 설정을 아무리 잘해도 토폴로지가 잘못되면 회복할 수 없다. 설계 단계에서 정해지는 것이라 나중에 손대기가 가장 어렵다.
수렴비 (oversubscription ratio)
leaf 스위치에서 서버로 내려가는 대역폭과 spine으로 올라가는 대역폭의 비율이다.
|
|
일반 웹 서비스라면 3:1이나 4:1이 흔하다. 트래픽이 대부분 랙 안에서 끝나고 동시에 몰리지 않기 때문이다.
분산 학습은 다르다. all-reduce는 모든 노드가 동시에 랙을 넘어 통신한다. 수렴비가 곧 성능 상한이 된다. 4:1이면 노드 간 실효 대역폭이 1/4로 떨어지고, 동기화 장벽 때문에 그 손해가 매 스텝 누적된다.
GPU 학습 패브릭은 1:1 비수렴(non-blocking)이 기본 목표다. 여기서 아끼면 GPU가 노는 시간으로 되돌아온다.
레일 최적화 (rails-optimized) 구성
GPU 8장 노드에 NIC이 8장 있다고 하자. 배선 방법이 둘이다.
flowchart TB
subgraph TRAD["전통적 배선 · 노드의 NIC들이 같은 leaf로"]
direction LR
T1["노드 1의 NIC 1~8"] --> TL1["Leaf 1"]
T2["노드 2의 NIC 1~8"] --> TL2["Leaf 2"]
TL1 --> TS["Spine"]
TL2 --> TS
end
style TS fill:#f1f5f9,stroke:#94a3b8,color:#0f172a
flowchart TB
subgraph RAILS["레일 최적화 · 같은 번호 NIC끼리 같은 leaf로"]
direction LR
R1["모든 노드의 NIC 1"] --> RL1["Leaf 1 · 레일 1"]
R2["모든 노드의 NIC 2"] --> RL2["Leaf 2 · 레일 2"]
R3["모든 노드의 NIC 8"] --> RL8["Leaf 8 · 레일 8"]
end
style RL1 fill:#e7f6ec,stroke:#22a15d,color:#0f172a
style RL2 fill:#e7f6ec,stroke:#22a15d,color:#0f172a
style RL8 fill:#e7f6ec,stroke:#22a15d,color:#0f172a
레일 최적화의 이점은 all-reduce 트래픽이 spine을 안 거친다는 것이다. GPU 0끼리, GPU 1끼리 통신하는 게 집합 통신의 주된 패턴인데, 같은 번호 GPU가 전부 같은 leaf에 붙어 있으면 leaf 안에서 끝난다.
| 전통적 배선 | 레일 최적화 | |
|---|---|---|
| 같은 번호 GPU 간 통신 | leaf → spine → leaf | leaf 하나만 거침 |
| spine 부하 | 높다 | 크게 줄어든다 |
| 홉 수 | 3홉 | 1홉 |
| 배선 복잡도 | 단순 | 규칙을 지켜야 한다 |
홉이 줄면 지연도 줄고, 5.3에서 본 PAUSE 전파 구간도 짧아진다. 혼잡이 spine까지 번질 일이 줄어드는 것이다.
버퍼 용량도 설계 항목이다
스위치 칩마다 포트당 버퍼가 다르다. 얕은 버퍼(shallow buffer) 칩은 단가가 싸지만 incast에서 금방 XOFF 임계치에 닿아 PFC가 자주 발동한다. 5.4의 headroom도 이 버퍼에서 떼어 쓴다. GPU 패브릭용 스위치를 고를 때 포트 수와 속도만 보지 말고 버퍼 용량을 같이 봐야 한다.
flowchart TD
A["링크가 올라왔나?<br/>ibv_devinfo state=PORT_ACTIVE"] -->|No| A1["케이블·트랜시버·드라이버 확인"]
A -->|Yes| B["RoCE v2 GID가 있나?<br/>show_gids"]
B -->|No| B1["RoCE 모드·IP 설정 확인"]
B -->|Yes| C["단순 통신이 되나?<br/>ib_write_bw"]
C -->|No| C1["방화벽 UDP 4791<br/>MTU 불일치 확인"]
C -->|Yes| D["대역폭이 회선 속도에 근접하나?"]
D -->|No| D1["PCIe 설정·NUMA 정렬<br/>MTU 확인"]
D -->|Yes| E["다중 노드에서도 유지되나?"]
E -->|No| E1["PAUSE·CNP 카운터 확인<br/>스위치 QoS 점검"]
E -->|Yes| F["정상"]
style F fill:#e7f6ec,stroke:#22a15d,color:#0f172a
|
|
측정은 했는데 합격인지 미달인지 모르면 소용이 없다. 100G 링크 기준 대략의 기대치는 이렇다.
| 측정 | 정상 범위 | 이 아래면 |
|---|---|---|
ib_write_bw (대용량 메시지) |
90~97 Gbps | 아래 진단표 참고 |
ib_send_lat (왕복 절반) |
2~4 μs (IB는 1~2 μs) | C-state, ASPM, NUMA 의심 |
all_reduce_perf busbw (노드당 100G 1장) |
85~95 Gbps | NCCL이 RDMA를 안 타는지부터 확인 |
이더넷 인코딩과 헤더 오버헤드가 있어 100G에서 100 Gbps는 나오지 않는다. 97 Gbps면 사실상 라인레이트로 봐도 된다.
all_reduce_perf 결과에서는 algbw가 아니라 busbw를 봐야 한다. algbw는 노드 수에 따라 달라지지만 busbw는 실제 링크 사용률을 나타내므로 회선 속도와 직접 비교할 수 있다.
숫자가 낮을 때 의심 순서
| 관측 | 유력한 원인 |
|---|---|
| 절반 정도 (100G에서 ~50) | PCIe 슬롯이 x8. lspci -vv 로 LnkSta 확인. 또는 PCIe Gen3에 듀얼포트 100G |
| 70~80% | NUMA 미정렬. 8.4대로 NIC과 프로세스를 같은 노드에 고정 |
| 대역폭은 나오는데 지연이 튄다 | C-state, ASPM, 주파수 스케일링. 8.2 확인 |
| 작은 메시지만 느리다 | 정상이다. 소메시지는 지연 지배 구간이라 대역폭이 안 나온다 |
| 노드를 늘리면 급락 | 이 글의 주제다. PFC·ECN 설정 누락 구간을 찾아야 한다 |
NET/Socket 로그 |
RDMA를 아예 안 타고 있다. NCCL_IB_HCA, GID index 확인 |
설치 시점의 숫자를 기록해두는 것이 중요하다. 위 범위는 일반론이고, 실제 판단 기준은 정상 상태에서 측정한 본인 환경의 값이다. 나중에 성능이 이상할 때 비교할 대상이 없으면 원인을 좁힐 수 없다.
|
|
|
|
| 증상 | 해석 | 조치 |
|---|---|---|
tx_prio3_pause 급증 |
내 NIC이 계속 PAUSE를 보냄. 수신 버퍼가 못 따라감 | 수신 측 처리 능력, PCIe 대역폭, DCQCN 동작 확인 |
rx_prio3_pause 급증 |
상류에서 PAUSE를 받고 있음. fabric 혼잡 | 스위치 ECN 임계치 조정, incast 패턴 완화 |
np_cnp_sent = 0 인데 PAUSE는 발생 |
수신 측 ECN(np)이 꺼져 있음 | roce_np/enable/3 확인 |
rp_cnp_ignored 증가 |
송신 측이 CNP를 무시. rp 설정 문제이거나 DSCP 불일치 | roce_rp/enable/3, CNP DSCP 매핑 확인 |
out_of_buffer 증가 |
RECV WQE 부족 (RNR) | 애플리케이션의 수신 큐 깊이 확대 |
packet_seq_err 증가 |
패킷 손실 발생 = 무손실 실패 | PFC 설정 누락 구간, headroom 부족 추적 |
local_ack_timeout 증가 |
ACK 미수신. 심각한 혼잡이나 경로 문제 | 경로 전체 점검 |
가장 흔한 실수 순위는 이렇다.
- 스위치가
trust dscp가 아니어서 마킹이 덮어써짐 - 특정 노드에서 ECN np/rp 설정 누락
- MTU 불일치 (서버는 9000인데 스위치 일부가 1500)
- 글로벌 PAUSE와 PFC를 동시에 켬
- GID 인덱스를 v1으로 잡아 L3를 못 넘음
- NUMA 미정렬로 대역폭이 절반만 나옴
- 방화벽에서 UDP 4791 차단
케이블이 빠지거나 스위치가 재부팅되면 RDMA 연결은 어떻게 되는가. 운영에 들어가면 반드시 겪는데, 동작이 TCP와 많이 다르다.
먼저 QP가 버티는 구간이 있다
링크가 잠깐 끊겨도 바로 죽지는 않는다. RC QP에는 타임아웃과 재시도 횟수가 설정되어 있고, 그 안에 복구되면 통신이 이어진다.
| 파라미터 | 의미 |
|---|---|
qp_timeout |
ACK를 기다리는 시간. 실제 시간은 4.096μs × 2^timeout |
retry_cnt |
타임아웃 시 재시도 횟수. 최대 7 |
rnr_retry |
수신 측이 준비 안 됐을 때(RNR) 재시도 횟수 |
이 값을 넘기면 QP가 ERR 상태로 떨어진다. 2.3의 상태 머신에서 봤듯 ERR에서는 복구 경로가 없다. RESET으로 내렸다가 INIT부터 다시 올려야 한다.
여기가 TCP와 결정적으로 다른 지점이다. TCP는 커널이 알아서 재전송하고 연결을 유지하지만, RDMA는 QP가 죽으면 애플리케이션이 직접 다시 만들어야 한다. 커널이 대신 해주지 않는다.
그래서 워크로드마다 결과가 갈린다
| 워크로드 | 장애 시 동작 |
|---|---|
| NCCL 분산 학습 | 작업이 죽는다. NCCL은 통신 에러에서 복구하지 않고 communicator를 abort한다. 링크 플랩 한 번에 학습 잡 전체가 날아간다 |
| NVMe-oF | 자동 재연결한다. nvme-rdma 에 재연결 로직이 있어 잠깐의 장애는 넘긴다 |
| 직접 만든 verbs 앱 | 만든 사람이 처리한 만큼만 복구된다 |
NVMe-oF 쪽 재연결 파라미터는 이렇다.
|
|
ctrl_loss_tmo 안에 복구되면 I/O가 이어지고, 넘기면 장치가 사라진다. 기본값이 상황에 안 맞는 경우가 많으니 확인해두는 게 좋다.
학습 잡이 죽는다는 게 실무에서 뜻하는 것
링크 플랩 한 번이 며칠짜리 학습을 날릴 수 있다는 뜻이다. GPU 패브릭의 안정성을 그렇게까지 따지는 이유가 여기 있다. 대응은 둘뿐이다.
- 체크포인트 주기를 짧게 가져간다. 복구 비용의 상한을 정하는 유일한 수단이다
- 패브릭에서 플랩이 안 나게 한다. 트랜시버 품질, 케이블 체결 상태, 펌웨어 버전, 그리고 5.6의 PFC deadlock까지
유지보수 시 주의
스위치 한 대를 내리면 그 경로의 QP가 전부 ERR로 떨어지고, 학습 잡은 죽는다. 무중단 교체를 기대하기 어렵다는 뜻이다. 패브릭 작업은 잡이 없는 시간에 잡는 것을 전제로 계획해야 한다. ECMP로 경로가 여러 개 있어도 QP는 이미 맺어진 경로에 묶여 있어서 자동으로 옮겨가지 않는다.
|
|
local_ack_timeout 이 올라가고 있다면 아직 QP가 죽지는 않았지만 재시도로 버티는 중이라는 뜻이다. 장애가 터지기 전에 잡을 수 있는 신호다.
RDMA에서 한 발 더 나가, GPU 메모리와 NIC을 직접 연결하는 기술이다.
flowchart TB
subgraph NOGDR["GPUDirect 없이"]
W1["GPU 메모리"] -->|"1. cudaMemcpy"| W2["호스트 메모리"] -->|"2. RDMA"| W3["NIC"] --> W4["네트워크"]
W5["복사 1회 + CPU 개입 + 지연 증가"]
end
subgraph GDR["GPUDirect RDMA"]
V1["GPU 메모리"] -->|"PCIe P2P DMA"| V2["NIC"] --> V3["네트워크"]
V4["호스트 메모리 미경유. CPU 미개입"]
end
style W5 fill:#fdeaea,stroke:#e05656,color:#0f172a
style V4 fill:#e7f6ec,stroke:#22a15d,color:#0f172a
전제 조건이 여럿이다.
- BIOS: Above 4G Decoding 활성, ACS 비활성, Large BAR 활성
- 커널 모듈:
nvidia-peermem로드 (또는 최신 스택의 DMABUF 경로) - 토폴로지: GPU와 NIC이 같은 PCIe 스위치 아래(
nvidia-smi topo -m에서 PIX/PXB)에 있어야 효과가 크다. SYS면 CPU를 경유해 이점이 줄어든다 - NIC: RDMA 지원 카드
|
|
RDMA 위에서 실제로 도는 건 대부분 NCCL이다. 자주 쓰는 값들.
| 변수 | 용도 |
|---|---|
NCCL_DEBUG=INFO |
어떤 경로를 쓰는지 로그로 확인. 가장 먼저 켜볼 것 |
NCCL_IB_HCA=mlx5_0,mlx5_1 |
사용할 RDMA 디바이스 지정 |
NCCL_IB_GID_INDEX=3 |
RoCE v2 GID 인덱스 지정. RoCE에서 거의 필수 |
NCCL_IB_TC=106 |
RDMA 트래픽의 ToS(DSCP 26). QoS 매핑과 맞춰야 함 |
NCCL_IB_SL=3 |
Service Level |
NCCL_IB_QPS_PER_CONNECTION |
연결당 QP 수. ECMP 분산 개선에 사용 |
NCCL_SOCKET_IFNAME |
부트스트랩용 소켓 인터페이스 지정 |
NCCL_NET_GDR_LEVEL |
GPUDirect 사용 조건 강제 |
NCCL_IB_GID_INDEX 와 NCCL_IB_TC 를 안 맞춰주면, QoS를 아무리 정성껏 설정해도 NCCL 트래픽이 기본 큐로 흘러 lossless 큐를 못 탄다. 실무에서 정말 자주 놓치는 지점이다.
결론부터: 아니다. RoCE는 RDMA 전송 엔진을 하드웨어로 구현한 특수한 NIC에서만 된다. 일반 서버 온보드 NIC이나 기본형 이더넷 카드로는 안 된다.
flowchart TD
A["보유한 NIC"] --> B{"RDMA 엔진 탑재?"}
B -->|No| C["RoCE 불가<br/>Realtek, Intel i350/X540,<br/>기본형 온보드 NIC 등"]
B -->|Yes| D{"어떤 프로토콜?"}
D -->|"RoCE v2"| E["NVIDIA ConnectX-4 이상<br/>Broadcom NetXtreme-E<br/>Intel E810<br/>Marvell FastLinQ"]
D -->|"iWARP만"| F["Chelsio T5/T6<br/>Intel X722"]
E --> G{"펌웨어·드라이버·<br/>라이선스 확인"}
G --> H["사용 가능"]
style C fill:#fdeaea,stroke:#e05656,color:#0f172a
style H fill:#e7f6ec,stroke:#22a15d,color:#0f172a
| 벤더·제품군 | RoCE v2 | 비고 |
|---|---|---|
| NVIDIA ConnectX-4 / 5 / 6 / 7 / 8 | O | 사실상 표준. 생태계·문서·NCCL 최적화가 압도적. ConnectX-3 Pro는 RoCE v2 지원하나 구세대 |
| NVIDIA BlueField DPU | O | ConnectX 기능 포함 + 오프로드 |
| Broadcom NetXtreme-E (BCM574xx, Thor 등) | O | 지원하지만 펌웨어 설정과 라이선스 확인 필요. 클라우드 벤더가 많이 씀 |
| Intel E810 (Columbiaville) | O | irdma 드라이버로 RoCE v2와 iWARP 둘 다 지원. NVM 버전 확인 필요 |
| Intel X722 | X | iWARP만 |
| Intel X710 / XL710 / X540 / i350 | X | RDMA 미지원 |
| Marvell(QLogic) FastLinQ 41000/45000 | O | RoCE와 iWARP 동시 지원 |
| Chelsio T5 / T6 | X | iWARP 전용 |
| 일반 온보드 1G/10G NIC, Realtek 등 | X | 논외 |
이 표는 칩 기준이다. 실제로 구매하는 카드는 대개 서버 제조사의 OEM 모델이라, 모델명을 칩으로 환산하는 단계가 한 번 더 필요하다.
Supermicro AOC, Dell, HPE, Lenovo 모두 같은 칩을 자기 이름으로 판다. 모델명만 보고는 알 수 없고, 안에 든 칩을 찾아 13.1 표와 대조해야 한다. Supermicro의 AOC-A100G-b2CG 를 예로 풀어본다.
|
|
| 항목 | 내용 |
|---|---|
| 컨트롤러 | Broadcom BCM57508 (코드명 Thor) |
| 포트 | 2 x 100GbE QSFP28 |
| PCIe | Gen4 x16 |
| RDMA | RoCE v1 / v2 지원 |
| DCB | DCBX, PFC 지원 |
| 폼팩터 | AIOM (OCP 3.0 계열) |
칩이 BCM57508이므로 13.1 표의 Broadcom NetXtreme-E 행에 해당하고, RoCE v2를 지원한다. 참고로 끝자리만 다른 b2CM 은 표준 브래킷 버전이고 칩과 기능은 같다.
다만 그 행의 비고대로 확인할 것이 둘 있다.
첫째, NVRAM에서 RDMA가 켜져 있어야 한다. Broadcom 카드는 기본값으로 꺼져 있는 경우가 있다.
|
|
둘째, 드라이버가 짝으로 필요하다. bnxt_re(RDMA)는 bnxt_en(이더넷)에 의존하며, RoCE가 활성화된 버전이어야 한다.
|
|
주의할 점이 하나 더 있다. 9장의 설정 명령은 이 카드에 쓸 수 없다. mlnx_qos, /sys/class/net/*/ecn/roce_*, cma_roce_tos 는 전부 NVIDIA 전용이다. 개념(DSCP 26과 priority 3, CNP는 DSCP 48, ECN 임계치)은 그대로지만 도구가 다르다.
| 용도 | NVIDIA | Broadcom |
|---|---|---|
| QoS·PFC 설정 | mlnx_qos |
niccli, lldpad/DCB |
| 펌웨어·NVRAM | mlxconfig |
bnxtnvm, niccli |
| 혼잡 제어 설정 | /sys/.../ecn/roce_rp |
Broadcom 제공 bnxt_setupcc.sh |
용도가 NVMe-oF나 일반 데이터센터 패브릭이면 이 카드로 충분하다. 다만 대규모 GPU 학습 패브릭이라면 13.3에서 말하듯 NCCL 최적화와 트러블슈팅 사례가 NVIDIA 쪽에 훨씬 많다는 점을 감안해야 한다.
- 25GbE 이상의 데이터센터급 NIC이라면 지원할 가능성이 높다
- 10GbE 이하나 온보드 NIC이면 대체로 안 된다
- 다만 칩이 지원해도 펌웨어 버전, 드라이버, 라이선스가 걸릴 수 있다. Broadcom 일부 모델은 RoCE 기능이 별도 라이선스로 잠겨 있다
- GPU 학습 클러스터를 새로 구성한다면 사실상 NVIDIA ConnectX 계열이 기본 선택지다. 성능 때문만이 아니라 NCCL 최적화, 문서, 트러블슈팅 사례가 압도적으로 많아서다
|
|
/sys/class/infiniband/ 가 비어 있으면 그 서버에는 RDMA 가능한 카드가 없거나 드라이버가 안 올라온 것이다.
| 클라우드 | RDMA 제공 방식 |
|---|---|
| AWS | 일반 ENA는 RDMA 미지원. EFA가 별도로 있으나 RoCE가 아니라 SRD라는 자체 프로토콜. 손실 허용 + 다중경로라 PFC가 필요 없다. libfabric 으로 접근 |
| Azure | HPC/GPU SKU(HB, ND 시리즈 등)에 InfiniBand를 직접 제공. verbs 그대로 사용 가능 |
| GCP | A3/A4 등 GPU 인스턴스에서 GPUDirect-TCPX/TCPXO 및 RDMA 옵션 제공 |
| 국내 CSP | 제공 여부가 상품별로 갈리므로 개별 확인 필요 |
클라우드에서는 PFC 튜닝을 내가 하지 않는다는 게 큰 차이다. 그 대신 프로토콜 선택권도 없다.
PFC 튜닝이 워낙 고통스럽다 보니 업계는 반대 방향으로 움직이고 있다.
timeline
title RDMA 이더넷의 진화
2010년대 초 : RoCE v1 : L2 한정, 확장성 없음
2014 : RoCE v2 : IP 라우팅 가능 : 하지만 PFC 의존
2018 이후 : DCQCN 정착 : PFC + ECN 조합이 표준
2020년대 : AWS SRD : 손실 허용 + 다중경로로 PFC 제거
최근 : Selective Repeat 로 부분 손실 감내 : Spectrum-X 의 Adaptive Routing 과 텔레메트리 기반 제어
진행중 : Ultra Ethernet : 새 전송 계층 표준화
| 방향 | 내용 |
|---|---|
| AWS SRD | RDMA verbs 대신 자체 전송 프로토콜. 순서 무관 전송 + 다중경로라 PFC 자체가 불필요 |
| Selective Repeat | ConnectX-6 이후 세대에서 go-back-N 대신 손실분만 재전송. 약간의 손실을 견딘다 |
| NVIDIA Spectrum-X | adaptive routing과 실시간 텔레메트리 기반 혼잡 제어로 PFC 의존도를 낮춘다 |
| Ultra Ethernet Consortium (UEC) | AI/HPC를 위한 새 이더넷 전송 계층 표준화. 다중경로, 순서 무관 전달, 개선된 혼잡 제어를 목표로 한다 |
즉 “RoCE = PFC 필수”는 클래식한 구성이고, 규모가 커질수록 lossy 기반 설계로 이동하는 중이다. 신규 클러스터를 검토한다면 이 선택지도 같이 봐야 한다.
flowchart LR
R(["RoCE v2"])
R --> C["개념"]
R --> O["객체"]
R --> L["무손실 만들기"]
R --> S["서버"]
R --> W["스위치"]
R --> V["검증"]
C --> C1["Zero-copy<br/>Kernel bypass<br/>Transport offload"]
O --> O1["QP / CQ / WQE<br/>MR / lkey / rkey<br/>PD / GID<br/>one-sided vs two-sided"]
L --> LP["PFC"]
L --> LD["DCQCN"]
LP --> LP1["hop-by-hop<br/>headroom<br/>watchdog"]
LD --> LD1["end-to-end<br/>CP / NP / RP<br/>CNP 보호"]
S --> SB["BIOS"]
S --> SO["OS"]
SB --> SB1["PCIe MPS·MRRS<br/>ASPM off<br/>ACS off<br/>C-state off<br/>NUMA 정렬"]
SO --> SO1["trust dscp<br/>pfc prio3<br/>ecn np 와 rp<br/>MTU 9000<br/>GID index v2"]
W --> W1["trust dscp<br/>DSCP → TC<br/>PFC + 버퍼<br/>WRED ECN<br/>CNP strict priority<br/>ECMP 엔트로피"]
V --> V1["ib_write_bw<br/>pause 카운터<br/>cnp 카운터<br/>packet_seq_err"]
style R fill:#cfe0f9,stroke:#2563eb,color:#0f172a
style C fill:#eaf1fc,stroke:#60a5fa,color:#0f172a
style O fill:#eaf1fc,stroke:#60a5fa,color:#0f172a
style L fill:#eaf1fc,stroke:#60a5fa,color:#0f172a
style S fill:#eaf1fc,stroke:#60a5fa,color:#0f172a
style W fill:#eaf1fc,stroke:#60a5fa,color:#0f172a
style V fill:#eaf1fc,stroke:#60a5fa,color:#0f172a
style LP fill:#dce9fb,stroke:#3b82f6,color:#0f172a
style LD fill:#dce9fb,stroke:#3b82f6,color:#0f172a
style SB fill:#dce9fb,stroke:#3b82f6,color:#0f172a
style SO fill:#dce9fb,stroke:#3b82f6,color:#0f172a
style C1 fill:#f1f5f9,stroke:#94a3b8,color:#0f172a
style O1 fill:#f1f5f9,stroke:#94a3b8,color:#0f172a
style LP1 fill:#f1f5f9,stroke:#94a3b8,color:#0f172a
style LD1 fill:#f1f5f9,stroke:#94a3b8,color:#0f172a
style SB1 fill:#f1f5f9,stroke:#94a3b8,color:#0f172a
style SO1 fill:#f1f5f9,stroke:#94a3b8,color:#0f172a
style W1 fill:#f1f5f9,stroke:#94a3b8,color:#0f172a
style V1 fill:#f1f5f9,stroke:#94a3b8,color:#0f172a
이 글에서 반복해서 나온 문장 세 개만 남긴다면 이렇다.
- RoCE는 네트워크를 무손실로 만들어야 동작한다. 그래서 경로상의 모든 서버와 모든 스위치가 같은 설정을 공유해야 한다. 한 곳만 빠져도 전체가 영향을 받는다
- PFC는 응급처치, DCQCN이 근본 치료다. PAUSE가 상시로 발생한다면 그건 정상 동작이 아니라 DCQCN이 제 역할을 못 한다는 신호다
- 받는 서버는 수동적이지 않다. 혼잡을 감지해 CNP를 되돌리는 게 수신 NIC의 역할이며, 이 설정 하나가 빠지면 클러스터 전체가 느려진다
본문에 나온 약어를 한자리에 모았다. 중간부터 읽더라도 여기만 보면 막히지 않는다.
| 약어 | 원래 이름 | 뜻 |
|---|---|---|
| RDMA | Remote Direct Memory Access | CPU와 커널을 거치지 않고 원격 서버의 메모리를 직접 읽고 쓰는 기술 |
| RoCE | RDMA over Converged Ethernet | 일반 이더넷 위에서 RDMA를 구현한 방식. 발음은 “로키” |
| RRoCE | Routable RoCE | RoCE v2의 다른 이름. IP 라우팅이 되기 때문에 붙은 이름 |
| IB | InfiniBand | 전용 케이블과 스위치를 쓰는 RDMA 전용 네트워크 규격 |
| iWARP | internet Wide Area RDMA Protocol | TCP 위에서 RDMA를 구현한 방식. 손실을 허용해 설정이 쉬운 대신 성능은 낮다 |
| HCA | Host Channel Adapter | InfiniBand 쪽에서 부르는 RDMA 카드 이름 |
| RNIC | RDMA NIC | 이더넷 쪽에서 부르는 RDMA 카드 이름. RDMA 전송 엔진이 하드웨어로 들어가 있다 |
| NIC | Network Interface Card | 네트워크 카드 일반 |
| DPU | Data Processing Unit | NIC 기능에 프로세서와 오프로드 엔진을 얹은 카드. NVIDIA BlueField 등 |
| 약어 | 원래 이름 | 뜻 |
|---|---|---|
| verbs | RDMA API | 소켓 API에 대응하는 RDMA 프로그래밍 인터페이스. libibverbs 로 제공된다 |
| QP | Queue Pair | Send Queue와 Receive Queue의 쌍. 소켓에 해당하는 통신 종단점 |
| QPN | Queue Pair Number | QP를 식별하는 번호. 패킷 헤더에 실려 목적지 QP를 지목한다 |
| CQ / CQE | Completion Queue / Element | 작업 완료를 알리는 큐와 그 항목 |
| WQE / WR | Work Queue Element / Work Request | “이 버퍼를 저기로 보내라” 같은 작업 요청 하나 |
| MR | Memory Region | RDMA용으로 등록(pin)된 메모리 영역 |
| PD | Protection Domain | MR과 QP를 묶는 격리 단위. 다른 PD의 메모리에는 접근할 수 없다 |
| GID | Global Identifier | 128비트 주소. RoCE v2에서는 IP 주소를 매핑해 쓴다 |
| LID | Local Identifier | InfiniBand 서브넷 안의 16비트 지역 주소. RoCE에는 없다 |
| PKey | Partition Key | InfiniBand의 논리 분할. VLAN과 비슷한 역할 |
| SM | Subnet Manager | InfiniBand 서브넷의 주소와 경로를 관리하는 주체 |
| RDMA-CM | RDMA Connection Manager | IP 주소 기반으로 QP 정보를 교환해 연결 수립을 돕는 계층 |
| RC / UC / UD | Reliable Connected / Unreliable Connected / Unreliable Datagram | QP의 전송 타입. RC가 기본이고 대규모에서는 UD를 쓴다 |
| DCT | Dynamically Connected Transport | RC의 신뢰성과 UD의 확장성을 합친 NVIDIA 확장 |
| CAS / FAA | Compare-and-Swap / Fetch-and-Add | 원격 메모리에 원자적으로 수행하는 ATOMIC 연산 |
| IMM | Immediate | WRITE에 4바이트 즉치값을 실어 수신 측에 완료를 알리는 방식 |
| RNR | Receiver Not Ready | 수신 측이 RECV를 올려두지 않아 발생하는 에러 |
| doorbell | 큐에 작업을 넣은 뒤 NIC의 레지스터를 두드려 알리는 동작. 커널을 거치지 않는다 | |
| DMA | Direct Memory Access | CPU를 거치지 않고 장치가 메모리를 직접 읽고 쓰는 것 |
| MMIO | Memory-Mapped I/O | 장치 레지스터를 메모리 주소 공간에 매핑해 접근하는 방식. doorbell이 여기 해당 |
| 약어 | 원래 이름 | 뜻 |
|---|---|---|
| BTH | Base Transport Header | 목적지 QPN, opcode, PSN이 들어가는 RDMA 전송의 핵심 헤더 |
| RETH | RDMA Extended Transport Header | one-sided 연산에만 붙는다. 상대 메모리의 가상주소, rkey, 길이가 담긴다 |
| GRH | Global Route Header | RoCE v1이 쓰던 라우팅 헤더 |
| PSN | Packet Sequence Number | 패킷 순서 번호. 어긋나면 재전송이 발생한다 |
| ICRC | Invariant CRC | RDMA 계층의 무결성 검사값. 이더넷 FCS와 별개다 |
| FCS | Frame Check Sequence | 이더넷 프레임의 오류 검사값 |
| MTU | Maximum Transmission Unit | 한 번에 보낼 수 있는 최대 크기. 이더넷 MTU와 RoCE의 IB MTU는 별개 값이다 |
| ACK | Acknowledgement | 잘 받았다는 응답 |
| 약어 | 원래 이름 | 뜻 |
|---|---|---|
| PFC | Priority Flow Control (IEEE 802.1Qbb) | 우선순위별로 정지 신호를 보내 버퍼 넘침을 막는 흐름 제어 |
| XOFF / XON | 전송을 멈추라는 신호와 다시 시작하라는 신호. 버퍼 점유율 임계치로 판단한다 | |
| ECN | Explicit Congestion Notification | 패킷을 버리는 대신 IP 헤더 비트로 혼잡을 알리는 방식 |
| ECT | ECN-Capable Transport | 이 패킷이 ECN을 지원한다는 표시 |
| CE | Congestion Experienced | 스위치가 혼잡할 때 찍는 ECN 표시값 |
| CNP | Congestion Notification Packet | CE를 본 수신 서버가 송신 서버에게 되돌리는 “속도 줄여” 패킷 |
| DCQCN | Data Center Quantized Congestion Notification | ECN 마킹, CNP 생성, 속도 조절을 묶은 RoCE의 혼잡 제어 알고리즘 |
| QCN | Quantized Congestion Notification (802.1Qau) | DCQCN의 이름이 유래한 이전 세대 혼잡 제어 규격 |
| CP / NP / RP | Congestion / Notification / Reaction Point | 각각 혼잡이 생긴 스위치, CNP를 만드는 수신 NIC, 속도를 낮추는 송신 NIC |
| WRED | Weighted Random Early Detection | 큐 길이에 따라 확률적으로 마킹하거나 버리는 방식. min/max 임계치로 설정한다 |
| DSCP | Differentiated Services Code Point | IP 헤더 ToS 바이트 상위 6비트. 트래픽 등급을 표시하는 마킹 값 |
| ToS | Type of Service | IP 헤더의 1바이트 필드. 상위 6비트가 DSCP, 하위 2비트가 ECN |
| TC | Traffic Class | 스위치 내부에서 트래픽을 나누는 등급. DSCP를 여기에 매핑한다 |
| PCP | Priority Code Point | VLAN 태그 안의 3비트 우선순위. L2 마킹이라 라우팅을 넘으면 사라진다 |
| DCB | Data Center Bridging | 무손실 이더넷을 위한 IEEE 표준 묶음. PFC가 그중 하나다 |
| DCBX | DCB Capability Exchange | LLDP에 얹혀 PFC 설정을 자동 협상하는 프로토콜 |
| CEE | Converged Enhanced Ethernet | DCBX의 표준 제정 이전 방식. IEEE 방식과 호환되지 않는다 |
| LLDP | Link Layer Discovery Protocol | 이웃 장비 정보를 주고받는 L2 프로토콜. DCBX가 여기 실린다 |
| HOL | Head-of-Line blocking | 앞선 하나 때문에 뒤의 전부가 막히는 현상 |
| RTT | Round-Trip Time | 왕복 시간. DCQCN이 반응하는 데 최소 한 번 필요하다 |
| 약어 | 원래 이름 | 뜻 |
|---|---|---|
| MAC | Media Access Control | 이더넷 주소 체계이자 그 처리를 담당하는 계층. PFC 프레임은 여기서 생성·소비된다 |
| PHY | Physical Layer | 전기 신호를 다루는 최하위 계층 |
| L2 / L3 / L4 | Layer 2 / 3 / 4 | 각각 이더넷, IP, TCP·UDP 계층 |
| ECMP | Equal-Cost Multi-Path | 비용이 같은 여러 경로에 트래픽을 해시로 분산시키는 라우팅 |
| SFP28 / QSFP28 | 25G급, 100G급 광 트랜시버 규격 | |
| LAG | Link Aggregation Group | 여러 물리 포트를 하나로 묶는 것. 서버 쪽에서는 본딩(bonding)이라 부른다 |
| LACP | Link Aggregation Control Protocol (802.3ad) | 양쪽이 LAG를 협상하는 프로토콜 |
| 약어 | 원래 이름 | 뜻 |
|---|---|---|
| NUMA | Non-Uniform Memory Access | CPU 소켓마다 가까운 메모리가 다른 구조. NIC과 프로세스를 같은 노드에 붙여야 성능이 난다 |
| SNC | Sub-NUMA Clustering | NUMA 노드를 더 잘게 쪼개는 Intel 기능 |
| NPS | Nodes Per Socket | AMD에서 소켓당 NUMA 노드 수를 정하는 설정 |
| UPI | Ultra Path Interconnect | Intel의 CPU 소켓 간 연결. AMD는 Infinity Fabric |
| PCIe | PCI Express | 확장 카드 연결 규격. NIC과 GPU가 여기 붙는다 |
| MPS | Max Payload Size | PCIe 한 트랜잭션에 실리는 데이터 크기 |
| MRRS | Max Read Request Size | NIC이 호스트 메모리를 한 번에 읽어오는 요청 크기 |
| ASPM | Active State Power Management | PCIe 링크를 저전력 상태로 내리는 기능. 지연이 늘어 RDMA에서는 끈다 |
| ACS | Access Control Services | PCIe 장치 간 직접 통신을 차단하는 보안 기능. GPUDirect를 쓰려면 끈다 |
| BAR | Base Address Register | 장치 메모리를 호스트 주소 공간에 노출하는 창. GPUDirect는 큰 BAR가 필요하다 |
| P2P | Peer-to-Peer | CPU를 거치지 않는 PCIe 장치 간 직접 전송 |
| IOMMU | I/O Memory Management Unit | 장치의 DMA 주소를 변환·격리하는 장치. Intel은 VT-d, AMD는 AMD-Vi |
| SR-IOV | Single Root I/O Virtualization | 물리 NIC 하나를 여러 가상 기능으로 나누는 기술 |
| PF / VF | Physical / Virtual Function | SR-IOV에서 물리 NIC 본체와 거기서 나뉜 가상 NIC. VF는 PF의 QoS 설정을 자동으로 물려받지 않는다 |
| DDIO / DCA | Data Direct I/O / Direct Cache Access | NIC의 DMA 데이터를 DRAM 대신 CPU 캐시에 직접 넣는 기능 |
| NVRAM | Non-Volatile RAM | 카드 설정을 저장하는 비휘발성 영역. Broadcom은 여기서 RDMA를 켠다 |
| 약어 | 원래 이름 | 뜻 |
|---|---|---|
| NCCL | NVIDIA Collective Communications Library | GPU 간 집합 통신(all-reduce 등)을 담당하는 라이브러리. 발음은 “니클”. RDMA 위에서 실제 트래픽을 만드는 주체다 |
| OFED | OpenFabrics Enterprise Distribution | RDMA 드라이버와 유틸리티 묶음. NVIDIA는 DOCA-OFED로 배포한다 |
| MPI | Message Passing Interface | HPC의 전통적인 분산 통신 표준 |
| HPC | High Performance Computing | 슈퍼컴퓨터급 과학 계산 분야 |
| GDR | GPUDirect RDMA | GPU 메모리와 NIC을 PCIe로 직접 연결해 호스트 메모리를 거치지 않는 기술 |
| CNI | Container Network Interface | 쿠버네티스의 네트워크 플러그인 규격. RDMA에는 Multus와 SR-IOV CNI를 함께 쓴다 |
| 약어 | 원래 이름 | 뜻 |
|---|---|---|
| NVMe | Non-Volatile Memory Express | PCIe에 직접 붙는 SSD를 다루는 명령 규격 |
| NVMe-oF | NVMe over Fabrics | NVMe 명령을 네트워크 너머로 보내 원격 SSD를 로컬처럼 쓰는 프로토콜 |
| SRD | Scalable Reliable Datagram | AWS EFA가 쓰는 자체 전송 프로토콜. 손실을 허용해 PFC가 필요 없다 |
| EFA | Elastic Fabric Adapter | AWS의 고성능 네트워크 어댑터 |
| UEC | Ultra Ethernet Consortium | AI·HPC를 위한 새 이더넷 전송 계층을 표준화 중인 단체 |
- IBTA, InfiniBand Architecture Specification Vol.1 Annex A17 (RoCEv2)
- Zhu et al., Congestion Control for Large-Scale RDMA Deployments (SIGCOMM 2015) : DCQCN 원논문
- Guo et al., RDMA over Commodity Ethernet at Scale (SIGCOMM 2016) : Microsoft의 대규모 운영 경험. PFC storm과 deadlock 사례가 여기 나온다
- IEEE 802.1Qbb (PFC), RFC 3168 (ECN)
- NVIDIA, RDMA over Converged Ethernet (RoCE) Configuration Guide
- NVIDIA, NCCL User Guide : 환경변수 전체 목록
- Supermicro, AOC-A100G-b2CM / b2CG 데이터시트 : 13.2의 OEM 카드 예시
- Broadcom, NetXtreme-E User Guide 및
bnxt_re드라이버 문서 : Broadcom 계열 RoCE 설정