Hướng dẫn triển khai NVIDIA Triton Inference Server trên Linux: Phục vụ đa mô hình AI hiệu năng cao

Artificial Intelligence tutorial - IT technology blog
Artificial Intelligence tutorial - IT technology blog

1. Quick Start: Chạy Triton Server và Test Model trong 5 phút

Nếu bạn cần dựng nhanh một instance Triton Inference Server trên máy Linux có GPU để test, 3 bước gọn nhẹ dưới đây sẽ giúp hệ thống nhận request được ngay.

Bước 1.1: Chuẩn bị thư mục Model Repository

Triton quản lý mô hình theo quy tắc thư mục rất chặt chẽ. Ta tạo nhanh khung thư mục cho một mô hình ONNX phân loại văn bản:

# Tạo thư mục cho model repository
mkdir -p ~/triton_models/sample_model/1
cd ~/triton_models/sample_model

# Tạo file config.pbtxt cơ bản
cat << 'EOF' > config.pbtxt
name: "sample_model"
platform: "onnxruntime_onnx"
max_batch_size: 8
input [
  {
    name: "input_ids"
    data_type: TYPE_INT64
    dims: [ 128 ]
  }
]
output [
  {
    name: "output_logits"
    data_type: TYPE_FP32
    dims: [ 2 ]
  }
]
EOF

Giờ bạn copy file ONNX thật vào đúng đường dẫn: ~/triton_models/sample_model/1/model.onnx. Số 1 chính là version của mô hình.

Bước 1.2: Khởi chạy Triton Server container

Máy chủ cần cài sẵn NVIDIA Container Toolkit. Ta kéo và chạy image chính thức từ NVIDIA NGC:

docker run --gpus all --rm -d \
  -p 8000:8000 -p 8001:8001 -p 8002:8002 \
  -v ~/triton_models:/models \
  --name triton-server \
  nvcr.io/nvidia/tritonserver:24.08-py3 \
  tritonserver --model-repository=/models

Ba cổng dịch vụ chính gồm:

  • 8000: Cổng HTTP REST API thông dụng.
  • 8001: Cổng gRPC API nhị phân, tối ưu cho production nhờ độ trễ cực thấp.
  • 8002: Cổng Prometheus Metrics để giám sát tài nguyên và hàng đợi.

Bước 1.3: Kiểm tra trạng thái sẵn sàng

Gửi 2 lệnh curl để xác nhận server và model đã sẵn sàng nhận tải:

# Kiểm tra server liveness
curl -s -o /dev/null -w "%{http_code}" http://localhost:8000/v2/health/live

# Kiểm tra model readiness
curl -s -o /dev/null -w "%{http_code}" http://localhost:8000/v2/models/sample_model/ready

Cả hai trả về 200 nghĩa là model đã nằm gọn trong VRAM. Server sẵn sàng phục vụ inference.

2. Kiến trúc và cơ chế cốt lõi của Triton

Nhiều team khi mới đưa AI lên production thường bọc từng model vào một web service FastAPI hoặc Flask riêng. Vừa có Whisper nhận diện giọng nói, YOLO phát hiện vật thể, lại thêm BERT phân loại text.

Kiến trúc này lộ điểm yếu rất nhanh. Mỗi container ôm cố định 2-4 GB VRAM dù không có tải. Python GIL kìm hãm throughput nặng nề. Hơn nữa, việc gộp batch giữa các request gửi đến lệch pha nhau gần như bất khả thi.

Triton giải quyết triệt để vấn đề này nhờ core C++ hiệu năng cao. Nó quản lý bộ nhớ tập trung, gom batch tự động và điều phối tài nguyên GPU chuẩn xác.

Cấu trúc Model Repository tiêu chuẩn

Triton dựa vào tên folder để nạp đúng runtime và phiên bản:

model_repository/
├── yolo_detector/
│   ├── config.pbtxt
│   ├── 1/
│   │   └── model.onnx
│   └── 2/
│       └── model.onnx
└── text_classifier/
    ├── config.pbtxt
    └── 1/
        └── model.savedmodel/ (TensorFlow)

Giải mã file cấu hình config.pbtxt

Tệp config.pbtxt quyết định toàn bộ hành vi của model: từ kiểu dữ liệu, tensor shape cho đến thuật toán lập lịch suy luận.

Dynamic Batching: Xương sống tăng Throughput

Thay vì xử lý lẻ tẻ từng request đơn (batch = 1), scheduler của Triton chủ động gom các request đến gần nhau thành batch lớn hơn trước khi nạp vào GPU compute core:

dynamic_batching {
  max_queue_delay_microseconds: 5000
  preferred_batch_size: [ 4, 8, 16 ]
}
max_batch_size: 16

Cấu hình này bảo Triton chờ tối đa 5ms. Nếu gom đủ 4, 8 hoặc 16 request, nó đẩy vào GPU chạy ngay. Nếu hết 5ms mà chỉ có 3 request, server vẫn thực thi để giữ latency ổn định. Trên thực tế với model ResNet50 hoặc BERT-base, cơ chế này giúp throughput tăng từ 3 đến 5 lần so với batching đơn lẻ thông thường.

3. Nâng cao: Đa mô hình, Multi-Instance và Model Pipeline (Ensemble)

Chạy nhiều model instances song song trên cùng một GPU

Mặc định Triton chỉ gán 1 compute instance cho mỗi model. Nếu bạn dùng GPU dung lượng lớn như A10G 24GB hay A100 80GB, VRAM còn thừa nhiều nhưng GPU compute core lại rảnh rỗi giữa các batch. Hãy nhân bản worker ngay trong config:

instance_group [
  {
    count: 2
    kind: KIND_GPU
    gpus: [ 0 ]
  }
]

Triton sẽ khởi tạo 2 bản sao độc lập của model trên GPU 0. Chúng xử lý đồng thời 2 batch từ hàng đợi, loại bỏ tình trạng request sau phải đứng chờ request trước kết thúc.

Model Ensemble: Ghép chuỗi Preprocessing và Inference

Dữ liệu thực tế hiếm khi chui thẳng vào model core. Một pipeline chuẩn thường gồm: tiền xử lý ảnh hoặc tokenize text, đưa qua deep learning model, rồi parse kết quả sang format nghiệp vụ. Triton Ensemble gom toàn bộ các bước này thành một pipeline duy nhất:

name: "pipeline_nlp"
platform: "ensemble"
max_batch_size: 8
input [
  {
    name: "RAW_TEXT"
    data_type: TYPE_STRING
    dims: [ 1 ]
  }
]
output [
  {
    name: "LABEL_SCORES"
    data_type: TYPE_FP32
    dims: [ 5 ]
  }
]
ensemble_scheduling {
  step [
    {
      model_name: "tokenizer_python_backend"
      model_version: 1
      input_map {
        key: "TEXT"
        value: "RAW_TEXT"
      }
      output_map {
        key: "TOKEN_IDS"
        value: "INTERMEDIATE_TOKENS"
      }
    },
    {
      model_name: "transformer_onnx"
      model_version: 1
      input_map {
        key: "input_ids"
        value: "INTERMEDIATE_TOKENS"
      }
      output_map {
        key: "output_logits"
        value: "LABEL_SCORES"
      }
    }
  ]
}

Client chỉ cần gọi duy nhất endpoint pipeline_nlp. Dữ liệu trung gian giữa tokenizer và model ONNX nằm trọn vẹn trong RAM hoặc shared memory của máy chủ. Bạn không còn tốn hàng chục mili-giây cho việc serialize JSON hay roundtrip qua network giữa các microservice.

Gọi Triton từ Python Client qua gRPC

Dùng thư viện tritonclient qua gRPC để đẩy dữ liệu binary siêu tốc, tránh triệt để overhead encode base64 hay parse JSON:

import numpy as np
import tritonclient.grpc as grpcclient

# Khởi tạo client gRPC tới Triton
client = grpcclient.InferenceServerClient(url="localhost:8001")

# Chuẩn bị dummy input_ids: batch_size=1, sequence_length=128
input_data = np.ones((1, 128), dtype=np.int64)

# Đóng gói tensor input
inputs = [grpcclient.InferInput("input_ids", input_data.shape, "TYPE_INT64")]
inputs[0].set_data_from_numpy(input_data)

# Khai báo output cần nhận
outputs = [grpcclient.InferRequestedOutput("output_logits")]

# Gửi request suy luận
response = client.infer(model_name="sample_model", inputs=inputs, outputs=outputs)

# Lấy kết quả dưới dạng NumPy array
result = response.as_numpy("output_logits")
print("Kích thước output:", result.shape)
print("Giá trị logits:", result)

4. Kinh nghiệm thực chiến khi vận hành Triton trên Production

Chạy thử model trên notebook rất khác với việc chịu tải hàng nghìn RPS lúc cao điểm. Dưới đây là những tinh chỉnh quan trọng rút ra từ môi trường thực tế:

  • Đo đạc chính xác bằng Perf Analyzer: Đừng đoán mò thông số max_queue_delay_microseconds hay preferred_batch_size. Hãy dùng công cụ chính hãng perf_analyzer để quét tải thực tế:
perf_analyzer -m sample_model -u localhost:8001 -i grpc --concurrency-range 1:16

Lệnh này giả lập từ 1 đến 16 client đồng thời. Kết quả sẽ chỉ rõ sweet spot: điểm mà throughput đạt đỉnh và p99 latency vẫn nằm dưới ngưỡng SLA cho phép (ví dụ dưới 30ms).

  • Kiểm soát VRAM bằng Dynamic Model Control: Khi hệ thống có hàng chục model nhưng GPU chỉ có 16GB VRAM, nạp hết lúc khởi động sẽ gây tràn bộ nhớ (CUDA OOM). Khởi chạy Triton với cờ --model-control-mode=explicit. Server chỉ load model vào VRAM khi nhận lệnh qua API và giải phóng khi hết nhu cầu.
  • Chuyển đổi sang TensorRT: Với GPU NVIDIA đời Turing/Ampere/Ada (như T4, A10, L4), hãy compile model ONNX sang engine TensorRT (.plan) thông qua trtexec. Bạn thường sẽ giảm được 40-60% độ trễ suy luận và cắt giảm đáng kể mức chiếm dụng VRAM so với ONNX Runtime.
  • Thiết lập cảnh báo Prometheus: Cổng 8002 trả metrics chuẩn Prometheus tại /metrics. Hãy theo dõi sát 3 thông số vàng: nv_inference_request_duration_us (tổng thời gian xử lý), nv_inference_queue_duration_us (thời gian request nghẽn trong hàng đợi) và nv_gpu_memory_used_bytes để tự động kích hoạt scale-out trước khi server quá tải.
Share: