네. 첨부된 vLLM 테스트 스크립트 기준으로 보면, “B300 8-GPU 단일 노드 도입 검증 → 기본 기능 확인 → vLLM 추론 성능/운영 특성 확인”이라는 목적에는 꽤 잘 구성되어 있습니다.
특히 Stage 3a가 단순 TPS 측정에 그치지 않고 BF16/FP8, short/long context, 동시성, prefix cache, MoE/8B까지 기본 축을 잡고 있고 stage3a_vllm_benchmark, 그 이후에 설정 스윕 → mixed workload → soak → saturation → TP scaling → prefix A/B → RAG 순으로 확장한 구조가 좋습니다. 예를 들어 설정 스윕은 max-num-seqs, GPU memory utilization, chunked prefill, TP8×1 vs TP4×2를 분리해 비교하도록 되어 있습니다. stage3a2_vllm_config_sweep stage3a2_vllm_config_sweep
제가 검토하면서는 아래처럼 우선순위를 조금 정리해서 실행하는 것을 권합니다.
| 우선순위 | 테스트 | 판단하려는 것 | 의견 |
|---|---|---|---|
| P0 | 기본 HW/OS/GPU/NVLink/NVMe 검증 | 납품 장비 정상 여부 | 필수 |
| P0 | Stage 3a 기본 vLLM | 실제 모델 로딩/추론/기본 성능 | 필수 |
| P0 | 3a-7 TP Scaling | B300 8장의 scaling 특성 | 강력 추천 |
| P0 | 3a-8 Prefix Cache A/B | 캐시 기능 실제 동작 여부 | 추천 |
| P1 | 3a-2 Config Sweep | 운영 기본값 선정 | 추천 |
| P1 | 3a-3 Mixed Workload | 실제 서비스 간섭 | 추천 |
| P1 | 3a-6 Saturation | 최대 동시 처리 용량 | 추천 |
| P1 | 3a-9 RAG Context | 장문 입력 scaling | RAG 예정이면 추천 |
| P1 | 3a-4 Soak | 장시간 안정성 | 최종 인수 전에 추천 |
| P2 | 3a-5 Quality BF16/FP8 | 양자화 품질 | FP8 운영 시 수행 |
| P2 | 3a-10 KV Tiering/MemKV | KV offload 가치 | 이번 1차 검증에서는 후순위 |
1. TP=1/2/4/8 테스트는 꼭 유지하는 게 좋습니다.
현재 스크립트가 B300의 큰 HBM을 이용해 70B를 TP=1부터 올려보고, TP 증가에 따른 TTFT/ITL 및 GPU당 처리량 변화를 보도록 되어 있습니다. stage3a7_vllm_tp_scaling
이건 단순 vLLM 벤치마크보다 B300 노드 자체를 검증하는 데 상당히 중요한 테스트입니다. NVLink/NVSwitch나 GPU 간 통신 문제가 있으면 TP scaling에서 이상 징후가 나타날 가능성이 있기 때문입니다.
다만 TP=1 대비 TTFT +10~20%면 정상 같은 절대적인 Pass/Fail 기준은 조금 약하게 표현하는 게 좋습니다. stage3a7_vllm_tp_scaling
장비 인수 관점에서는 오히려 TP별 실제 결과를 baseline으로 보존하고, 비정상적인 역전/급락/특정 GPU 조합 문제를 확인하는 방식이 안전합니다.
2. Prefix Cache를 ON/OFF A/B로 따로 만든 것도 좋습니다.
같은 32k prefix로 ON/OFF를 비교하고, 단순 TTFT뿐 아니라 서버의 prefix-cache hit metric까지 확인합니다. stage3a8_vllm_prefix_cache_ab
이건 기능 검증 관점에서 상당히 좋습니다.
다만 여기의 5~10배 이상 단축 = 정상 역시 장비 Pass/Fail보다는 기대 효과 참고치로 두는 편이 좋습니다. stage3a8_vllm_prefix_cache_ab
즉,
Cache hit가 실제 발생한다 → 기능 PASS
TTFT가 얼마나 개선된다 → 성능 결과
로 분리하는 것을 권합니다.
3. Mixed workload도 실사용 검증으로 의미가 큽니다.
1k short request와 32k long request를 동시에 넣어서 long prefill 때문에 short request가 얼마나 영향을 받는지 보도록 되어 있습니다. stage3a3_vllm_mixed_workload
특히 B300에서 단순 최대 TPS보다 이 값이 서비스 설계에는 더 유용할 가능성이 큽니다.
4. Soak test도 인수 테스트에 포함시키는 것이 좋습니다.
현재 4시간 기본값으로 반복 inference를 수행하면서 GPU memory/temperature/power까지 30초 주기로 기록합니다. stage3a4_vllm_soak_test stage3a4_vllm_soak_test
다만 최종 인수 시험이라면 저는 4시간 smoke soak + 가능하면 overnight 8~12시간 soak 두 단계로 운영하겠습니다.
가장 먼저 볼 것은 Stage 3a-9의 64k 테스트입니다.
현재 max-model-len=65536인데 평균 입력을 63000, random-range-ratio=0.25, 출력 256으로 설정했습니다. stage3a9_vllm_rag_realistic stage3a9_vllm_rag_realistic
즉 입력 길이가 평균 63k에서 ±25%라면 상단 샘플은 65,536을 상당히 초과할 수 있습니다. 출력 토큰 여유도 필요합니다. 따라서 이 구간은 정상적인 64k 성능 측정보다 context overflow/error 테스트가 섞일 위험이 있습니다.
예를 들어 64k 구간만 RANGE_RATIO=0.02 정도로 제한하거나, 64k가 아니라 56k/60k 근방으로 잡는 것을 권합니다.
두 번째는 Stage 3a-6입니다. saturation test 자체는 매우 좋습니다. 64→128→192→256→384→512→768까지 올리면서 TTFT와 error rate로 capacity cliff를 찾도록 되어 있습니다. stage3a6_vllm_saturation_test
그런데 이번 목적이 “신규 B300 8장 노드의 기본 검증”이라면 KV tier별 saturation까지 동시에 수행하는 것은 조금 과합니다. 현재 스크립트는 none/fs/memkv를 비교하도록 확장되어 있는데 stage3a6_vllm_saturation_test, 1차 인수에서는 KV_TIERS=none으로 돌려서 순수 GPU/vLLM capacity cliff부터 확보하는 것을 추천합니다.
MemKV/KV tiering은 별도의 솔루션 검증 단계로 빼는 편이 결과 해석도 훨씬 깔끔합니다. Stage 3a-10 자체도 TCP 환경에서 baseline/local NVMe/MemKV를 비교하는 실험으로 설계되어 있으므로, 그 단계에서 따로 보는 게 맞습니다. stage3a10_vllm_kv_tier_comparis…
현재 기본 Stage 3a에서 Llama 70B에
--quantization fp8
을 사용하고 있습니다. stage3a_vllm_benchmark
그리고 품질 테스트에서는 BF16과 FP8을 MMLU/GSM8K로 비교합니다. stage3a5_vllm_quality_check
방향은 좋습니다. 다만 최종 보고서에는 FP8을 그냥 하나의 항목으로 쓰지 말고 checkpoint 자체가 FP8인지, runtime FP8 quantization인지, weight/activation/KV cache 중 무엇이 FP8인지를 명확하게 기록하는 것을 권합니다. 나중에 다른 B300/H200/H100 결과와 비교할 때 이 구분이 상당히 중요합니다.
평가 데이터셋을 air-gap 환경용으로 미리 cache하고, 실제 lm_eval task 생성 경로를 이용해 검증하는 구조는 좋습니다. 특히 MMLU의 57개 config가 빠지는 문제까지 고려되어 있습니다. stage3a5_prefetch_eval_datasets
전체 테스트를 세 개의 Gate로 나누겠습니다.
Gate 1 — Hardware Acceptance
8 GPU 인식 → ECC/Xid → NVLink/NVSwitch → GPU P2P/BW → HBM → NVMe → CPU/NUMA → power/thermal
여기서 실패하면 vLLM 테스트를 진행하지 않습니다.
Gate 2 — vLLM Functional Acceptance
70B BF16 load → OpenAI API → TP8 inference → TP1/2/4/8 → FP8 → long context → prefix cache
여기까지 통과하면 “B300 8-GPU 노드에서 vLLM 기본 기능 정상”이라고 판단할 수 있습니다.
Gate 3 — vLLM Performance Characterization
Config sweep → Short/Long concurrency → Mixed → Saturation → RAG → Soak
여기부터는 PASS/FAIL보다는 이 노드의 운영 baseline을 만드는 단계로 보는 게 좋습니다.
그리고 KV tier/MemKV, 품질 benchmark, 특수 workload는 그 다음 Advanced Validation으로 분리하겠습니다.
이렇게 하면 지금 만들어 놓은 많은 스크립트를 버릴 필요가 없으면서도, “장비가 정상인가?”와 “이 장비를 어떻게 튜닝해야 하는가?”가 섞이지 않습니다.
결론적으로 현재 계획은 상당히 잘 만들어져 있고, 테스트 항목 부족보다는 오히려 범위가 넓어진 상태입니다. 지금 단계에서는 테스트를 더 추가하기보다는 ① HW Acceptance / vLLM Functional / Performance Characterization으로 재분류하고, ② 각 항목의 Pass/Fail과 단순 참고 성능치를 분리하며, ③ Stage 3a-9 64k 조건을 수정하는 것이 가장 효과적입니다.
원하시면 다음 단계로 지금 첨부된 스크립트 전체를 기준으로 B300 8-GPU 인수검증 Test Matrix를 Stage / Test Item / Command·Script / Metric / Pass Criteria / 결과 기록 항목 형태로 한 장짜리 표로 정리해드릴 수 있습니다.
좋아. 첨부한 계획을 기준으로, “B300 8-GPU 노드 1대 도입 후 기본 인수검증 + vLLM 추론 검증” 범위에 맞춰 우선순위를 줄여서 정리하면 아래 구성이 가장 깔끔해 보여.
현재 스크립트는 이미 vLLM의 기본 서빙뿐 아니라 config sweep, mixed workload, saturation, RAG, soak, KV tier까지 상당히 넓게 준비돼 있다. stage3a_vllm_benchmark stage3a2_vllm_config_sweep 그래서 1차 인수에서는 전부 수행하기보다 Gate 방식으로 진행하는 걸 권장해.
| Stage | Test Item | 주요 확인 내용 | 기준 / 판단 | 우선순위 |
|---|---|---|---|---|
| 1. HW 기본 | GPU 인식 | B300 8장 정상 인식 | 8/8 정상 | P0 |
| GPU 상태 | ECC / Xid / 온도 / 전력 상태 | Critical error 없음 | P0 | |
| NVLink/NVSwitch | GPU 간 연결 상태 | 링크/토폴로지 이상 없음 | P0 | |
| GPU P2P | GPU↔GPU P2P 통신 | 전체 GPU pair 정상 | P0 | |
| HBM | GPU별 HBM 용량/오류 | 8 GPU 동일, 오류 없음 | P0 | |
| NVMe | 디스크 인식/기본 I/O | 모든 장치 정상 | P0 | |
| CPU/NUMA | CPU-GPU-NIC/NVMe affinity | 비정상 topology 없음 | P0 | |
| Thermal/Power | 부하 시 온도/전력 | throttle/비정상 reset 없음 | P0 | |
| 2. vLLM 기능 | Model Load | 70B BF16 모델 로딩 | 정상 로드 | P0 |
| API | OpenAI-compatible API | 정상 응답 | P0 | |
| TP=8 | 8 GPU tensor parallel | 정상 추론 | P0 | |
| TP Scaling | TP 1/2/4/8 | 각 구성 정상 동작 | P0 | |
| FP8 | FP8 모델/설정 | 정상 로드·추론 | P0 | |
| Long Context | 최대 context 근접 요청 | 정상 처리 | P0 | |
| Prefix Cache | 동일 prefix 재사용 | cache hit 확인 | P0 | |
| 3. vLLM 성능 | Short Prompt | 짧은 입력 workload | TPS/TTFT/ITL 기록 | P1 |
| Long Prompt | 긴 입력 workload | TPS/TTFT/ITL 기록 | P1 | |
| Config Sweep | max-num-seqs / GPU mem util | 최적점 탐색 | P1 | |
| Mixed Workload | short + long 동시 요청 | HOL 영향 측정 | P1 | |
| Saturation | concurrency 단계 증가 | capacity cliff 측정 | P1 | |
| RAG workload | 8K/16K/32K/64K급 | context별 성능 기록 | P1 | |
| Soak | 장시간 serving | 오류/latency/memory drift | P1 | |
| 4. Advanced | BF16 vs FP8 Quality | MMLU 등 품질 비교 | 품질 변화 기록 | P2 |
| KV Tier | none/NVMe/MemKV | 효과 비교 | P2 | |
| Remote KV | TCP 기반 MemKV | 효과/overhead 측정 | P2 |
특히 Stage 2까지 통과하면 “노드와 vLLM의 기본 기능은 정상”이라고 판단하고, Stage 3은 합격/불합격보다는 이 장비의 성능 baseline을 만드는 과정으로 보는 게 좋다.
1차 도입 검증은 다음 순서로 돌리는 게 좋겠다.
① HW Acceptance → ② vLLM Smoke → ③ TP Scaling → ④ BF16/FP8 → ⑤ Long Context → ⑥ Prefix Cache → ⑦ Config Sweep → ⑧ Mixed/Saturation → ⑨ RAG → ⑩ Soak
첨부된 기본 benchmark 스크립트에는 이미 70B BF16/FP8 short·long, prefix caching, DeepSeek-R1, 8B 시나리오가 들어가 있으므로, 이걸 vLLM 기본 baseline의 중심으로 사용하면 된다. stage3a_vllm_benchmark
TP 검증도 별도 스크립트가 TP 1/2/4/8을 비교하도록 되어 있어서 그대로 활용하기 좋다. 다만 현재 스크립트의 “+10~20% 정도면 정상” 같은 수치는 Acceptance PASS 기준으로 고정하지 않는 것을 권장한다. 첫 노드에서는 TP별 throughput/latency를 baseline으로 저장하고, GPU pair 이상이나 TP 증가 시 비정상적인 성능 역전이 있는지를 보는 편이 낫다. stage3a7_vllm_tp_scaling
이 부분이 꽤 중요하다.
예를 들어 Prefix Cache는 현재 계획처럼 동일한 32K prefix로 ON/OFF를 비교하는 방식이 좋다. stage3a8_vllm_prefix_cache_ab 다만 “5~10배 빨라야 PASS”보다는,
기능 Acceptance: Cache ON → 실제 cache hit 발생 → 정상 응답 → PASS
성능 Characterization: Cache OFF 대비 TTFT가 얼마나 개선되는지 기록
으로 분리하는 게 좋다. 현재 스크립트의 5~10x 등의 값은 참고용 성능 기대치로 남겨두면 된다. stage3a8_vllm_prefix_cache_ab
Mixed workload도 마찬가지다. 현재 계획은 short-only / long-only를 먼저 측정하고 short+long을 동시에 수행해 degradation을 계산하므로 방법 자체는 좋다. stage3a3_vllm_mixed_workload 다만 “10~20% OK / 50% 이상 BAD” 같은 값은 인수 PASS/FAIL보다는 baseline 해석 지표로 두는 걸 추천한다. stage3a3_vllm_mixed_workload
첫째, RAG 64K 테스트는 수정하는 게 좋다. 현재 max-model-len=65536인데 stage3a9_vllm_rag_realistic 64K workload가 평균 약 63,000 token에 random-range-ratio=0.25를 사용한다. stage3a9_vllm_rag_realistic 그러면 일부 입력은 65,536을 넘어갈 수 있고 output token까지 있으므로 long-context 성능이 아니라 context overflow 오류가 섞일 가능성이 있다.
예를 들면 8K / 16K / 32K / 56K로 바꾸거나, 64K급만 random range를 크게 줄이는 방법이 더 적절하다.
둘째, saturation 1차 테스트는 KV_TIERS=none부터 시작하는 게 좋다. 현재 saturation 스크립트는 none/fs/memkv tier를 지원하고 concurrency 64→768까지 올리도록 되어 있다. stage3a6_vllm_saturation_test 처음에는 외부 KV 계층 영향을 제거하고 순수 B300 + vLLM capacity를 baseline으로 잡은 뒤 KV tier를 붙이는 게 비교가 훨씬 명확하다.
셋째, Soak는 현재 4시간이면 1차 검증으로 충분하다. 스크립트가 4시간 동안 GPU 상태를 주기적으로 수집하고 first/last quarter latency drift도 비교하도록 되어 있어서 smoke soak로는 상당히 괜찮다. stage3a4_vllm_soak_test stage3a4_vllm_soak_test 최종 인수 시 필요하면 별도로 overnight 8~12시간 정도를 추가하는 구조가 좋겠다.
결국 1차 목표는 “성능을 최대한 뽑는 것”보다 “정상 장비임을 증명하고 재현 가능한 baseline을 남기는 것”으로 잡는 게 좋다. 그래서 결과물도 PASS/FAIL만 남기지 말고 SW version + Model + TP + Input/Output length + Concurrency + TTFT + ITL + Output TPS + GPU utilization + HBM usage + Power를 한 세트로 보관하는 것을 권장한다.
다음 단계로는 이 내용을 바로 현장에서 쓸 수 있게 B300 8-GPU 인수검증 체크리스트 형태(테스트 명 / 실행 명령·스크립트 / 기대 결과 / 실제 결과 / PASS·FAIL / 비고)로 만들어두면 가장 유용하다.
좋아. 현장에서 바로 체크하면서 쓸 수 있도록 기능 인수검증(PASS/FAIL)과 성능 Baseline 기록을 한 표에 같이 넣는 형태로 정리하면 아래와 같아. 첨부한 스크립트의 테스트 흐름과 파라미터를 기준으로 구성했어.
| # | 단계 | 테스트 명 | 실행 명령·스크립트 | 기대 결과 / 판정 기준 | 실제 결과 | P/F | 비고 |
|---|---|---|---|---|---|---|---|
| 1 | HW | GPU 인식 | nvidia-smi | B300 GPU 8/8 인식 | ☐ | GPU UUID/SN 기록 | |
| 2 | HW | GPU 상태 | nvidia-smi -q | ECC/Xid 등 Critical Error 없음 | ☐ | Driver/FW 기록 | |
| 3 | HW | GPU Topology | nvidia-smi topo -m | 8 GPU topology 정상 | ☐ | CPU/NUMA affinity 포함 | |
| 4 | HW | NVLink/NVSwitch | NVLink 상태/토폴로지 점검 | 모든 GPU 연결 정상, link error 없음 | ☐ | 링크 상태 저장 | |
| 5 | HW | GPU P2P | P2P bandwidth/latency test | GPU pair 간 통신 정상 | ☐ | BW matrix 저장 | |
| 6 | HW | HBM | GPU memory test | 8 GPU 모두 오류 없음 | ☐ | GPU별 결과 | |
| 7 | HW | NVMe | nvme list, I/O test | 전체 NVMe 정상 인식/동작 | ☐ | BW/IOPS 기록 | |
| 8 | HW | CPU/NUMA | lscpu, numactl -H, topology | GPU/CPU/NUMA 구성 정상 | ☐ | topology 저장 | |
| 9 | HW | Power/Thermal | GPU load + nvidia-smi | throttle/reset/Xid 없음 | ☐ | Max temp/power 기록 | |
| 10 | vLLM | BF16 Model Load | Stage 3a / 70B BF16 | 모델 정상 load | ☐ | Model revision 기록 | |
| 11 | vLLM | API Smoke | /v1/models, /v1/chat/completions 등 | OpenAI-compatible API 정상 응답 | ☐ | HTTP/error 확인 | |
| 12 | vLLM | TP=8 추론 | Stage 3a / TP=8 | 8 GPU 사용, 정상 inference | ☐ | GPU util 확인 | |
| 13 | vLLM | Short Prompt | Stage 3a short workload | 요청 성공, TTFT/ITL/TPS 수집 | ☐ | Baseline | |
| 14 | vLLM | Long Prompt | Stage 3a long workload | 요청 성공, TTFT/ITL/TPS 수집 | ☐ | Baseline | |
| 15 | vLLM | FP8 Model | Stage 3a FP8 | 모델 load 및 inference 정상 | ☐ | FP8 방식 명시 | |
| 16 | vLLM | Long Context | Stage 3a long context | 설정 범위 내 요청 정상 처리 | ☐ | input/output token 기록 | |
| 17 | vLLM | TP=1 | Stage 3a-7 | 정상 load/inference | ☐ | TPS/TTFT | |
| 18 | vLLM | TP=2 | Stage 3a-7 | 정상 load/inference | ☐ | TPS/TTFT | |
| 19 | vLLM | TP=4 | Stage 3a-7 | 정상 load/inference | ☐ | TPS/TTFT | |
| 20 | vLLM | TP=8 | Stage 3a-7 | 정상 load/inference | ☐ | TPS/TTFT | |
| 21 | vLLM | Prefix Cache OFF | Stage 3a-8 OFF | 정상 inference | ☐ | TTFT baseline | |
| 22 | vLLM | Prefix Cache ON | Stage 3a-8 ON | Cache hit 확인 + 정상 inference | ☐ | TTFT 개선율 | |
| 23 | PERF | max-num-seqs | Stage 3a-2 / 64,128,256 | 각 설정 정상 수행 | ☐ | 최적값 기록 | |
| 24 | PERF | GPU Memory Util | Stage 3a-2 / .85,.90,.95 | OOM 없이 수행 | ☐ | throughput 비교 | |
| 25 | PERF | Chunked Prefill | Stage 3a-2 ON/OFF | 두 설정 정상 수행 | ☐ | TTFT/TPS 비교 | |
| 26 | PERF | TP Replica | Stage 3a-2 TP8×1 vs TP4×2 | 두 구성 정상 수행 | ☐ | throughput 비교 | |
| 27 | PERF | Mixed Workload | Stage 3a-3 | short+long 동시 수행 성공 | ☐ | degradation 기록 | |
| 28 | PERF | Saturation | Stage 3a-6 / KV_TIERS=none | concurrency별 측정 성공 | ☐ | capacity cliff 기록 | |
| 29 | PERF | RAG 8K | Stage 3a-9 | 정상 수행 | ☐ | TPS/TTFT | |
| 30 | PERF | RAG 16K | Stage 3a-9 | 정상 수행 | ☐ | TPS/TTFT | |
| 31 | PERF | RAG 32K | Stage 3a-9 | 정상 수행 | ☐ | TPS/TTFT | |
| 32 | PERF | RAG Long | Stage 3a-9 수정 | 최대 context 이하에서 정상 수행 | ☐ | 56K 등 권장 | |
| 33 | STABILITY | 4h Soak | Stage 3a-4 | crash/OOM/Xid 없음 | ☐ | 1차 soak | |
| 34 | STABILITY | Latency Drift | Stage 3a-4 | first/last 구간 비교 | ☐ | % 기록 | |
| 35 | STABILITY | GPU Memory | Stage 3a-4 | 비정상 지속 증가 없음 | ☐ | leak 여부 | |
| 36 | STABILITY | GPU Health | Stage 3a-4 | 8 GPU 정상 유지 | ☐ | temp/power/Xid |
Stage 3a의 기본 benchmark에는 BF16/FP8 short·long 및 prefix caching 등의 시나리오가 이미 포함되어 있다. stage3a_vllm_benchmark Config sweep도 max-num-seqs=64/128/256, GPU memory utilization .85/.90/.95, chunked prefill ON/OFF 및 TP8×1/TP4×2 비교가 준비되어 있으므로 #23~26에 그대로 대응시킬 수 있다. stage3a2_vllm_config_sweep
각 성능 테스트 결과는 PASS/FAIL만 적지 말고 아래 필드를 공통으로 남기는 것을 권장해.
| 항목 | 기록값 |
|---|---|
| Date / Node | |
| GPU | B300 × 8 |
| Driver Version | |
| CUDA Version | |
| vLLM Version | |
| PyTorch Version | |
| Model / Revision | |
| Precision | BF16 / FP8 |
| TP | 1 / 2 / 4 / 8 |
gpu-memory-utilization | |
max-model-len | |
max-num-seqs | |
| Input Tokens | |
| Output Tokens | |
| Concurrency | |
| Request Success | |
| Error Rate | |
| TTFT Avg / P50 / P95 / P99 | |
| ITL Avg / P95 / P99 | |
| Output TPS | |
| Request Throughput | |
| GPU Util Avg/Max | |
| HBM Used Avg/Max | |
| GPU Power Avg/Max | |
| GPU Temp Max | |
| 비고 |
첨부한 Stage 3a가 TTFT/ITL histogram snapshot과 serving benchmark 결과를 수집하도록 구성되어 있으므로 이 양식과 잘 맞는다. stage3a_vllm_benchmark
Gate 1 — Hardware Acceptance: #1~9가 모두 정상이어야 다음 단계로 진행. 특히 GPU 8장 중 한 장이라도 Xid/ECC/P2P/NVLink 계열 이상이 확인되면 vLLM 성능 측정 전에 HW 문제부터 분리하는 게 좋다.
Gate 2 — vLLM Functional Acceptance: #10~22를 수행한다. 여기서는 성능 수치 자체보다 모델 load, API, TP, FP8, long context, prefix cache 기능이 실제로 정상 동작하는지를 PASS/FAIL 기준으로 잡는다. Prefix cache의 경우 현재 스크립트가 동일 32K prefix를 이용해 ON/OFF를 비교하도록 되어 있다. stage3a8_vllm_prefix_cache_ab
Gate 3 — Performance Baseline: #23~32는 PASS/FAIL보다 장비 baseline 확보가 핵심이다. Mixed workload도 short-only/long-only와 mixed를 비교해 degradation을 측정하는 구조이므로 수치를 그대로 baseline으로 보관하면 된다. stage3a3_vllm_mixed_workload Saturation 역시 우선 KV tier 없이 수행하고 concurrency 증가에 따른 capacity cliff를 기록하는 방향이 적절하다. 현재 스크립트는 concurrency 64~768 범위를 지원한다. stage3a6_vllm_saturation_test
Gate 4 — Stability: 마지막 #33~36에서 4시간 soak를 수행한다. 현재 스크립트의 기본값이 4시간이고 5분 단위 cycle이며, GPU 상태를 별도로 추적하도록 되어 있다. stage3a4_vllm_soak_test 여기까지 정상이라면 “B300 8-GPU 단일 노드 기본 인수 + vLLM 기본 기능/성능 baseline 확보 완료”로 정리하는 구조가 좋다.
그리고 MMLU BF16↔FP8 품질 비교, NVMe KV tier, MemKV/TCP 비교는 이번 체크리스트에서는 빼고 Advanced Validation 별도 시트로 분리하는 것을 추천해. 현재 KV tier 테스트는 baseline/local NVMe/MemKV까지 비교하는 구조라 기본 인수 범위를 꽤 넘어간다. stage3a10_vllm_kv_tier_comparis…
이 표를 실제 현장에서 쓰려면 엑셀(.xlsx)로 만들어 01_Overview / 02_HW_Acceptance / 03_vLLM_Function / 04_Performance / 05_Soak / 06_Result_Summary 6개 시트로 구성하는 게 가장 실용적이야. 각 항목에 PASS/FAIL 드롭다운과 결과 입력란까지 넣으면 그대로 인수검증 결과서로 사용할 수 있어.
응. 이번에 올린 실행 가이드까지 포함해서 보면, 현재 단계의 범위를 더 명확히 줄이는 게 좋습니다. 문서 전체는 향후 확장까지 고려해 상당히 넓게 만들어져 있지만, 지금 목적은 “B300 8-GPU 노드가 정상이고, K8s에 편입했을 때 GPU/vLLM 서비스가 정상적으로 운용되는가”이므로 모든 Stage를 돌릴 필요는 없습니다.
특히 Stage6는 그대로 전부 실행하기보다 필수 K8s Acceptance / 운영 준비 / 향후 고급 검증으로 나누는 것을 권장합니다.
제가 권장하는 최종 범위는 아래입니다.
| Gate | 범위 | 이번 수행 |
|---|---|---|
| Gate 0 | OS/Driver/CUDA/Fabric Manager/기본 환경 | 필수 |
| Gate 1 | Stage1 HW 무결성 | 필수 |
| Gate 2 | Stage2 Network + Local NVMe | 필수 |
| Gate 3 | Stage3a vLLM 기본 기능/기본 성능 | 필수 |
| Gate 4 | K8s GPU 인프라 검증 | 필수 |
| Gate 5 | K8s vLLM 서비스 검증 | 필수 |
| Gate 6 | Cilium/ClusterMesh/NetworkPolicy/Observability | 필수/조건부 |
| Stage3b Triton/TRT-LLM | 다른 inference engine 비교 | SKIP |
| Stage3c SGLang | 다른 inference engine 비교 | SKIP |
| Stage3d AIPerf | 통합 inference benchmark | SKIP |
| Stage3a5 | MMLU/GSM8K 품질평가 | SKIP |
| Stage3a10 | KV tier/MemKV inference | SKIP |
| Stage4 | 학습 | SKIP |
| Stage5 | 기존 bare-metal cluster 연동 suite | SKIP |
| Stage6d | Spark burst inference 부하 | SKIP(현재) |
| Stage6j | bandwidth contention/QoS | SKIP(현재) |
| Stage6g | ClusterMesh partition/chaos | SKIP(초기 인수) |
이렇게 해도 이번 목적에는 충분합니다.
현재 README는 Stage3 이후 Triton, SGLang, 학습, Stage5까지 확장하도록 구성되어 있는데 README, 지금은 그 부분을 수행 범위에서 제외하는 게 맞습니다.
여기는 기존 계획을 거의 그대로 유지하면 됩니다.
GPU/PCIe → NVLink/NVSwitch → ECC/XID → DCGM → NCCL → FP8/FP4 Tensor Core → Power/Thermal/Soak
특히 Stage1은 성능 벤치마크라기보다는 신품 B300 노드 자체의 인수검사이므로 빼면 안 됩니다.
문서에 정의된 핵심 결과 파일도 잘 구성되어 있습니다. GPU 8장 인식, PCIe downgrade, NVLink error, XID 전후 비교, DCGM, FP8/FP4 stress, gpu-burn 및 throttling까지 한 번에 확인할 수 있습니다. 01_USAGE_GUIDE_RHEL10_baremetal
판정은 현재 gate_criteria.yaml처럼 XID=0, ECC Uncorrected=0, PCIe downgrade=0, gpu-burn DIED=0, DCGM fail=0을 hard fail로 두는 방향이 적절합니다. gate_criteria
다만 앞서 이야기한 것처럼 NCCL bandwidth 같은 성능 수치는 장비 인수계약/벤더 스펙이 최우선입니다. 현재 해설서 자체도 Pass Criteria 수치는 참고 임계치이며 정식 스펙/SLA가 우선한다고 명시하고 있습니다. 07_STAGE1_2_3A_TEST_GUIDE
이것도 유지합니다.
다만 현재 단계에서는 MemKV 관련 Stage2c는 SKIP하겠습니다.
즉,
NIC 상태 → NUMA → iperf single/multi → NIC error/FEC → Local NVMe fio → NVMe SMART
정도까지만 수행하면 충분합니다.
MinIO가 이미 실제 운영 환경에서 사용될 예정이라면 MinIO read/cold-load baseline은 수행 가치가 높습니다. 나중에 K8s/ClusterMesh를 통과한 뒤 같은 MinIO를 다시 측정하면 다음 비교가 가능하기 때문입니다.
Bare Metal B300 → MinIO
vs
B300 Pod → Cilium/ClusterMesh → MinIO
이 비교는 꽤 중요합니다.
Stage2 해설서도 네트워크 → MinIO → Local NVMe 순으로 병목 위치를 분리하도록 설계되어 있습니다. 07_STAGE1_2_3A_TEST_GUIDE
여기는 기존 계획보다 꽤 줄여도 됩니다.
70B BF16을 기준 모델 하나로 고정하는 것을 권장합니다.
그리고 다음만 봅니다.
즉 기존 Stage3a + 3a7 + 3a8 + 3a4 정도가 중심입니다.
Config sweep인 3a2는 필요하면 수행하되 Acceptance 이후 tuning 단계로 봐도 됩니다.
반대로 이번에는 다음을 과감히 빼겠습니다.
DeepSeek-R1 / 8B / MMLU / GSM8K / SGLang / TRT-LLM / AIPerf / MemKV / KV Tier / RAG 현실 workload
현재 air-gap 문서도 Llama 70B 외에 8B, DeepSeek, GPT-OSS 등을 각 특수 시나리오용으로 요구하고 있습니다. 02_AIRGAP_DOWNLOAD_CHECKLIST 이번 범위를 이렇게 줄이면 대용량 DeepSeek-R1이나 GPT-OSS를 굳이 반입할 필요도 없습니다.
이건 운영 준비 부담을 꽤 줄여줍니다.
여기는 필요합니다.
오히려 실제 운영이 K8s라면 저는 Stage6를 단순 “추가 테스트”가 아니라 두 번째 Acceptance Gate로 보는 게 맞다고 생각합니다.
이유는 간단합니다.
Bare metal에서
NCCL 정상
NVLink 정상
GPU 8장 정상
vLLM 정상
이어도 K8s 위에서는 GPU Operator, device plugin, CPU/NUMA topology, pod scheduling, CNI, NetworkPolicy 등의 영향으로 결과가 달라질 수 있기 때문입니다.
현재 Stage6 문서도 정확히 이 취지로 bare-metal 결과가 K8s + ClusterMesh에서도 유지되는지 재검증하도록 구성되어 있습니다. 06_STAGE6_K8S_CLUSTERMESH_GUIDE
이게 가장 먼저입니다.
stage6c_k8s_gpu_topology_check.sh
목표는 간단합니다.
TP=8 Pod가 B300 8장을 제대로 할당받았는가?
그리고 그 8장이 bare-metal에서 봤던 NVLink/NVSwitch topology 그대로인가?
현재 Stage6도 GPU Operator/Topology Manager 및 TP=8 Pod의 NVLink topology 보존을 확인하도록 설계되어 있습니다. 06_STAGE6_K8S_CLUSTERMESH_GUIDE
현장에서는 최소한 다음을 남겨야 합니다.
kubectl describe node, GPU allocatable=8, GPU Operator/device plugin 상태, Pod 내부 nvidia-smi, Pod 내부 nvidia-smi topo -m, GPU 8/8 allocation.
Bare metal topology와 Pod 내부 topology가 일치해야 PASS로 보는 게 좋습니다.
stage6a_k8s_nccl_revalidation.sh
이것도 매우 중요합니다.
Bare metal Stage1에서 NCCL baseline을 만들어놓고, 동일 노드의 Pod 안에서 다시 NCCL을 실행합니다.
현재 스크립트도 STAGE1_NCCL_BASELINE을 받을 수 있도록 되어 있습니다. 04_ENVIRONMENT_VARIABLES_REFERE…
제가 권장하는 판정 방식은 단순합니다.
Bare Metal NCCL = 기준값
K8s Pod NCCL = 비교값
K8s에 올렸다는 이유만으로 NCCL 성능이 눈에 띄게 떨어진다면 원인을 찾아야 합니다.
Stage6 가이드도 A/B/C 결과가 bare-metal 대비 크게 벌어지면 K8s overhead로 그냥 받아들이지 말고 device plugin, CNI, Topology Manager 등을 확인하도록 되어 있습니다. 06_STAGE6_K8S_CLUSTERMESH_GUIDE
여기서 현재 Stage6 계획에 한 가지 보완을 권장합니다.
Stage6에는 NCCL, topology, network 등의 검증은 잘 들어가 있는데, 제가 보기에는 Acceptance 관점에서 다음 테스트를 별도 항목으로 명확하게 넣는 게 좋습니다.
K8s vLLM Functional Acceptance예를 들어:
Deployment/StatefulSet 생성
↓
GPU 8개 request
↓
TP=8 vLLM 기동
↓
Pod Ready
↓
Service Endpoint 등록
↓
/v1/models
↓
/v1/chat/completions
↓
short prompt
↓
long prompt
↓
Pod 내부 GPU 8장 utilization 확인
여기서는 bare-metal Stage3 성능을 다시 풀 벤치마크할 필요는 없습니다.
동일 70B BF16 + 동일 TP8 + 동일 대표 workload 2~3개만 재실행하면 됩니다.
그리고 결과를:
Bare metal vLLM baseline
K8s vLLM baseline
으로 비교합니다.
이 테스트가 실제 운영 방식에 가장 가까운 최종 Acceptance가 됩니다.
stage6b_k8s_network_revalidation.sh
이것도 수행하는 게 좋습니다.
구조를 다음처럼 나눠서 결과를 저장하세요.
Host → Host
Pod → Same Cluster Pod
Pod → Remote Cluster Pod/Service
Pod → ClusterMesh Global Service
그러면 문제가 발생했을 때
NIC인가?
K8s인가?
Cilium인가?
ClusterMesh인가?
를 분리할 수 있습니다.
현재 Stage6b는 바로 이 목적으로 Stage2 iperf 결과와 Pod-to-Pod/ClusterMesh 결과를 비교하도록 되어 있습니다. 06_STAGE6_K8S_CLUSTERMESH_GUIDE
운영 모델을 MinIO에서 가져오는 구조라면 필수로 올리는 게 좋습니다.
stage6e_clustermesh_minio_coldload.sh
비교 구조는:
Stage2
B300 Host ───────────────→ MinIO
Stage6
B300 vLLM Pod → Cilium → ClusterMesh → MinIO
입니다.
이렇게 하면 K8s 전환 후 모델 cold-load 경로에 구조적인 병목이 생겼는지 바로 알 수 있습니다.
Stage6e도 ClusterMesh Global Service를 통한 MinIO 접근을 검증하도록 설계되어 있습니다. 06_STAGE6_K8S_CLUSTERMESH_GUIDE
이건 성능 테스트가 아니라 접근통제 기능 테스트입니다.
허용되어야 할 client → vLLM은 성공하고,
허용되지 않은 namespace/pod → vLLM은 차단되어야 합니다.
즉 단순하게:
Allowed Client → vLLM → PASS
Denied Client → vLLM → BLOCK
두 가지를 반드시 확인하면 됩니다.
이것도 하는 게 좋습니다.
실제 운영에서 장애가 났을 때
요청이 Pod까지 왔나?
NetworkPolicy에서 drop됐나?
ClusterMesh에서 끊겼나?
를 보려면 Hubble이 매우 유용하기 때문입니다.
현재 Stage6도 NetworkPolicy 양성/음성 테스트와 Hubble flow/drop 관측을 각각 별도 테스트로 두고 있습니다. 06_STAGE6_K8S_CLUSTERMESH_GUIDE
stage6f_k8s_resilience_test.sh
여기에는 node drain / PDB / Readiness가 들어가 있습니다.
그런데 B300 8-GPU 노드가 현재 딱 1대라면 이 테스트를 그대로 해석하면 안 됩니다.
GPU 노드가 1대뿐인데 그 노드를 drain하면 TP=8 vLLM Pod가 이동할 다른 8-GPU 노드가 없습니다.
따라서 이번에는:
Readiness/Liveness/Startup Probe → 테스트
Pod delete/restart → 테스트
vLLM process crash 후 Pod recovery → 테스트
PDB 설정 검증 → 테스트
까지는 수행하고,
Node drain 후 서비스 지속성 → N/A
로 두는 게 맞습니다.
노드 한 대에서 node drain 후에도 inference가 계속 살아있기를 기대하는 것은 K8s 설정 문제가 아니라 물리적인 GPU capacity 부재 문제입니다.
stage6g_clustermesh_partition_test.sh
ClusterMesh 연결을 실제로 끊는 테스트입니다.
문서도 이 테스트와 node drain 테스트는 운영 영향을 줄 수 있으므로 maintenance window에서 수행하라고 명시하고 있습니다. 06_STAGE6_K8S_CLUSTERMESH_GUIDE
첫 B300 한 대의 인수 단계에서는 굳이 여기까지 할 필요는 없습니다.
ClusterMesh 정상 상태 / Global Service 정상 / NetworkPolicy 정상 / Hubble 정상
까지만 확인하고,
실서비스 구성 완료 후 별도 Chaos/DR Test 단계로 넘기는 것을 권장합니다.
6d Spark burst는 실제 Spark형 burst workload를 vLLM에 넣는 테스트입니다.
즉 지금 말씀하신 “아직 다른 추론 테스트까지 할 단계는 아니다”라는 범위와 맞지 않습니다.
따라서 SKIP.
6j bandwidth contention도 Compute cluster의 noisy neighbor가 GPU node에 미치는 영향을 보는 상당히 실전적인 테스트지만, 기본 인수검증보다 운영 성능 검증에 가깝습니다.
이것도 이후로 넘기는 게 좋습니다.
테스트는 줄여도 K8s 관련 air-gap artifact 준비는 미리 해놓아야 합니다.
현재 문서에는 Stage6용으로 kubectl, cilium, hubble과 테스트용 PyTorch/CUDA/iperf3/MinIO mc/curl 이미지를 반입하도록 되어 있습니다. 02_AIRGAP_DOWNLOAD_CHECKLIST
특히 Cilium과 GPU Operator 이미지를 고정 목록으로 관리하지 않고 실제 설치할 Helm values를 렌더링해서 필요한 이미지 목록을 추출하도록 한 방향은 좋습니다. ClusterMesh/Hubble/MIG 등의 옵션에 따라 필요한 이미지가 달라질 수 있기 때문입니다. 02_AIRGAP_DOWNLOAD_CHECKLIST
그리고 장기 운영을 생각하면 각 노드에 podman load를 반복하기보다는 사내 private registry를 두는 방향이 더 적절합니다. 현재 문서에도 같은 방향이 제시되어 있습니다. 02_AIRGAP_DOWNLOAD_CHECKLIST
이번 B300 도입은 결국 아래 정도면 충분하다고 봅니다.
Gate 0
OS / Driver / CUDA / Fabric Manager
↓
Gate 1
Stage1 HW Acceptance
GPU / PCIe / NVLink / ECC / XID
DCGM / NCCL / Tensor Core / Soak
↓
Gate 2
Stage2 Infrastructure
NIC / iperf / NVMe / SMART
(+ MinIO baseline)
↓
Gate 3
Bare-metal vLLM
70B BF16 / TP8 / API
Short / Long
TP scaling / Prefix cache
4h Soak
↓
========== Bare Metal PASS ==========
↓ K8s 편입
Gate 4
K8s GPU Infrastructure
GPU Operator / Device Plugin
GPU 8/8 allocation
Topology Manager
Pod 내부 NVLink topology
Stage6c
↓
Stage6a
Pod NCCL
vs Bare-metal NCCL
↓
Stage6b
Pod / Cilium / ClusterMesh Network
vs Bare-metal iperf
↓
Gate 5
K8s vLLM TP=8
70B BF16
Pod Ready
Service
API
Short / Long
vs Bare-metal vLLM
↓
Gate 6
Stage6e MinIO / Global Service
Stage6h NetworkPolicy
Stage6i Hubble
↓
Pod restart / Readiness / PDB
↓
========== K8s Acceptance PASS ==========
그리고 이번에는 명시적으로 SKIP:
Training / DeepSeek / 8B / MMLU-GSM8K / TRT-LLM / SGLang / AIPerf / MemKV-KV tier / Spark burst / bandwidth contention / ClusterMesh partition chaos
로 남겨두면 범위가 상당히 명확해집니다.
한 가지 더 중요한 부분은 gate_criteria.yaml도 이번 범위에 맞춰 수정해야 한다는 것입니다. 현재 default_missing_data_policy: fail인데 gate_criteria, 동시에 Stage3a5 품질검증과 Stage4 MFU가 gate에 포함되어 있습니다. gate_criteria 지금처럼 Stage3a5/Stage4를 의도적으로 SKIP하면 정상적인 이번 Acceptance가 missing data 때문에 FAIL될 가능성이 있습니다.
따라서 이번에는 별도의 gate_criteria_b300_acceptance.yaml을 만드는 게 가장 깔끔합니다. 여기에 Stage1 + Stage2 핵심 + Stage3a 기본 + Stage6a/b/c + K8s vLLM + 6h/6i만 넣고, 이것을 실제 장비 인수의 최종 PASS/FAIL 기준으로 사용하는 구조를 추천합니다.