먼저 알아둘 결론

두 DGX Spark는 승인된 QSFP/CX7 케이블 한 개로 직접 연결할 수 있습니다. 한 물리 케이블이 두 개의 논리 netdev로 보이며, NVIDIA는 케이블 하나만으로 200GbE 전체 대역폭을 낼 수 있다고 안내합니다. 이 가이드에서는 두 논리 경로를 동시에 측정하되 Linux bond로 묶지 않습니다.

01 · GB10 이해

DGX Spark와 GB10

DGX Spark는 Grace CPU와 Blackwell GPU를 결합한 GB10 Superchip, 128GB 일관된 통합 메모리, ConnectX-7 NIC를 탑재합니다. 단일 장비는 최대 200B급 모델을 대상으로 하며, NVIDIA는 두 장비 연결 시 최대 405B 모델 구성을 안내합니다.

항목공식 사양이 가이드에서의 의미
메모리128GB LPDDR5x UMA · 273GB/sCPU와 GPU가 같은 시스템 메모리를 사용하므로 일반 GPU의 VRAM 표와 다르게 봅니다.
AI 연산FP4 sparsity 기준 최대 1PFLOP이론 최고값이며 실제 token/s가 아닙니다.
네트워크ConnectX-7 · 200Gbps · 후면 QSFP 포트 2개두 Spark 사이의 모델 분산 통신 경로입니다.

출처: NVIDIA DGX Spark Hardware Overview

02 · QSFP 케이블 구입

QSFP28(100Gbps)·QSFP56(200Gbps)·QSFP112(400Gbps) 중 하나를 구입하세요

DGX Spark의 ConnectX-7 포트에는 QSFP28(100Gbps), QSFP56(200Gbps), QSFP112(400Gbps) 규격 중 하나를 사용합니다. 세 규격은 세대와 속도 등급이 다르지만 Spark 후면 QSFP/CX7 포트에 맞는 classic QSFP 계열입니다. GB10 포트는 200Gb/s로 제한되므로 QSFP112(400Gbps)의 초과 대역폭은 사용하지 못합니다.

구매 전 판매자에게 확인할 네 가지

  • 규격이 QSFP28(100Gbps), QSFP56(200Gbps), QSFP112(400Gbps) 중 하나인가?
  • 판매자가 Spark 후면 QSFP/CX7 포트에 맞는 QSFP 케이블이라고 확인해 주는가?
  • 200GbE 이상 직접 연결 동작을 보증하고, 어댑터나 breakout 구성이 아닌 단일 케이블인가?
  • DGX Spark의 ConnectX-7 직접 연결 호환 보증과 반품 조건을 제공하는가?

참고 문서: NVIDIA Spark Stacking · Connect Two Sparks playbook

03 · QSFP 연결

같은 위치 연결을 권장하고, pull-tab(플라스틱 손잡이)은 위로 둡니다

  1. 두 장비의 후면에서 같은 위치의 ConnectX-7 포트를 고릅니다. 포트 자체는 서로 바꿔 쓸 수 있지만, NVIDIA playbook도 NCCL 테스트 혼선을 줄이기 위해 같은 physical port 사용을 권장합니다. 왼쪽은 왼쪽끼리·오른쪽은 오른쪽끼리 연결하면 이후 Path1/Path2 IP와 RDMA device 매핑도 양쪽에서 같은 순서로 기록하기 쉽습니다.
  2. 각 커넥터의 pull-tab(플라스틱 손잡이)이 장비 윗면을 향하게 둡니다.
  3. 포트와 수평을 맞춘 뒤 힘을 주지 말고 끝까지 밀어 넣습니다. 제대로 정렬되면 부드럽게 들어갑니다.
  4. 우리 케이블에서는 끝까지 들어갈 때 “딱” 하는 체결음이 났습니다. 소리보다 중요한 확인은 pull-tab(플라스틱 손잡이)을 건드리지 않은 채 커넥터 하우징을 아주 가볍게 당겼을 때 빠지지 않는 것입니다.
  5. 분리할 때만 pull-tab(플라스틱 손잡이)을 포트와 수평으로 곧게 당깁니다.
양쪽 노드물리 링크와 논리 인터페이스 확인 bash
ibdev2netdev
ip -br link
for IFACE in $(ibdev2netdev | awk '$NF == "(Up)" { print $(NF-1) }'); do
  echo "== $IFACE =="
  ethtool "$IFACE" | grep -E 'Speed|Lanes|Duplex|Link detected'
done
EXPECT
rocep1s0f0 port 1 ==> enp1s0f0np0 (Up)
roceP2p1s0f0 port 1 ==> enP2p1s0f0np0 (Up)
== enp1s0f0np0 ==
Speed: 200000Mb/s
Duplex: Full
Port: Direct Attach Copper
Link detected: yes
== enP2p1s0f0np0 ==
Speed: 200000Mb/s
Duplex: Full
Port: Direct Attach Copper
Link detected: yes

ibdev2netdev에서 아무 인터페이스도 (Up)이 아니면 케이블을 다시 체결하고 두 장비를 정상 재부팅한 뒤 재확인합니다.

04 · 네트워크 설정

자동 IP를 먼저 확인하고, 필요할 때만 수동 /30을 넣습니다

NVIDIA Sync Cluster Assistant나 DHCP가 있는 QSFP 스위치 환경은 주소를 자동으로 만들 수 있습니다. Linux도 IPv6 link-local은 보통 자동으로 만들고, NetworkManager 프로필이 ipv4.method link-local이거나 fallback이면 169.254.x.y/16 IPv4 link-local을 자동으로 잡을 수 있습니다.

양쪽 노드자동 IPv4와 route 상태 확인 bash
ibdev2netdev
for IFACE in $(ibdev2netdev | awk '$NF == "(Up)" { print $(NF-1) }'); do
  echo "== $IFACE =="
  ip -4 -br address show dev "$IFACE"
  nmcli -f GENERAL.STATE,IP4.ADDRESS device show "$IFACE" | sed 's/^/  /'
done
ip -4 route
EXPECT
== enp1s0f0np0 ==
enp1s0f0np0 UP 169.254.72.31/16
  GENERAL.STATE: 100 (connected)
  IP4.ADDRESS[1]: 169.254.72.31/16
== enP2p1s0f0np0 ==
enP2p1s0f0np0 UP 169.254.84.12/16
  GENERAL.STATE: 100 (connected)
  IP4.ADDRESS[1]: 169.254.84.12/16
169.254.0.0/16 dev enp1s0f0np0 proto kernel scope link src 169.254.72.31
169.254.0.0/16 dev enP2p1s0f0np0 proto kernel scope link src 169.254.84.12

이 가이드의 TCP·RoCE·RPC 명령은 두 경로의 알려진 IPv4 peer 주소를 필요로 합니다. 자동 주소가 없거나, 169.254/16 주소가 재부팅 때 바뀌거나, 두 논리 경로가 같은 route처럼 보여 peer를 고정하기 어렵거나, 기존 사내망·VPN·컨테이너 route와 겹치면 수동 주소를 넣습니다.

상태판단다음 단계
NVIDIA Sync 또는 DHCP가 두 QSFP 경로에 안정적 IPv4를 부여자동 사용 가능그 IP를 qsfp-guide.env에 기록하고 수동 적용은 건너뜁니다.
169.254.x.y/16만 있음임시 통신은 가능하지만 peer·GID가 흔들릴 수 있음재현 가능한 측정과 RPC에는 수동 /30을 권합니다.
IPv4 없음, route 충돌, ping 실패수동 설정 필요아래 기본값 또는 충돌 없는 private /30 두 개를 넣습니다.

아래 기본값은 2026-07-23에 검증한 예시입니다. Path1은 10.42.0.0/30, Path2는 10.42.1.0/30입니다. 같은 대역이 이미 ip -4 route에 보이면 prompt에서 다른 private /30 두 개를 입력하세요.

양쪽 노드노드 역할·인터페이스·주소 기록 bash
ibdev2netdev
read -r -p "이 노드의 역할 (A/B): " NODE_ROLE
read -r -p "첫 번째 Up netdev (Path1): " QSFP_IF1
read -r -p "두 번째 Up netdev (Path2): " QSFP_IF2
case "$NODE_ROLE" in
  A) DEFAULT_LOCAL_IP1=10.42.0.1; DEFAULT_PEER_IP1=10.42.0.2; DEFAULT_LOCAL_IP2=10.42.1.1; DEFAULT_PEER_IP2=10.42.1.2 ;;
  B) DEFAULT_LOCAL_IP1=10.42.0.2; DEFAULT_PEER_IP1=10.42.0.1; DEFAULT_LOCAL_IP2=10.42.1.2; DEFAULT_PEER_IP2=10.42.1.1 ;;
  *) echo "A 또는 B만 입력하세요." >&2; exit 1 ;;
esac
echo "기본값: Path1 10.42.0.0/30, Path2 10.42.1.0/30"
read -r -p "Path1 local IP [$DEFAULT_LOCAL_IP1]: " LOCAL_IP1
read -r -p "Path1 peer IP  [$DEFAULT_PEER_IP1]: " PEER_IP1
read -r -p "Path2 local IP [$DEFAULT_LOCAL_IP2]: " LOCAL_IP2
read -r -p "Path2 peer IP  [$DEFAULT_PEER_IP2]: " PEER_IP2
: "${LOCAL_IP1:=$DEFAULT_LOCAL_IP1}"
: "${PEER_IP1:=$DEFAULT_PEER_IP1}"
: "${LOCAL_IP2:=$DEFAULT_LOCAL_IP2}"
: "${PEER_IP2:=$DEFAULT_PEER_IP2}"
mkdir -p "$HOME/.config"
cat > "$HOME/.config/qsfp-guide.env" <<EOF
export NODE_ROLE="$NODE_ROLE"
export QSFP_IF1="$QSFP_IF1"
export QSFP_IF2="$QSFP_IF2"
export LOCAL_IP1="$LOCAL_IP1"
export LOCAL_IP2="$LOCAL_IP2"
export PEER_IP1="$PEER_IP1"
export PEER_IP2="$PEER_IP2"
EOF
chmod 600 "$HOME/.config/qsfp-guide.env"
cat "$HOME/.config/qsfp-guide.env"
EXPECT
export NODE_ROLE="A"
export QSFP_IF1="enp1s0f0np0"
export QSFP_IF2="enP2p1s0f0np0"
export LOCAL_IP1="10.42.0.1"
export LOCAL_IP2="10.42.1.1"
export PEER_IP1="10.42.0.2"
export PEER_IP2="10.42.1.2"
양쪽 노드NetworkManager 영구 프로필과 MTU 9000 적용 bash
source "$HOME/.config/qsfp-guide.env"
ensure_profile() {
  name="$1"; iface="$2"; address="$3"
  if nmcli -t -f NAME connection show | grep -Fxq "$name"; then
    sudo nmcli connection modify "$name" connection.interface-name "$iface" ipv4.method manual ipv4.addresses "$address/30" ipv4.gateway "" ipv4.dns "" ipv4.never-default yes ipv6.method link-local 802-3-ethernet.mtu 9000 connection.autoconnect yes
  else
    sudo nmcli connection add type ethernet ifname "$iface" con-name "$name" ipv4.method manual ipv4.addresses "$address/30" ipv4.gateway "" ipv4.dns "" ipv4.never-default yes ipv6.method link-local 802-3-ethernet.mtu 9000 connection.autoconnect yes
  fi
  sudo nmcli connection up "$name"
}
ensure_profile qsfp-primary "$QSFP_IF1" "$LOCAL_IP1"
ensure_profile qsfp-secondary "$QSFP_IF2" "$LOCAL_IP2"
EXPECT
Connection successfully activated (D-Bus active path: /org/freedesktop/NetworkManager/ActiveConnection/12)
Connection successfully activated (D-Bus active path: /org/freedesktop/NetworkManager/ActiveConnection/13)
양쪽 노드route와 Jumbo frame 확인 bash
source "$HOME/.config/qsfp-guide.env"
ip -4 -br address show dev "$QSFP_IF1"
ip -4 -br address show dev "$QSFP_IF2"
ip route get "$PEER_IP1"
ip route get "$PEER_IP2"
ping -I "$QSFP_IF1" -M do -s 8972 -c 4 "$PEER_IP1"
ping -I "$QSFP_IF2" -M do -s 8972 -c 4 "$PEER_IP2"
EXPECT
enp1s0f0np0 UP 10.42.0.1/30
enP2p1s0f0np0 UP 10.42.1.1/30
10.42.0.2 dev enp1s0f0np0 src 10.42.0.1 uid 1000
10.42.1.2 dev enP2p1s0f0np0 src 10.42.1.1 uid 1000
4 packets transmitted, 4 received, 0% packet loss, time 3001ms
4 packets transmitted, 4 received, 0% packet loss, time 3001ms

직접 연결에는 default gateway와 DNS를 넣지 않습니다. 두 logical netdev는 별도 /30에 두고 bond로 합치지 않습니다.

05 · QSFP 속도 확인

두 경로를 동시에, A→B와 B→A를 따로 측정합니다

먼저 수신 노드에서 server 블록을 실행하고, 바로 이어 송신 노드에서 client 블록을 실행합니다. A→B가 끝나면 역할을 바꿔 다시 실행합니다. 두 client 로그의 [SUM] receiver 값을 더한 것이 한 방향의 TCP 합계입니다.

노드 BA→B 수신: 두 iperf3 server 동시 실행 bash
source "$HOME/.config/qsfp-guide.env"
PORT1=5201; PORT2=5202
iperf3 -s -B "$LOCAL_IP1" -p "$PORT1" --one-off > /tmp/qsfp-path1-recv.log &
iperf3 -s -B "$LOCAL_IP2" -p "$PORT2" --one-off > /tmp/qsfp-path2-recv.log &
wait
cat /tmp/qsfp-path1-recv.log /tmp/qsfp-path2-recv.log
EXPECT
-----------------------------------------------------------
Server listening on 5201 (test #1)
-----------------------------------------------------------
-----------------------------------------------------------
Server listening on 5202 (test #1)
-----------------------------------------------------------
노드 AA→B 송신: 두 경로 동시 측정 bash
source "$HOME/.config/qsfp-guide.env"
PORT1=5201; PORT2=5202
iperf3 -c "$PEER_IP1" -B "$LOCAL_IP1" -p "$PORT1" -P 16 -t 20 --zerocopy -w 16M > /tmp/qsfp-path1-send.log &
iperf3 -c "$PEER_IP2" -B "$LOCAL_IP2" -p "$PORT2" -P 16 -t 20 --zerocopy -w 16M > /tmp/qsfp-path2-send.log &
wait
grep -E '\[SUM\].*receiver' /tmp/qsfp-path1-send.log /tmp/qsfp-path2-send.log
EXPECT
/tmp/qsfp-path1-send.log:[SUM]   0.00-20.04  sec   220 GBytes  94.1 Gbits/sec  receiver
/tmp/qsfp-path2-send.log:[SUM]   0.00-20.04  sec   224 GBytes  95.6 Gbits/sec  receiver

반대 방향은 노드 A에서 receiver 블록, 노드 B에서 sender 블록을 실행합니다. 직전 server가 완전히 종료된 뒤 같은 port를 재사용하세요.

2026-07-23 실제 측정 결과
측정결과기준·조건상태
TCP · A → B189.73 Gb/s두 경로 receiver 합계검증됨
TCP · B → A192.15 Gb/s두 경로 receiver 합계검증됨
RoCE · A → B196.08 Gb/s두 경로 합계검증됨
RoCE · B → A196.11 Gb/s두 경로 합계검증됨

TCP 통과 기준은 방향별 두 경로 합계 180Gb/s 이상, RoCE는 190Gb/s 이상입니다. 이 값은 line rate가 아니라 이 환경의 acceptance 기준입니다.

RoCE도 196Gb/s 수준인지 확인하기

ib_write_bw를 실행하기 전에 netdev와 RDMA device·port·RoCE v2 IPv4 GID index가 같은 경로인지 확인해야 합니다. GID index를 추측하지 마세요.

양쪽 노드RDMA device·port·GID 매핑 확인 bash
source "$HOME/.config/qsfp-guide.env"
ibdev2netdev
rdma link show
show_gids
# 같은 netdev의 RDMA device, port, RoCE v2 IPv4 GID index를 기록하세요.
EXPECT
rocep1s0f0 port 1 ==> enp1s0f0np0 (Up)
roceP2p1s0f0 port 1 ==> enP2p1s0f0np0 (Up)
link rocep1s0f0/1 state ACTIVE physical_state LINK_UP netdev enp1s0f0np0
link roceP2p1s0f0/1 state ACTIVE physical_state LINK_UP netdev enP2p1s0f0np0
DEV       PORT  INDEX  GID                                      IPv4          VER  DEV
rocep1s0f0 1    3      ::ffff:10.42.0.1                         10.42.0.1    v2   enp1s0f0np0
양쪽 노드확인한 RDMA 매핑을 환경 파일에 기록 bash
ENV_FILE="$HOME/.config/qsfp-guide.env"
source "$ENV_FILE"
ibdev2netdev
rdma link show
show_gids
read -r -p "Path1 RDMA device: " RDMA_DEV1
read -r -p "Path1 RDMA port: " RDMA_PORT1
read -r -p "Path1 RoCE v2 IPv4 GID index: " GID_INDEX1
read -r -p "Path2 RDMA device: " RDMA_DEV2
read -r -p "Path2 RDMA port: " RDMA_PORT2
read -r -p "Path2 RoCE v2 IPv4 GID index: " GID_INDEX2
TMP_ENV="$(mktemp)"
grep -vE '^export (RDMA_DEV1|RDMA_PORT1|GID_INDEX1|RDMA_DEV2|RDMA_PORT2|GID_INDEX2)=' "$ENV_FILE" > "$TMP_ENV"
cat >> "$TMP_ENV" <<EOF
export RDMA_DEV1="$RDMA_DEV1"
export RDMA_PORT1="$RDMA_PORT1"
export GID_INDEX1="$GID_INDEX1"
export RDMA_DEV2="$RDMA_DEV2"
export RDMA_PORT2="$RDMA_PORT2"
export GID_INDEX2="$GID_INDEX2"
EOF
install -m 600 "$TMP_ENV" "$ENV_FILE"
rm -f "$TMP_ENV"
EXPECT
export RDMA_DEV1="rocep1s0f0"
export RDMA_PORT1="1"
export GID_INDEX1="3"
export RDMA_DEV2="roceP2p1s0f0"
export RDMA_PORT2="1"
export GID_INDEX2="3"

A→B는 노드 B에서 receiver를 먼저 실행한 다음 노드 A에서 sender를 실행합니다. 두 경로의 BW average[Gb/sec]를 더해 190Gb/s 이상인지 확인합니다.

노드 BA→B RoCE receiver 두 경로 동시 실행 bash
source "$HOME/.config/qsfp-guide.env"
PORT1=18515; PORT2=18516
ib_write_bw -d "$RDMA_DEV1" -i "$RDMA_PORT1" -x "$GID_INDEX1" -F --report_gbits -D 20 -q 8 -s 1048576 -p "$PORT1" > /tmp/roce-path1-recv.log &
ib_write_bw -d "$RDMA_DEV2" -i "$RDMA_PORT2" -x "$GID_INDEX2" -F --report_gbits -D 20 -q 8 -s 1048576 -p "$PORT2" > /tmp/roce-path2-recv.log &
wait
cat /tmp/roce-path1-recv.log /tmp/roce-path2-recv.log
EXPECT
************************************
* Waiting for client to connect... *
************************************
************************************
* Waiting for client to connect... *
************************************
노드 AA→B RoCE sender 두 경로 동시 실행 bash
source "$HOME/.config/qsfp-guide.env"
PORT1=18515; PORT2=18516
ib_write_bw -d "$RDMA_DEV1" -i "$RDMA_PORT1" -x "$GID_INDEX1" -F --report_gbits -D 20 -q 8 -s 1048576 -p "$PORT1" "$PEER_IP1" > /tmp/roce-path1-send.log &
ib_write_bw -d "$RDMA_DEV2" -i "$RDMA_PORT2" -x "$GID_INDEX2" -F --report_gbits -D 20 -q 8 -s 1048576 -p "$PORT2" "$PEER_IP2" > /tmp/roce-path2-send.log &
wait
cat /tmp/roce-path1-send.log /tmp/roce-path2-send.log
EXPECT
#bytes     #iterations    BW peak[Gb/sec]    BW average[Gb/sec]
1048576    4890           99.20              98.04
#bytes     #iterations    BW peak[Gb/sec]    BW average[Gb/sec]
1048576    4893           99.36              98.04

B→A는 노드 A에서 receiver, 노드 B에서 sender를 같은 순서로 실행합니다. 직전 process가 종료된 뒤 port를 재사용하세요. 2026-07-23에는 A→B 196.08Gb/s, B→A 196.11Gb/s를 확인했습니다.

06 · 문제가 있다면

증상 아래 계층부터 확인합니다

증상먼저 확인조치
netdev가 모두 Down같은 위치 포트, 탭 방향, 완전 체결케이블 재장착 후 양쪽 정상 재부팅
200000Mb/s·2 lanes가 아님케이블 호환성, 포트 모드, firmwareIP 설정 전에 물리 링크부터 해결
Jumbo만 실패양쪽 MTU 9000, route get 결과NetworkManager profile과 주소 충돌 수정
TCP 한 방향만 느림송신 노드, 같은 방향 RoCE, CRC·discard·AER느린 송신 노드의 NIC·PCIe 상태 조사
RoCE만 느림RDMA device·port·GID 매핑같은 netdev의 RoCE v2 IPv4 GID로 재측정
모델만 실패binary·model SHA, RPC0, 메모리네트워크 튜닝이 아니라 runtime을 점검
양쪽 노드변경·재부팅 전 증거 저장 bash
source "$HOME/.config/qsfp-guide.env"
STAMP="$(date +%F-%H%M%S)"
OUT="$HOME/qsfp-evidence/$(hostname)-$STAMP"
mkdir -p "$OUT"
{
  date -Is
  uname -a
  ip -br link
  ip -4 -br address
  ip -4 route
  ibdev2netdev
  rdma link show
  nvidia-smi
} > "$OUT/inventory.txt" 2>&1
for IFACE in "$QSFP_IF1" "$QSFP_IF2"; do
  ethtool "$IFACE" > "$OUT/ethtool-$IFACE.txt" 2>&1
  ethtool -S "$IFACE" > "$OUT/ethtool-stats-$IFACE.txt" 2>&1
done
sudo lspci -tv > "$OUT/lspci-tree.txt" 2>&1
sudo lspci -vv > "$OUT/lspci-vv.txt" 2>&1
sudo journalctl -k -b --no-pager > "$OUT/kernel-journal.txt" 2>&1
printf 'Evidence saved: %s
' "$OUT"
find "$OUT" -maxdepth 1 -type f -printf '%f
' | LC_ALL=C sort
EXPECT
Evidence saved: /home/donghyeon/qsfp-evidence/spark-a-2026-07-23-153000
ethtool-enP2p1s0f0np0.txt
ethtool-enp1s0f0np0.txt
ethtool-stats-enP2p1s0f0np0.txt
ethtool-stats-enp1s0f0np0.txt
inventory.txt
kernel-journal.txt
lspci-tree.txt
lspci-vv.txt

우리가 실제로 겪은 방향성 병목

우리가 겪은 병목은 한 방향 TCP·RoCE가 약 16–25Gb/s까지 떨어지는 형태였습니다. qdisc, pause frame, ring 설정으로는 해결되지 않았고, Linux kernel과 NVIDIA driver update를 먼저 시도했습니다.

이후 firmware update를 적용한 뒤 속도가 정상 범위로 돌아왔습니다. 업데이트 전에는 journal, ethtool, lspci 증거를 먼저 저장하고, update 뒤에는 링크·Jumbo·TCP·RoCE를 처음부터 다시 측정합니다.

07 · 병렬화 후 LLM 추론

llama-server는 검증값을 싣고, vLLM은 별도 검증 절로 둡니다

추론 절은 두 갈래입니다. 현재 재현 가능한 실습은 llama.cpp RPC와 llama-server로 K-EXAONE Q4_K_M을 1:1 layer split 실행하는 경로입니다. vLLM은 같은 네트워크 acceptance를 통과한 뒤 별도 명령·모델·메모리 한계를 검증해 추가해야 하며, 여기서는 아직 추천 절차로 확정하지 않습니다.

llama.cpp RPC + llama-server: 검증 완료

1. 두 노드에 같은 llama.cpp 빌드

양쪽 노드검증 commit b10088 · CUDA/RPC build bash
git clone https://github.com/ggml-org/llama.cpp.git "$HOME/llama.cpp-b10088"
cd "$HOME/llama.cpp-b10088"
git checkout b10088
cmake -B build -DGGML_CUDA=ON -DGGML_RPC=ON -DCMAKE_BUILD_TYPE=Release
cmake --build build -j"$(nproc)"
sha256sum build/bin/ggml-rpc-server
build/bin/llama-server --version
EXPECT
<sha256>  build/bin/ggml-rpc-server
version: b10088

2. 노드 A에 모델 받기

hf CLI 로그인과 저장소 이용 조건 확인이 먼저 필요합니다. 최소 150GiB의 여유 공간을 확보하세요.

노드 AK-EXAONE Q4_K_M 다운로드와 checksum bash
MODEL_DIR="$HOME/models/K-EXAONE-236B-A23B-GGUF"
MODEL_FILE="$MODEL_DIR/K-EXAONE-236B-A23B-Q4_K_M.gguf"
mkdir -p "$MODEL_DIR"
hf download LGAI-EXAONE/K-EXAONE-236B-A23B-GGUF K-EXAONE-236B-A23B-Q4_K_M.gguf --local-dir "$MODEL_DIR" >/dev/null
sha256sum "$MODEL_FILE"
stat -c 'size %s bytes' "$MODEL_FILE"
EXPECT
83f744c3ee7ee7f19a80c7e0a73769f66b23db1831dddbbdea168637d3f868be  /home/donghyeon/models/K-EXAONE-236B-A23B-GGUF/K-EXAONE-236B-A23B-Q4_K_M.gguf
size 143471722240 bytes

3. 노드 B에서 RPC server 실행

노드 BQSFP Path1 private 주소에만 RPC bind bash
source "$HOME/.config/qsfp-guide.env"
[ "$NODE_ROLE" = B ] || { echo "노드 B에서 실행하세요." >&2; exit 1; }
RPC_BIN="$HOME/llama.cpp-b10088/build/bin/ggml-rpc-server"
LD_LIBRARY_PATH="$(dirname "$RPC_BIN")" "$RPC_BIN" -H "$LOCAL_IP1" -p 50052 -d CUDA0
EXPECT
create_backend: using CUDA0
Starting RPC server on 10.42.0.2:50052

4. 노드 A에서 두 device 확인

노드 Alocal CUDA0와 remote RPC0 확인 bash
source "$HOME/.config/qsfp-guide.env"
[ "$NODE_ROLE" = A ] || { echo "노드 A에서 실행하세요." >&2; exit 1; }
LLAMA_SERVER="$HOME/llama.cpp-b10088/build/bin/llama-server"
"$LLAMA_SERVER" --rpc "$PEER_IP1:50052" --list-devices
EXPECT
Available devices:
  CUDA0: NVIDIA GB10
  RPC0: 10.42.0.2:50052

5. 모델을 1:1로 분할해 실행

노드 AK-EXAONE llama-server 시작 bash
source "$HOME/.config/qsfp-guide.env"
MODEL="$HOME/models/K-EXAONE-236B-A23B-GGUF/K-EXAONE-236B-A23B-Q4_K_M.gguf"
LLAMA_SERVER="$HOME/llama.cpp-b10088/build/bin/llama-server"
"$LLAMA_SERVER" --model "$MODEL" --rpc "$PEER_IP1:50052" --gpu-layers 999 --split-mode layer --tensor-split 1,1 --ctx-size 4096 --parallel 1 --batch-size 512 --ubatch-size 128 --threads 10 --threads-batch 10 --flash-attn on --jinja --host 127.0.0.1 --port 8088
EXPECT
llama_model_loader: loaded meta data with 64 key-value pairs
llama_model_load: model loaded
llama server listening at http://127.0.0.1:8088
노드 AOpenAI 호환 API sanity prompt bash
curl -sS http://127.0.0.1:8088/v1/chat/completions -H 'Content-Type: application/json' -d '{"model":"K-EXAONE","messages":[{"role":"user","content":"1+1의 답만 말하세요."}],"temperature":0,"max_tokens":16}' | python3 -c 'import json, sys; data=json.load(sys.stdin); content=data["choices"][0]["message"]["content"].strip(); print("assistant content: " + content); print("sanity: ok" if content == "2" else "sanity: unexpected")'
EXPECT
assistant content: 2
sanity: ok
2026-07-23 K-EXAONE 검증 결과
측정결과기준·조건상태
K-EXAONE 생성약 13.7 token/sQ4_K_M · layer split 1,1검증됨
  • 모델 SHA-256: 83f744c3…f868be
  • local allocation 67,463MiB · remote allocation 약 69.1GiB
  • 프롬프트 1+1의 답만 말하세요. → 응답 2
  • generation 약 13.7 token/s

vLLM: 작성 중

vLLM은 후보 runtime으로 남깁니다. 다만 이 문서의 검증 데이터는 llama.cpp RPC 기준이므로, vLLM 절은 K-EXAONE 또는 대체 공개 모델의 실제 2노드 실행, 메모리 사용량, token/s, 실패 조건을 측정한 뒤 명령을 고정합니다.

08 · 병렬화 후 학습

학습 방법은 탐색 방향만 남기고 작성 중으로 둡니다

QSFP/RDMA가 통과하면 NCCL 기반 분산 학습을 탐색할 수 있습니다. 하지만 이 프로젝트에서는 아직 GB10 두 대로 실제 학습을 재현하지 않았으므로 권장 절차처럼 쓰지 않습니다.

  • 먼저 NCCL all-reduce, PyTorch DDP/FSDP, 작은 공개 모델과 합성 데이터로 통신 안정성을 확인합니다.
  • 성능 숫자나 설정값은 학습 workload를 실제로 실행한 뒤에만 고정합니다.

09 · 측정값 해석

측정값을 해석하는 법

모든 수치는 2026-07-23의 DGX Spark 2대, kernel 6.17.0-1026-nvidia, MTU 9000 환경에서 얻었습니다. 다른 케이블·소프트웨어·주소·모델에서는 다시 측정해야 합니다. TCP/RoCE 처리량과 token/s는 서로 다른 측정값이므로 직접 비교하지 않습니다.

10 · 운영 원칙

끝까지 지켜야 할 세 가지

  1. 인터페이스 이름과 GID는 예시를 복사하지 말고 현재 장비에서 다시 찾습니다.
  2. 속도는 두 경로 합계와 두 방향을 각각 기록합니다.
  3. 문제가 생기면 update보다 먼저 현재 boot의 journal과 counter를 저장합니다.
DGX Spark 2노드 QSFP·LLM 가이드 검증 일자 2026-07-23 · 환경별 값은 직접 발견 후 사용