Загружаем каталог…
Загружаем каталог…
가능합니다. 다만 여기서는 세 층을 분리해서 설계 하는 게 좋습니다. 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
То, что RADAR обнаружил и классифицировал для этой возможности. Это опубликованный источником текст, а не подтверждение, что предложение ещё действует.
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…
Открыть источник