카테고리 없음

AI Datacenter Network 스터디 1주차 - AI를 위한 네트워크 들여다보기

qtscott 2026. 6. 22. 10:43

AI Datacenter Network Study를 시작했다. 

첫번째 주에는 GPU 사용에 있어서 네트워크가 어떻게 발전했는지와 왜 병목이 되는지 그리고 그걸 해결하기 위한 기술들을 알아봤다.

 

1. 병목은 연산이 아니라 메모리와 데이터를 나르는 통로인 네트워크

지난 10여 년간 GPU의 연산 성능 증가폭은 메모리 대역폭 증가폭을 크게 앞질렀다. 코어는 빨라졌는데 메모리가 데이터를 그 속도로 못 따라가서, 코어가 데이터를 기다리는 상태가 된다. 흔히 말하는 'Memory Wall'이다.

AI 연산의 실제 병목은 GPU 코어의 FLOPS가 아니라, 모델 파라미터와 KV cacheGPU 메모리에서 얼마나 빠르게 읽고 쓰느냐로 결정되는 경우가 많다. GPU가 아무리 많은 FLOPS를 내도 메모리 대역폭이 못 받쳐주면 전체 성능은 Memory Bound 상태에 묶인다.

이게 단일 GPU 안의 문제라면, GPU를 여러 장 묶는 순간 똑같은 문제가 이번엔 네트워크에서 터진다. 큰 모델은 애초에 한 장에 안 들어간다. 2조 파라미터급이면 가중치 + gradient + optimizer 상태로 수십 TB라, 수백~수천 장에 쪼개야 한다. 그리고 쪼개는 방식이 곧 통신 패턴을 결정한다.

  • Data Parallelism — 모델을 모든 GPU에 복제하고 배치를 나눈다. 매 스텝 끝에 GPU마다 다른 gradient를 평균 내야 하는데, 이게 All-Reduce다.
  • Tensor Parallelism — 행렬 곱 하나를 여러 GPU에 쪼갠다. 단계마다 서로를 기다려야 해서 가장 빠른 링크에서만 효율적이다.
  • Pipeline Parallelism — 레이어를 GPU들에 나눠 맡긴다.
  • Expert Parallelism (MoE) — expert를 여러 GPU에 흩뿌린다. all-to-all 통신이 잦아 지연에 민감하다.

어떤 방식을 쓰든 결론은 같다. 쪼개는 순간 GPU들은 끊임없이 서로 통신하고, 그 통신량이 곧 네트워크 부하가 된다. 게다가 GPU 한 장이 느려지면 나머지 수천 장이 같이 멈춰 기다린다. 그래서 분산 학습에서는 "가장 느린 통신 경로"가 전체 속도를 좌우한다.

 

2. 그래서 RDMA, 그리고 InfiniBand

대규모 분산 학습에서는 gradient 동기화, All-Reduce, parameter exchange 같은 GPU 간 통신이 끊임없이 일어난다. 그래서 GPU와 네트워크 카드 사이에서 데이터를 얼마나 효율적으로 옮기느냐가 전체 처리 속도를 크게 좌우한다.

 

일반 TCP/IP로 두 GPU 서버가 통신하면, 데이터가 GPU → Host RAM → user buffer → kernel socket buffer → NIC를 거치고, 받는 쪽에서 같은 과정을 거꾸로 되밟는다. 매 단계가 메모리 복사이거나 커널 처리라, 대역폭을 키워도 CPU가 못 따라온다.

 

RDMA(Remote Direct Memory Access)는 이 경로에서 커널과 CPU 복사를 들어낸다. 한 서버의 NIC가 상대 서버의 미리 등록된 메모리에 직접 읽고 쓴다. 그래서 전송 전에 메모리를 등록(페이지 고정 + 접근 key 발급)해두고, Queue Pair와 Work Request로 통신을 굴린다. CPU는 초기 설정·연결 관리(control path)만 맡고, 반복되는 대용량 전송(data path)에서는 빠진다.

 

GPU 데이터라면 한 단계 더 나아간다. GPUDirect RDMA는 NIC가 GPU의 VRAM에 직접 DMA를 걸어 호스트 RAM 경유까지 없앤다. 그래서 GPU VRAM ↔ NIC ↔ 네트워크 ↔ NIC ↔ GPU VRAM으로 한 번에 간다.

RDMA를 네트워크에 실어 나르는 방식은 여러 가지가 있었지만, 지금은 크게 두 갈래다.

  • InfiniBand — RDMA를 위해 처음부터 설계된 전용 패브릭. 링크 레벨에서 credit 기반 흐름 제어로 무손실이고 저지연이며, SHARP(스위치가 All-Reduce 같은 reduction을 네트워크 안에서 대신 수행) 같은 기능을 받친다. 대신 전용 장비가 필요하다.
  • RoCEv2 — 이더넷 + IP + UDP 위에 InfiniBand의 RDMA transport를 그대로 얹은 방식. 범용 이더넷 장비를 쓸 수 있지만, 손실 가능한 이더넷을 무손실처럼 만들기 위해 PFC / ECN / DCQCN 같은 혼잡 제어를 얹어야 한다.

사내 인프라는 트레이닝에 무게를 두고 더 큰 대역폭과 RDMA에 특화된 InfiniBand로 구성했다. 그래서 이번 스터디도 IB에 조금 더 집중했다. DGX B300은 각 GPU에 ConnectX-8 SuperNIC가 800Gbps(XDR)로 붙고, 이 NIC가 PCIe Gen6로 GPU에 직결된다 — 앞서 말한 GPUDirect RDMA의 물리적 토대다. 그리고 이 NIC들을 Quantum-X800 스위치(포트당 800Gb/s, Quantum-3 ASIC)가 받아낸다.

 

3. 실제로 IB 패브릭 들여다보기

(1) ibstat — 링크들이 살아있는지 확인

$ ibstat mlx5_0
CA 'mlx5_0'
	CA type: MT4131
	Number of ports: 1
	Firmware version: 40.47.2526
	Hardware version: 0
	Node GUID: 0x7425540300c73865
	System image GUID: 0x7425540300c73865
	Port 1:
		State: Active 
		Physical state: LinkUp  
		Rate: 800 
		Base lid: 190 
		LMC: 0
		SM lid: 151
		Capability mask: 0xa751ec48
		Port GUID: 0x7425540300c73865
		Link layer: InfiniBand

CA type: MT4131은 ConnectX-8 NIC가 제대로 잡혔다는 뜻이고, State: Active는 포트가 살아서 Subnet Manager에 등록돼 통신 가능한 상태라는 의미다(Base lid가 찍혀 있으면 SM이 LID를 할당해 패브릭에 정상 편입됐다는 증거다). Rate: 800은 방향당 800Gb/s, 즉 XDR로 협상됐다는 가장 중요한 한 줄이다(NDR로 떨어졌으면 400이 떴을 것이다). 마지막으로 Link layer: InfiniBand는 이 포트가 이더넷이 아니라 IB 모드로 동작 중이라는 확인이다. 정리하면 이 한 화면이 "스펙시트의 800G가 내 케이블에서 실제로 나오고, IB 모드로 패브릭에 붙었다"를 한 번에 보여준다.

 

(2) 800G가 실제로 나오는가 — ib_write_bw

링크가 살아있는 건 확인했으니, 이제 두 노드 사이 RDMA Write 대역폭을 측정한다. --use_cuda=0을 붙이면 GPU 메모리를 직접 소스로 써서 GPUDirect RDMA 경로까지 함께 측정된다.

# 서버 노드

$ ib_write_bw -d mlx5_0 -F --report_gbits --use_cuda=0



# 클라이언트 노드 (서버 IP 지정)

$ ib_write_bw -d mlx5_0 -F --report_gbits --use_cuda=0 <server_ip>



initializing CUDA

Listing all CUDA devices in system:

CUDA device 0: PCIe address is 1A:00

CUDA device 1: PCIe address is 3C:00

CUDA device 2: PCIe address is 62:00

CUDA device 3: PCIe address is 73:00

CUDA device 4: PCIe address is 9A:00

CUDA device 5: PCIe address is BC:00

CUDA device 6: PCIe address is DF:00

CUDA device 7: PCIe address is F0:00



Picking device No. 0

[pid = 2072037, dev = 0] device name = [NVIDIA B300 SXM6 AC]

creating CUDA Ctx

making it the current CUDA Ctx

CUDA device integrated: 0

allocated GPU buffer of a 131072 address at 0x55673145afd0 for type CUDA_MEM_DEVICE

---------------------------------------------------------------------------------------

                    RDMA_Write BW Test

 Dual-port       : OFF Device         : mlx5_0

 Number of qps   : 1 Transport type : IB

 Connection type : RC Using SRQ      : OFF

 PCIe relax order: ON Lock-free      : OFF

 ibv_wr* API     : ON Using DDP      : ON

 TX depth        : 128

 CQ Moderation   : 1

 CQE Poll Batch  : 16

 Mtu             : 4096[B]

 Link type       : IB

 Max inline data : 0[B]

 rdma_cm QPs : OFF

 Data ex. method : Ethernet

---------------------------------------------------------------------------------------

 local address: LID 0xaa QPN 0x0057 PSN 0x49ce33 RKey 0x1fffbf VAddr 0x0074ea67010000

 remote address: LID 0xbe QPN 0x0046 PSN 0xfc006f RKey 0x1fffbe VAddr 0x0071f13b010000

---------------------------------------------------------------------------------------

 #bytes     #iterations    BW peak[Gb/sec]    BW average[Gb/sec]   MsgRate[Mpps]

 65536      5000             786.06             784.74      1.496775

---------------------------------------------------------------------------------------

deallocating GPU buffer 000074ea67000000

destroying current CUDA Ctx

 

64KB 메시지 기준으로 BW peak 786.06Gb/s, BW average 784.74Gb/s가 나왔다. 800G 라인레이트의 약 98% 수준이라, NIC ↔ 스위치 ↔ NIC 경로가 정상이라는 뜻이다.

흥미로운 건 GPU 메모리 사용 여부에 따른 차이였다. 같은 노드에서 일반 호스트 메모리로 측정했을 때는 평균 462Gb/s에 그쳤는데, GPU 메모리를 직접 소스로 쓰는 GPUDirect RDMA 경로로 바꾸자 784Gb/s까지 올라갔다. 데이터가 호스트 RAM을 경유하지 않고 NIC ↔ GPU VRAM으로 직행하면서 생기는 차이다. 2번에서 말한 "호스트 RAM 경유까지 없앤다"가 실제 숫자로 드러난 셈이다.

 

4. 정리

1주차는 AI 워크로드가 GPU 위에서 어떻게 도는지 개론을 잡고, InfiniBand의 입구까지 들어가 봤다. ibstat으로 링크가 XDR로 살아있는지 확인하고, ib_write_bw로 두 노드 사이 RDMA Write가 800G 라인레이트에 닿는지, --use_cuda로 GPUDirect RDMA 경로에서 대역폭이 462 → 784Gb/s로 뛰는 것까지 눈으로 봤다.

다음부터는 이 링크 위에서 한 단계씩 더 측정해볼 생각이다. nccl-testsall_reduce_perf로 노드 수를 늘려가며 busbw가 유지되는지(스케일링), NCCL_DEBUG=INFO로 어느 경로를 타는지 확인한다. Quantum-X800만의 기능으로는 SHARP(스위치가 reduction을 대신하는 in-network computing)를 켜고 끈 all-reduce를 비교하고, Adaptive Routing이 다대다 트래픽을 링크별로 고르게 분산하는지 포트 카운터로 관찰한다. 마지막으로 정상일 때 ibdiagnet 결과를 baseline으로 저장해두면, 나중에 성능 저하가 생겼을 때 어느 포트가 범인인지 빠르게 좁힐 수 있다.

흐름은 결국 이렇다 — 링크가 사는가(ibstat) → 한 링크가 제 속도를 내는가(ib_write_bw) → 여러 노드로 묶어 collective가 스케일하는가(nccl-tests) → 스위치 기능으로 더 끌어올릴 수 있는가(SHARP/AR).