Phân tích và xử lý lỗi OOM Killer trên GPU hạn chế
Khi chạy các model lớn như Llama-3-70B trên GPU có VRAM thấp (ví dụ: A100 40GB), lỗi Out Of Memory (OOM) xảy ra khi tổng bộ nhớ cần cho weights, KV cache và activation vượt quá giới hạn vật lý.
Tác động trực tiếp là tiến trình bị hệ điều hành giết chết (SIGKILL), gây downtime dịch vụ. Nguyên nhân thường là do cấu hình max_num_batched_tokens quá lớn hoặc gpu_memory_utilization được đặt cao hơn mức an toàn.
Điều chỉnh tham số GPU Memory và Quantization
Bước đầu tiên là giảm mức sử dụng GPU memory và áp dụng quantization (nén model) để giảm footprint của weights mà vẫn giữ độ chính xác chấp nhận được.
Sửa file values.yaml của Helm chart vLLM hoặc chỉnh trực tiếp trong Deployment YAML. Đặt gpu_memory_utilization xuống 0.90 để dành 10% memory cho hệ thống và buffer, đồng thời bật quantization (ví dụ: AWQ hoặc GPTQ).
Đường dẫn file cấu hình: /opt/k8s/manifests/vllm-deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: vllm-llama3-70b-optimized
spec:
replicas: 1
template:
spec:
containers:
- name: vllm
image: vllm/vllm:latest
command:
- python3
- -u
- /usr/local/bin/vllm-entrypoint.py
args:
- --model
- /data/models/Llama-3-70B-AWQ
- --gpu-memory-utilization
- "0.90"
- --max-num-batched-tokens
- "4096"
- --max-model-len
- "8192"
- --quantization
- "awq"
- --tensor-parallel-size
- "4"
- --enable-chunked-prefill
- --enforce-eager
resources:
limits:
nvidia.com/gpu: "1"
requests:
nvidia.com/gpu: "1"
volumeMounts:
- name: model-storage
mountPath: /data/models
- name: dshm
mountPath: /dev/shm
volumes:
- name: model-storage
persistentVolumeClaim:
claimName: ai-model-pvc
- name: dshm
emptyDir:
medium: Memory
Kết quả mong đợi: Pod khởi động thành công mà không bị OOM Killer giết chết ngay lập tức. Khi gửi request, model vẫn trả về kết quả nhưng tốc độ có thể chậm hơn một chút do quantization và giới hạn batch size.
Verify: Kiểm tra trạng thái OOM trong Kubernetes
Sử dụng lệnh sau để kiểm tra lịch sử sự kiện của Pod, tìm kiếm nguyên nhân OOMKilled để xác nhận lỗi đã được khắc phục.
kubectl describe pod vllm-llama3-70b-optimized -n ai-inference | grep -A 5 "Last State"
Kết quả mong đợi: Trạng thái Last State hiển thị Running hoặc Terminated với lý do Exit Code 0, không còn xuất hiện Reason: OOMKilled.
Giải quyết Deadlock và Race Condition trong Concurrent Inference
Trong môi trường concurrent (nhiều request cùng lúc), deadlock xảy ra khi các thread chờ nhau vô tận để lấy tài nguyên (GPU context, CPU lock). Race condition xảy ra khi nhiều tiến trình truy cập cùng một vùng nhớ hoặc file log không được đồng bộ hóa.
Triệu chứng: API Gateway trả về lỗi 504 Gateway Timeout hoặc request bị treo (hang) không bao giờ trả về kết quả, trong khi GPU vẫn hoạt động bình thường.
Bật Chunked Prefill và Enforce Eager Mode
Để tránh deadlock do việc phân bổ bộ nhớ KV cache quá lớn cho một request duy nhất, hãy bật --enable-chunked-prefill. Chế độ này chia nhỏ quá trình prefill (xử lý prompt đầu vào) thành các chunk nhỏ, giúp giải phóng bộ nhớ từng phần và cho phép các request khác chạy song song.
Đồng thời, sử dụng --enforce-eager để tắt Graph Mode (CUDA Graph) trong các trường hợp model architecture phức tạp hoặc input length thay đổi liên tục, vì Graph Mode đôi khi gây race condition khi thu thập statistics.
kubectl set env deployment/vllm-llama3-70b-optimized VLLM_ENABLE_CHUNKED_PREFILL=true VLLM_ENFORCE_EAGER=true -n ai-inference
Kết quả mong đợi: Khi gửi hàng loạt request dài cùng lúc, không còn hiện tượng request bị treo. Thời gian phản hồi (latency) có thể tăng nhẹ ở request đầu tiên nhưng tổng throughput (request/giây) ổn định hơn.
Cấu hình Timeout và Retry Policy cho Ingress
Cấu hình Ingress Gateway (Nginx/Traefik) để ngắt kết nối sau một khoảng thời gian an toàn và áp dụng retry logic cho client, tránh để server bị quá tải do giữ quá nhiều connection hang.
Đường dẫn file cấu hình Ingress: /opt/k8s/manifests/ai-gateway-ingress.yaml
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: vllm-ingress
annotations:
nginx.org/client-max-body-size: "100m"
nginx.org/proxy-read-timeout: "300"
nginx.org/proxy-send-timeout: "300"
nginx.org/upstream-fail-timeout: "30"
nginx.org/upstream-max-fails: "3"
spec:
rules:
- host: ai.inference.local
http:
paths:
- path: /v1/chat/completions
pathType: Prefix
backend:
service:
name: vllm-service
port:
number: 8000
Kết quả mong đợi: Client nhận được lỗi 408 Request Timeout hoặc 504 sau 300 giây thay vì treo mãi. Server tự động đóng connection để phục hồi tài nguyên.
Verify: Kiểm tra Race Condition bằng Stress Test
Dùng công cụ ab hoặc wrk để tấn công song song với số lượng lớn connection, quan sát log của vLLM xem có lỗi AssertionError hay Deadlock không.
wrk -t12 -c24 -d30s -s concurrent.lua http://ai.inference.local/v1/chat/completions
Kết quả mong đợi: Không xuất hiện lỗi panic hoặc segfault trong log vLLM. Số lượng request thành công (200 OK) đạt tỷ lệ cao (>95%) trong suốt quá trình test.
Tối ưu chi phí với Spot Instances và Node Autoscaler
Chi phí vận hành GPU là yếu tố lớn nhất. Sử dụng Spot Instances (thừa từ Cloud Provider hoặc GPU node rảnh) có thể giảm chi phí 60-90% so với On-Demand. Tuy nhiên, Spot Instances có thể bị reclaim (thu hồi) bất cứ lúc nào.
Giải pháp là kết hợp Spot Instances cho workload không quan trọng (training, batch inference) và On-Demand cho workload time-critical, đồng thời dùng Cluster Autoscaler để tự động thêm/bớt node dựa trên pending pod.
Cấu hình Node Autoscaler cho Kubernetes
Triển khai cluster-autoscaler để tự động scale node pool. Cấu hình --scale-down-utilization-threshold để xóa node khi CPU/GPU sử dụng dưới 50% trong 10 phút.
Đường dẫn file cấu hình: /opt/k8s/manifests/cluster-autoscaler-config.yaml
apiVersion: v1
kind: ConfigMap
metadata:
name: cluster-autoscaler
namespace: kube-system
data:
cluster-autoscaler.yaml: |
global:
scale-down:
delay-after-add: 10m
enabled: true
utilization-threshold: 0.5
unneeded-time: 10m
scan-interval: 10s
skip-nodes-with-system-pods: false
nodeGroups:
- name: gpu-spot-pool
scaleFrom: 0
scaleTo: 10
maxEmptyBulkDelete: 3
maxTotalUnneededPercentage: 10
template:
labels:
node.kubernetes.io/instance-type: nvidia-a100-40gb
spot: "true"
taints:
- key: "nvidia.com/gpu"
effect: "NoSchedule"
Kết quả mong đợi: Khi có pending pod yêu cầu GPU, Autoscaler tự động tạo thêm node. Khi traffic giảm, node trống sẽ bị xóa sau 10 phút, giúp tiết kiệm chi phí khi không có request.
Cấu hình Tolerations và Node Affinity cho Spot
Để đảm bảo các Pod AI inference chỉ chạy trên Spot Instances (để tiết kiệm) hoặc ưu tiên Spot nhưng fallback về On-Demand, cần cấu hình tolerations và nodeAffinity trong Deployment.
Thêm toleration cho taint spot=true vào Deployment vLLM.
spec:
template:
spec:
affinity:
nodeAffinity:
preferredDuringSchedulingIgnoredDuringExecution:
- weight: 100
preference:
matchExpressions:
- key: spot
operator: In
values:
- "true"
tolerations:
- key: "spot"
operator: "Equal"
value: "true"
effect: "NoSchedule"
Kết quả mong đợi: Kubernetes ưu tiên schedule Pod lên các node Spot. Nếu không có node Spot, Pod sẽ pending cho đến khi Autoscaler tạo thêm node mới, hoặc nếu cấu hình preferred thì sẽ fallback sang node On-Demand.
Verify: Kiểm tra hoạt động của Autoscaler
Quan sát số lượng node và trạng thái Pod khi tăng/giảm tải.
kubectl get nodes -l spot=true && kubectl get events -n ai-inference --field-selector reason=Scheduled,reason=FailedScheduling
Kết quả mong đợi: Khi scale up, thấy node mới xuất hiện trong danh sách. Khi scale down, thấy node bị xóa và Pod được di chuyển hoặc terminate an toàn.
Debug hiệu năng thấp do PCIe Bottleneck và Network Latency
Trong kiến trúc multi-node (Tensor Parallel), hiệu năng bị giới hạn bởi tốc độ truyền dữ liệu giữa các GPU. Nếu PCIe bandwidth thấp hoặc Network (InfiniBand/RoCE) latency cao, thời gian truyền tensor sẽ lớn hơn thời gian tính toán, gây nghẽn cổ chai.
Triệu chứng: Throughput giảm mạnh khi tăng tensor-parallel-size, hoặc latency tăng đột biến khi request lớn.
Kiểm tra Bandwidth PCIe và NVLink
Sử dụng công cụ nvidia-smi để kiểm tra tốc độ truyền dữ liệu giữa các GPU trong cùng một node. Nếu dùng NVLink, tốc độ nên đạt 600GB/s+. Nếu chỉ dùng PCIe Gen3, tốc độ chỉ khoảng 10-15GB/s.
nvidia-smi topo -m
Kết quả mong đợi: Xem bảng kết nối. Nếu thấy PXI (PCIe) thay vì NV (NVLink) giữa các GPU cần chạy TP, đây là nguyên nhân gây bottleneck. Cần cân nhắc giảm tensor-parallel-size xuống để mỗi GPU chứa nhiều layer hơn, giảm tần suất giao tiếp.
Đo lường Network Latency với NCCL
Sử dụng nccl-tests để benchmark network throughput giữa các node. Đây là chuẩn để debug vấn đề giao tiếp trong Distributed Training/Inference.
Triển khai một Job đơn giản để chạy test.
apiVersion: batch/v1
kind: Job
metadata:
name: nccl-benchmark
spec:
template:
spec:
containers:
- name: nccl-test
image: nvcr.io/nvidia/k8s-samples/nccl-tests:latest
command:
- /bin/bash
- -c
- "nccl-tests/nccl_bench -n 4 -b 8 -e 20 -f 1 -g 1 -z 0"
resources:
limits:
nvidia.com/gpu: "1"
restartPolicy: OnFailure
Kết quả mong đợi: Xem log của Job. Nếu throughput thấp hơn 80% so với lý thuyết của card mạng (ví dụ 100Gbps), kiểm tra lại cấu hình net.ipv4.tcp_congestion_control hoặc driver RDMA trên host Proxmox.
Tối ưu Network Stack trên Proxmox Host
Trên host Proxmox, cần đảm bảo hugepages được bật và net.core.rmem_max được tăng để giảm overhead của kernel khi xử lý gói tin lớn.
Chỉnh sửa file /etc/sysctl.conf trên node Proxmox.
net.core.rmem_max = 134217728
net.core.wmem_max = 134217728
net.ipv4.tcp_congestion_control = bbr
vm.nr_hugepages = 4096
Áp dụng thay đổi:
sysctl -p
Kết quả mong đợi: Giảm latency mạng và tăng throughput khi truyền dữ liệu lớn giữa các node Kubernetes.
Verify: So sánh Throughput trước và sau
Chạy lại benchmark inference với cùng một model và prompt size, so sánh số tokens/giây.
curl -X POST http://ai.inference.local/v1/chat/completions -d '{"model": "llama-3", "prompt": "Explain quantum physics in detail", "max_tokens": 2000}' -s | jq '.usage.total_tokens' --arg start $(date +%s) --arg end $(date +%s) --arg diff $((end - start)) --arg tokens $result --arg tps $((tokens / diff))
Kết quả mong đợi: Tốc độ (tokens/giây) tăng lên đáng kể sau khi tối ưu PCIe/Network.
Best Practices vận hành hệ thống AI ổn định 24/7
Để duy trì hệ thống hoạt động liên tục, cần áp dụng các quy tắc về cấu hình, giám sát và bảo trì phòng ngừa. Không chỉ sửa lỗi khi nó xảy ra, mà phải ngăn chặn từ gốc.
1. Thiết lập Circuit Breaker và Rate Limiting
Đừng để hệ thống bị quá tải. Sử dụng Kubernetes Service hoặc Envoy Proxy để giới hạn số lượng request mỗi giây (RPS) và ngắt kết nối khi server bị lỗi liên tục (circuit breaker).
Cấu hình trong RateLimit policy (nếu dùng Envoy/Istio) hoặc LimitRange trong K8s.
apiVersion: networking.istio.io/v1beta1
kind: VirtualService
metadata:
name: ai-gateway
spec:
hosts:
- ai.inference.local
http:
- route:
- destination:
host: vllm-service
weight: 100
fault:
abort:
percentage: 0
delay:
percentage: 0
- match:
- headers:
x-api-key:
exact: "blocked"
route:
- destination:
host: vllm-service
fault:
abort:
percentage: 100
httpStatus: 429
Kết quả mong đợi: Hệ thống từ chối request khi quá tải hoặc khi phát hiện lỗi, bảo vệ GPU khỏi bị crash hoàn toàn.
2. Cấu hình Health Check chính xác (Liveness & Readiness)
Sai lầm phổ biến là dùng health check HTTP đơn giản trên port 8000. Với AI model, cần kiểm tra xem GPU có còn hoạt động và model đã load xong chưa.
Sử dụng endpoint /health của vLLM (nếu có) hoặc script custom kiểm tra nvidia-smi.
livenessProbe:
httpGet:
path: /health
port: 8000
initialDelaySeconds: 60
periodSeconds: 10
timeoutSeconds: 5
failureThreshold: 3
readinessProbe:
httpGet:
path: /health
port: 8000
initialDelaySeconds: 30
periodSeconds: 5
timeoutSeconds: 2
failureThreshold: 3
Kết quả mong đợi: Pod bị restart tự động nếu vLLM treo (deadlock) hoặc GPU bị hang, đảm bảo dịch vụ luôn sẵn sàng.
3. Backup và Rollback tự động
Sử dụng ArgoCD hoặc Flux để quản lý GitOps. Mọi thay đổi cấu hình phải qua commit code. Nếu có lỗi, rollback về version trước đó chỉ với 1 lệnh kubectl rollout undo.
kubectl rollout undo deployment/vllm-llama3-70b-optimized -n ai-inference
Kết quả mong đợi: Hệ thống quay về trạng thái ổn định ngay lập tức khi deploy mới gây lỗi.
4. Log Rotation và Disk Cleanup
Log inference có thể rất lớn. Cấu hình logrotate trên container hoặc sử dụng Filebeat để gửi log lên Elasticsearch/S3 ngay lập tức, tránh đầy disk trên node.
Đảm bảo PVC có storageClass với reclaimPolicy: Delete hoặc Retain tùy chiến lược, và đặt giới hạn max-log-size trong vLLM.
args:
- --log-level
- "INFO"
- --log-verbosity
- "0"
Kết quả mong đợi: Disk usage trên node không vượt quá 80%, tránh tình trạng node bị freeze do full disk.
Điều hướng series:
Mục lục: Series: Series: Xây dựng nền tảng AI inference hiệu năng cao với vLLM, TensorRT-LLM và Kubernetes trên Proxmox
« Phần 9: Bảo mật: TLS, Authentication và Network Policies cho AI Gateway