Loading the catalog…
Loading the catalog…
가능합니다. 다만 여기서는 세 층을 분리해서 설계 하는 게 좋습니다. K8s: Pod가 CPU/GPU를 같은 NUMA에 받도록 한다. NVIDIA/NCCL: 한 모델에 여러 GPU를 쓸 때 NVLink/NVSwitch를 최대한 사용한다. vLLM: TP/DP/EP와 KV cache를 workload 특성에 맞춘다. 특히 B300 8-GPU 노드라면 “무조건 single-numa-node”가 정답은 아닙니다. 8-GPU 모델은 양쪽 NUMA를 사용해야 하기 때문입니다. 1. K8s에서 CPU ↔ GPU affinity GPU 노드 kubelet의 기본 방향은 다음입니다. # /var/lib/kubelet/config.yaml cpuManagerPolicy: static topologyManagerPolicy: restricted topologyManagerScope: pod CPU Manager=static 은 Guaranteed Pod에 exclusive CPU를 할당할 수 있게 하고, Topology Manager는 CPU와 GPU 같은 device의 topology hint를 종합합니다. restricted 는 적절한 topology alignment를 만들 수 없으면 Pod admission을 거부합니다. Kubernetes 그리고 serving Pod를 반드시 Guaranteed QoS 로 만드는 게 중요합니다. resources: requests: cpu: "16" memory: "128Gi" nvidia.com/gpu: "2" limits: cpu: "16" memory: "128Gi" nvidia.com/gpu: "2" 즉 CPU의 requests == limits 로 잡습니다. 예를 들어 물리 topology가: NUMA 0 NUMA 1 ──────────────── ──────────────── CPU 0-63 CPU 64-127 GPU 0 GPU 4 GPU 1 GPU 5 GPU 2 GPU 6 GPU 3 GPU 7 NIC0 NIC1 이라면 2-GPU serving Pod에 대해 목표는: Pod A CPU 0-15 │ NUMA 0 ├── GPU0 └── GPU1 입니다. 반대로 이것은 피하고 싶은 상태입니다. CPU NUMA0 │ └──────── PCIe/NUMA crossing ─────── GPU5 NUMA1 single-numa-node 를 쓰면 더 강력하지 않나? 맞습니다. topologyManagerPolicy: single-numa-node 이면 CPU/GPU 등을 하나의 NUMA node에 배치할 수 없는 Pod는 거부합니다. Kubernetes 그런데 네 환경에서는 문제가 있습니다. 2 GPU Pod GPU0 + GPU1 → NUMA0 → OK 4 GPU Pod GPU0~3 → NUMA0 → OK 8 GPU Pod GPU0~7 → NUMA0 + NUMA1 → single NUMA 불가능 그래서 다양한 크기의 LLM serving을 같은 B300 node에서 운영한다면 restricted 를 기본으로 두는 게 더 현실적 입니다. 2. NIC locality는 Topology Manager만으로 끝나지 않는다 여기가 중요한 부분입니다. 일반적인 Kubernetes eth0 같은 host networking NIC를 사용한다고 해서 Topology Manager가 자동으로 GPU0 → NUMA0 → NIC0 GPU5 → NUMA1 → NIC1 을 만들어주는 것은 아닙니다. NIC까지 topology-managed device로 다루려면 SR-IOV/device plugin 같은 구조가 필요합니다. 따라서 네 Ethernet 구성이 예를 들어: B300 Node NUMA0 NUMA1 │ │ GPU0-3 GPU4-7 │ │ NIC0 400G NIC1 400G │ │ └────────── Ethernet Fabric ───────────┘ │ AIStor 라면 가장 강한 locality를 원할 때는: GPU Device Plugin + SR-IOV Network Device Plugin + CPU Manager + Topology Manager 식으로 CPU/GPU/NIC를 resource로 노출하는 방식을 검토합니다. 다만 AIStor에서 모델을 한 번 NVMe/HBM으로 stage한 후 serving하는 구조라면 NIC locality를 지나치게 최적화할 필요는 없습니다. 실제 inference hot path가: Client │ NIC │ CPU │ GPU │ GPU HBM 이기 때문에 request traffic 자체가 모델 weight loading traffic보다 훨씬 작을 가능성이 큽니다. NIC locality는 오히려 multi-node TP/EP/NCCL 또는 KV-cache remote offload 를 할 때 훨씬 중요해집니다. 3. GPU topology는 조금 다르게 생각해야 합니다 B300 8-GPU 시스템에서 확인해야 할 첫 번째 명령은: nvidia-smi topo -m 입니다. 목표는 대략 다음 관계를 파악하는 것입니다. NVLink / NVSwitch GPU0 ─┐ GPU1 ─┤ GPU2 ─┤ GPU3 ─┼──── NVSwitch fabric GPU4 ─┤ GPU5 ─┤ GPU6 ─┤ GPU7 ─┘ 여기서 중요한 점은 CPU NUMA와 GPU-to-GPU topology를 동일하게 생각하면 안 된다는 것 입니다. CPU에서는: CPU NUMA0 → GPU0~3 CPU NUMA1 → GPU4~7 같은 locality가 중요할 수 있지만 GPU끼리 Tensor Parallel communication을 할 때는: GPU │ NVLink │ NVSwitch │ GPU 경로가 핵심입니다. 따라서 8 GPU를 사용하는 큰 모델에서는 CPU NUMA 때문에 GPU를 억지로 4+4 별도 serving group으로 쪼개는 것보다 NVSwitch fabric 전체를 활용하는 TP/EP 구성이 더 중요할 수 있습니다. 4. 그래서 모델별 GPU 구성부터 정해야 한다 네 모델 목록을 보면 크게 Dense / MoE / Vision/OCR 로 나눠 접근하는 게 좋습니다. vLLM도 TP는 큰 모델을 여러 GPU에 shard하는 일반적인 방식이고, MoE에는 EP를 별도로 지원합니다. vLLM 예를 들어 설계 개념은: workload 우선 검토 작은 모델 GPU 1 + DP replicas 중형 Dense TP=2 또는 TP=4 큰 Dense TP=4/8 큰 MoE EP + DP/TP OCR/Vision GPU 1~2 + DP 동시 요청이 많음 DP 증가 Dense model이라면: TP=4 GPU0 ─┐ GPU1 ─┤ GPU2 ─┼── NVLink/NVSwitch GPU3 ─┘ 한 model instance 가 되고, GPU memory가 충분해서 모델 하나가 GPU 한 장에 들어가고 throughput이 중요하다면: DP=4 GPU0 → Model replica #0 GPU1 → Model replica #1 GPU2 → Model replica #2 GPU3 → Model replica #3 ▲ Load Balancer 가 더 적합합니다. vLLM의 DP는 model weight를 replica별로 가지고 독립 request batch를 처리합니다. vLLM 5. MoE는 특히 EP를 검토해야 한다 DeepSeek/Qwen 계열처럼 MoE 모델이면 이야기가 달라집니다. 예를 들어 8 GPU에서: MoE model GPU0 ─ expert set ─┐ GPU1 ─ expert set ─┤ GPU2 ─ expert set ─┤ GPU3 ─ expert set ─┼── NVSwitch GPU4 ─ expert set ─┤ GPU5 ─ expert set ─┤ GPU6 ─ expert set ─┤ GPU7 ─ expert set ─┘ 처럼 expert를 GPU에 분산시키는 Expert Parallelism 을 사용할 수 있습니다. vLLM에서는: --enable-expert-parallel 을 제공하고, 현재 EP 크기는 TP와 DP 구성으로 결정됩니다. vLLM 따라서 네 workload에서는 단순히 "8 GPU 있으니까 TP=8" 으로 통일하면 안 됩니다. Dense와 MoE의 최적 parallelism이 다릅니다. 6. KV cache가 실제 serving 성능에서 매우 중요 LLM inference에서 GPU HBM은 크게: GPU HBM ─────────────────────────── Model weights ████████████████ KV cache ████████ Activation / workspace ████ CUDA/NCCL/etc ██ 로 사용됩니다. model weight를 제외하고 남는 HBM을 얼마나 KV cache에 줄 수 있는지가 동시 request 수와 context length 에 큰 영향을 줍니다. vLLM은 이를 --gpu-memory-utilization 이나 더 직접적인 --kv-cache-memory-bytes 로 제어할 수 있습니다. 현재 기본 gpu-memory-utilization 은 0.92이고, KV cache capacity와 max concurrency도 startup log에서 확인할 수 있습니다. vLLM 처음부터 0.99 같은 공격적인 값을 쓰기보다는 실제 모델을 load해서 여유 HBM과 peak usage를 측정하는 게 좋습니다. 7. Prefix caching은 적극 검토 네가 말한 workload에는 prefix caching 도 꽤 중요할 수 있습니다. 예를 들어 OCR/document workload에서 여러 요청이: [공통 system prompt] [공통 instruction] [document A] [공통 system prompt] [공통 instruction] [document B] [공통 system prompt] [공통 instruction] [document C] 처럼 동일한 긴 prefix를 가지고 있다면: shared prefix │ KV cache █████████ / | \ / | \ doc A doc B doc C 로 reuse할 수 있습니다. vLLM에는 enable_prefix_caching 이 KV-cache configuration으로 존재합니다. vLLM 8. KV cache를 NVMe에 바로 내리는 것은 1순위가 아니다 네 시스템에는 NVMe 8개가 있지만 저는 우선: HBM │ ├── model weights └── KV cache ← 1순위 로 갑니다. HBM이 부족해졌다고 바로 HBM → NVMe 를 하기보다 먼저: HBM │ ▼ CPU RAM offload 계층을 검토하는 편이 낫습니다. 그리고 훨씬 큰 KV capacity가 필요한 경우: GPU HBM HOT │ CPU RAM WARM │ MemKV/RDMA external cache │ NVMe capacity tier 같은 계층을 검토할 수 있습니다. 현재 vLLM에는 native CPU KV offloading과 LMCache backend가 있으며 KV offload 크기를 설정할 수 있습니다. vLLM 이 부분이 앞에서 이야기했던 MemKV 테스트와 직접 연결되는 영역 입니다. 9. 네 환경에서는 전체를 이렇게 맞추는 게 좋다 제가 현재까지 나온 조건을 합치면 목표 architecture는 이쪽입니다. B300 Node ┌────────────────────────────────────────────────────┐ │ │ │ NUMA0 NUMA1 │ │ ───── ───── │ │ CPU cores CPU cores │ │ │ │ │ │ GPU0 GPU1 GPU2 GPU3 GPU4 GPU5 GPU6 GPU7 │ │ \ | | / \ | | / │ │ └──┴───┴───────────────────────┴───┴───┘ │ │ │ │ │ NVLink/NVSwitch │ │ │ │ NIC0 400G NIC1 400G │ │ │ │ │ │ └──────── Ethernet Fabric ───────┘ │ │ │ │ │ AIStor / S3 │ │ │ │ 8 x NVMe RAID0 + XFS │ │ │ │ │ /model-cache │ │ /dataset-cache │ │ /scratch │ └────────────────────────────────────────────────────┘ 그리고 Kubernetes는: CPU Manager static │ ├─────────────┐ │ │ Topology Manager │ restricted │ │ │ ▼ ▼ CPU GPU │ │ └──── NUMA ───┘ 로 시작하겠습니다. 중요한 운영 원칙 하나 GPU 1~4개짜리 serving Pod와 8-GPU serving Pod를 구분해서 생각하는 것이 좋습니다. GPU 1~4 Pod ──────────── 가능하면 CPU NUMA0 + GPU0~3 또는 CPU NUMA1 + GPU4~7 → NUMA locality 중요 GPU 8 Pod ───────── CPU NUMA0 + NUMA1 GPU0~7 NVSwitch 전체 → NUMA locality보다 NVLink/NVSwitch + TP/EP 최적화 중요 따라서 이 클러스터에서는 Topology Manager를 single-numa-node 로 고정하기보다 restricted 로 두는 것이 제가 권하는 기본안 입니다. 그리고 그 위에서 Dense 모델은 TP/DP , MoE 모델은 TP/DP/EP , KV cache는 HBM 우선 + 필요 시 CPU/MemKV offload 로 모델별 profile을 만드는 방식이 좋습니다. 네 모델 목록처럼 주간/야간 workload가 명확하다면, 다음 단계에서는 각 모델별로 GPU 수 / TP / DP / EP / 예상 HBM(weight) / KV-cache HBM / CPU core / NUMA / local NVMe cache 를 한 장짜리 배치표로 만드는 것 이 가장 유용합니다. 그 표가 나오면 “주간에는 GPU0~7을 어떻게 쪼개고, 야간에는 어떻게 재배치할지”까지 구체적으로 결정할 수 있습니다. == 맞습니다. NIC이 특정 NUMA에 명확하게 붙지 않는 topology라면 NIC까지 억지로 NUMA affinity 대상으로 묶는 것보다 CPU↔GPU locality를 우선 하는 게 좋습니다. 특히 inference 요청 트래픽 자체는 보통 model/KV 통신보다 작으므로, NIC locality는 multi-node TP/EP, remote KV cache, AIStor 대량 staging 이 있을 때 더 중요해집니다. 그리고 TP / DP / EP 는 “모델을 여러 GPU에 어떻게 나눠서 돌릴 것인가”를 정하는 서로 다른 축입니다. TP — Tensor Parallelism 한 모델의 tensor/weight 계산을 여러 GPU에 나눕니다. 예를 들어 모델 하나가 GPU 한 장에 안 들어가거나, 한 요청의 처리 속도를 높이고 싶다면: 하나의 Model │ Tensor Parallel = 4 │ ┌────────────┼────────────┐ ▼ ▼ ▼ GPU0 GPU1 ... GPU3 Weight Weight Weight 1/4 1/4 1/4 │ │ │ └───── collective ────────┘ NVLink/NVSwitch 각 transformer layer를 계산할 때 GPU끼리 자주 통신합니다. 그래서 TP는 GPU interconnect 성능에 매우 민감 합니다. B300 8-GPU NVSwitch 시스템이면 TP에 좋은 환경입니다. TP=1 → GPU간 TP communication 없음 TP=2 → GPU 2개가 하나의 model TP=4 → GPU 4개 TP=8 → GPU 8개 단순히 생각하면: TP = 모델 하나를 몇 GPU로 쪼갤 것인가 입니다. DP — Data Parallelism DP는 반대로 모델을 복제 합니다. 예를 들어 모델이 GPU 1장에 충분히 들어간다고 합시다. Load Balancer │ ┌────────────┼────────────┐ ▼ ▼ ▼ Request A Request B Request C │ │ │ GPU0 GPU1 GPU2 Model A Model A Model A replica replica replica GPU마다 동일한 model weight가 있습니다. 그래서: DP = 같은 모델을 몇 벌 만들어 요청을 병렬 처리할 것인가 입니다. Serving에서 동시 요청 처리량을 늘리는 데 매우 중요합니다. 예를 들어 8 GPU에서 모델 하나가 2 GPU를 요구한다면: TP=2 DP=4 GPU0 ─┐ ├ Model replica #1 GPU1 ─┘ GPU2 ─┐ ├ Model replica #2 GPU3 ─┘ GPU4 ─┐ ├ Model replica #3 GPU5 ─┘ GPU6 ─┐ ├ Model replica #4 GPU7 ─┘ 즉 전체 GPU 수는 간단한 경우: TP × DP 2 × 4 = 8 GPU 가 됩니다. 이 구성은 serving에서 매우 흔합니다. EP — Expert Parallelism EP는 MoE(Mixture of Experts) 모델에서만 특히 중요한 개념 입니다. MoE에서는 transformer 내부에 여러 expert가 있습니다. Token │ Router │ ┌─────────┼─────────┐ ▼ ▼ ▼ Expert 0 Expert 1 ... Expert N 모든 token이 모든 expert를 계산하는 게 아니라 router가 일부 expert를 선택합니다. 예를 들어: token A → expert 3, 17 token B → expert 8, 21 token C → expert 3, 11 처럼 됩니다. Expert가 많으면 한 GPU에 전부 넣기 어려우므로 여러 GPU에 분산합니다. EP=4 GPU0 ├ Expert 0 ├ Expert 1 └ Expert 2 GPU1 ├ Expert 3 ├ Expert 4 └ Expert 5 GPU2 ├ Expert 6 ├ Expert 7 └ Expert 8 GPU3 ├ Expert 9 ├ Expert 10 └ Expert 11 이게 Expert Parallelism 입니다. 즉: EP = MoE의 Expert들을 몇 GPU에 분산할 것인가 라고 생각하면 됩니다. TP와 EP의 결정적인 차이 둘 다 model을 여러 GPU에 나누니까 비슷해 보이지만 통신 패턴이 상당히 다릅니다. TP ──────────────────── GPU0 ←─────→ GPU1 ↑ ↑ │ AllReduce │ ↓ ↓ GPU2 ←─────→ GPU3 Tensor 계산 결과를 GPU들이 계속 교환 EP ──────────────────── Router │ token dispatch │ ┌──────────┼──────────┐ ▼ ▼ ▼ GPU0 GPU1 GPU2 Expert Expert Expert All-to-All TP는 AllReduce 계열 통신 , EP는 All-to-All token dispatch 가 중요합니다. 그래서 둘 다 NVLink/NVSwitch가 매우 유용하지만 EP는 특히 All-to-All network/interconnect 성능과 load balancing에 민감 합니다. TP + DP + EP를 동시에 사용할 수도 있습니다 예를 들어 8 GPU MoE serving을 생각해봅시다. 개념적으로: 8 GPU ┌─────────┴─────────┐ │ │ DP replica 0 DP replica 1 │ │ GPU0~3 GPU4~7 │ │ EP=4 EP=4 라면: DP = 2 EP = 4 형태입니다. 각 replica 내부의 expert를 4 GPU에 분산하고, 그런 serving replica를 두 개 만드는 겁니다. 요청은: Requests │ Load Balance / \ ▼ ▼ DP replica 0 DP replica 1 GPU0~3 GPU4~7 │ │ EP=4 EP=4 로 갑니다. 이 구조는 네 환경처럼 8 GPU B300 + NVSwitch 에서 검토할 가치가 큽니다. 그런데 TP × DP × EP = GPU 수 라고 이해하면 안 됩니다 이건 중요한 부분입니다. TP와 EP는 항상 독립적으로 GPU를 곱해서 사용하는 관계가 아닙니다. 예를 들어 vLLM에서 MoE expert parallel을 사용하면 TP
What RADAR observed and classified to build this opportunity. It is what the source published, not a verification that the offer is still active.
26O06b2. 가능합니다. 다만 여기서는 세 층을 분리해서 설계 하는 게 좋습니다. K8s: Pod가 CPU/GPU를 같은 NUMA에 받도록 한다. NVIDIA/NCCL: 한 모델에 여러 GPU를 쓸 때 NVLink/NVSwitch를 최대한 사용한다. vLLM: TP/DP/EP와 KV cache를 workload 특성에 맞춘다. 특히 B300 8-GPU 노드라면 “무조건 single-numa-node”가 정답은 아닙니다. 8-GPU 모델은 양쪽 NUMA를 사용해야 하기 때문입니다. 1. K8s에서 CPU ↔ GPU affinity GPU 노드 kubelet의 기본 방향은 다음입니다. # /var/lib/kubelet/config.yaml cpuManagerPolicy: static…
Open source