Điều Phối Workload Suy Luận LLM Phân Tán Với KServe, Ray Và Dynamic GPU Bin-Packing Trên K8s
Điều Phối Workload Suy Luận LLM Phân Tán Với KServe, Ray Và Dynamic GPU Bin-Packing Trên Kubernetes
Triển khai các mô hình ngôn ngữ lớn (LLM) như Llama-3-70B, DeepSeek-V3, hoặc Mixtral-8x22B trong môi trường Production đặt ra những thách thức nghiêm trọng về hạ tầng. Việc chạy mô hình trên một GPU đơn lẻ là điều không thể đối với các mô hình vượt quá 30 tỷ tham số do giới hạn VRAM. Kiến trúc doanh nghiệp bắt buộc phải áp dụng Tensor Parallelism (TP) và Pipeline Parallelism (PP) trải rộng trên nhiều GPU và nhiều Node.
Tuy nhiên, việc cấp phát GPU tĩnh dẫn đến phân mảnh tài nguyên, hiệu suất tính toán GPU cực thấp (thường dưới 20%), và chi phí đám mây đắt đỏ. Bài viết kĩ thuật này cung cấp một framework cấp doanh nghiệp để điều phối các công việc suy luận LLM phân tán trên Kubernetes. Bằng cách kết hợp KServe (Control Plane phục vụ model), Ray Serve (Runtime tính toán phân tán), cùng Kueue và Karpenter (Gom cụm dynamic GPU bin-packing nhận biết nhận dạng topology), chúng ta có thể đạt được autoscaling tốc độ cao, tối ưu hóa giao tiếp NVLink giữa các GPU và tối đa hóa mật độ phần cứng.
1. Tổng Quan Kiến Trúc Doanh Nghiệp
Control Plane phân tách việc định nghĩa workload, điều phối phân tán và cấp phát hạ tầng thành các lớp độc lập:
- KServe (v0.13+): Lớp Ingress Control Plane bên ngoài, cung cấp endpoint REST/gRPC thống nhất, triển khai Blue-Green Canary, chính sách tự động mở rộng theo hàng đợi (queue depth) và tính năng scale-to-zero.
- Ray & RayCluster: Quản lý việc thực thi Tensor và Pipeline Parallelism. Ray điều phối các Python worker trên các node vật lý, duy trì topology của worker và giao tiếp IPC độ trễ thấp thông qua Shared Memory (Plasma Store).
- vLLM Engine: Chạy bên trong các Ray Actor, tận dụng PagedAttention và Continuous Batching để tối đa hóa băng thông token và hiệu suất VRAM.
- Kueue & Karpenter: Kueue đóng vai trò là hệ thống hàng đợi công việc để thực thi quota GPU đa người dùng, trong khi Karpenter cấp phát động các node GPU linh hoạt (ví dụ: NVIDIA H100 SXM5 vs A100 80GB PCIe) và áp dụng chiến lược Bin-packing Consolidation.
Quy tắc kiến trúc: Không bao giờ cho phép Kubernetes Pod Scheduler mặc định tự điều phối các tác vụ LLM đa node trực tiếp. Luôn đóng gói distributed runtime vào các hàng đợi tích hợp topology-aware để tránh tình trạng deadlock (khi Node-A lấy 4 GPU và Node-B lấy 4 GPU nhưng không thể thiết lập liên kết NVLink băng thông cao).
2. Khaai Báo Manifest KServe & RayServe Chuẩn Enterprise
Dưới đây là file manifest Kubernetes tích hợp KServe với cấu hình RayCluster custom, chạy Llama-3-70B trên 8x GPU H100 với Tensor Parallelism = 8.
apiVersion: serving.kserve.io/v1beta1
kind: InferenceService
metadata:
name: llama-3-70b-instruct
namespace: llm-serving
annotations:
serving.kserve.io/enable-prometheus-scraping: 'true'
autoscaling.kserve.io/target: '10'
autoscaling.kserve.io/metric: 'concurrency'
autoscaling.kserve.io/scale-to-zero-pod-deletion-cost: '100'
spec:
predictor:
minReplicas: 1
maxReplicas: 4
model:
modelFormat:
name: vllm
runtime: kserve-ray-runtime
storageUri: 's3://enterprise-model-registry/llama-3-70b-instruct/'
resources:
limits:
cpu: '32'
memory: 128Gi
nvidia.com/gpu: '8'
requests:
cpu: '16'
memory: 64Gi
nvidia.com/gpu: '8'
args:
- '--model=/mnt/models'
- '--tensor-parallel-size=8'
- '--pipeline-parallel-size=1'
- '--max-model-len=8192'
- '--gpu-memory-utilization=0.92'
- '--enable-chunked-prefill'
- '--trust-remote-code'
---
apiVersion: ray.io/v1
kind: RayService
metadata:
name: ray-vllm-llama-70b
namespace: llm-serving
spec:
serviceUnhealthyThreshold: 300
rayClusterConfig:
rayVersion: '2.35.0'
headGroupSpec:
rayStartParams:
dashboard-host: '0.0.0.0'
num-gpus: '0'
template:
spec:
containers:
- name: ray-head
image: rayproject/ray:2.35.0-py310
resources:
limits:
cpu: '4'
memory: 16Gi
requests:
cpu: '2'
memory: 8Gi
workerGroupSpecs:
- groupName: gpu-group
replicas: 1
minReplicas: 1
maxReplicas: 4
rayStartParams:
block: 'true'
template:
metadata:
labels:
karpenter.sh/capacity-type: spot-fallback-on-demand
node.kubernetes.io/instance-type: g6e.12xlarge
spec:
containers:
- name: ray-worker
image: vllm/vllm-openai:v0.6.0
resources:
limits:
nvidia.com/gpu: '4'
memory: 192Gi
cpu: '48'
requests:
nvidia.com/gpu: '4'
memory: 160Gi
cpu: '32'
securityContext:
capabilities:
add: ['SYS_PTRACE']3. Gom Cụm Dynamic GPU Bin-Packing Với Kueue & Karpenter
Nếu không có dynamic bin-packing, các node GPU sẽ bị phân mảnh bộ nhớ—ví dụ, ba node 8-GPU mỗi node trống 2 GPU, nhưng request mới yêu cầu 4 GPU trên cùng một NVLink domain. Sự kết hợp giữa hàng đợi Kueue và Karpenter NodePools đảm bảo gom cụm tối ưu và tự động thu hồi các GPU node bị nhàn rỗi.
Cấu Hình Karpenter NodePool Cho Tối Ưu Mật Độ GPU
apiVersion: karpenter.sh/v1beta1
kind: NodePool
metadata:
name: gpu-llm-binpack
spec:
template:
spec:
requirements:
- key: kubernetes.io/arch
operator: In
values: ["amd64"]
- key: karpenter.k8s.aws/instance-gpu-manufacturer
operator: In
values: ["nvidia"]
- key: karpenter.k8s.aws/instance-gpu-count
operator: In
values: ["4", "8"]
- key: karpenter.sh/capacity-type
operator: In
values: ["on-demand"]
nodeClassRef:
apiVersion: karpenter.k8s.aws/v1beta1
kind: EC2NodeClass
name: gpu-node-class
disruption:
consolidationPolicy: WhenEmpty
consolidateAfter: 2m
expireAfter: 720h
---
apiVersion: karpenter.k8s.aws/v1beta1
kind: EC2NodeClass
metadata:
name: gpu-node-class
spec:
amiFamily: AL2
blockDeviceMappings:
- deviceName: /dev/xvda
ebs:
volumeSize: 500Gi
volumeType: gp3
iops: 10000
throughput: 1000
userData: |
#!/bin/bash
/usr/bin/nvidia-smi -pm 1
/usr/bin/nvidia-smi --auto-boost-default=0
/usr/bin/nvidia-smi -ac 5001,15904. Chiến Lược Hàng Đợi Ưu Tiên Với Kueue ClusterQueue
Kueue ngăn ngừa tình trạng pod GPU bị kẹt ở trạng thái Pending bằng cách giữ lại các Ray workload cho đến khi toàn bộ các GPU worker có thể được lập lịch đồng thời trong cùng nhóm topology.
apiVersion: kueue.x-k8s.io/v1beta1
kind: ClusterQueue
metadata:
name: llm-priority-queue
spec:
namespaceSelector: {}
queueingStrategy: StrictFIFO
cohort: gpu-reasoning
resourceGroups:
- coveredResources: ["nvidia.com/gpu"]
flavors:
- name: h100-sxm5
resources:
- name: "nvidia.com/gpu"
nominalQuota: 32
- name: a100-pcie
resources:
- name: "nvidia.com/gpu"
nominalQuota: 64
---
apiVersion: kueue.x-k8s.io/v1beta1
kind: LocalQueue
metadata:
name: llm-queue
namespace: llm-serving
spec:
clusterQueue: llm-priority-queue5. Tối Ưu vLLM Engine & Continuous Batching
Để đạt thông lượng GPU cao nhất dưới tải concurrent lớn, cấu hình engine vLLM cần được tinh chỉnh đồng bộ với thông số container Kubernetes:
--gpu-memory-utilization 0.92: Dành 92% VRAM GPU riêng cho trọng số mô hình và KV Cache (PagedAttention), giữ lại 8% cho overhead PyTorch context.--enable-chunked-prefill: Chia nhỏ giai đoạn prefill của prompt dài, giúp tránh hiện tượng tăng đột biến TTFT (Time To First Token) cho các luồng generation đến đồng thời.--max-num-batched-tokens: Được tính toán động dựa trên context length (ví dụ 32768) nhằm triệt tiêu hoàn toàn lỗi CUDA Out-Of-Memory.
Bảng So Sánh Hiệu Năng Engine
| Kiến Trúc Engine | Mô Hình | Phần Cứng GPU | TP Size | Thông Lượng (tok/s) | P99 TTFT (ms) | Hiệu Suất VRAM |
|---|---|---|---|---|---|---|
| Naive PyTorch + FastApi | Llama-3-70B | 8x A100-80GB PCIe | 8 | 142 | 1850 | 48% |
| Ray + vLLM (PagedAttn) | Llama-3-70B | 8x A100-80GB PCIe | 8 | 980 | 320 | 91% |
| KServe + Ray + vLLM | Llama-3-70B | 8x H100-80GB SXM5 | 8 | 2840 | 85 | 95% |
6. Các Lệnh CLI Kiểm Tra Và Giám Sát Production
Kiểm tra trạng thái Ray Actor và topology liên kết NVLink trên cụm Kubernetes:
# Kiểm tra topology thực tế của Ray Cluster
kubectl exec -it -n llm-serving deployment/ray-vllm-llama-70b-head -- ray status
# Xác minh tốc độ giao tiếp NVLink giữa các Ray Worker
kubectl exec -it -n llm-serving deployment/ray-vllm-llama-70b-worker -- nvidia-smi topo -m
# Kiểm tra trạng thái Autoscaling của KServe InferenceService
kubectl get inferenceservice llama-3-70b-instruct -n llm-serving -o jsonpath='{.status.conditions[*]}'
# Truy vấn metric Continuous Batching và KV Cache usage của vLLM từ Prometheus
curl -s http://llama-3-70b-instruct.llm-serving.svc.cluster.local:8080/metrics | grep -E "(vllm:num_requests_waiting|vllm:gpu_cache_usage_perc)"7. Khuyến Nghị Cho Môi Trường Production
- Chia Sẻ Bộ Nhớ Shared Memory Host IPC: Luôn mount
/dev/shmdưới dạngemptyDirvớimedium: Memorytrong spec của Ray container để tránh lỗi timeout giao tiếp NCCL giữa các tiến trình. - Ghim Topology GPU: Sử dụng label của
Karpenterđể đảm bảo Ray Worker được đẩy vào các instance mà GPU kết nối trực tiếp qua NVLink thay vì đi qua các switch PCIe. - Cơ Chế Warm KV Caching: Pre-warm các Ray worker node bằng các System Prompt phổ biến thông qua KServe Startup Probe nhằm loại bỏ hiện tượng latency spike do cold-start.
