이 글에서 다루는 것
CPU-only 환경에서 Triton의 dynamic_batching과 instance_group 설정으로 처리량을 높이고 latency를 안정화하는 성능 최적화 과정
선수지식
이 단계에서 해결하려는 문제
Triton을 올리고 모델이 READY 상태가 되면 끝일까? 기본 설정만 사용하면 요청이 하나씩 순서대로 처리됩니다. 동시 요청이 몰리면 큐가 쌓이고, latency가 급격히 올라갑니다.
이 글은 dynamic_batching과 instance_group 설정으로
CPU 환경에서 처리량을 높이고 latency를 안정화한 과정을 설명합니다.
🎯 핵심 요약
- 기본 설정의 한계: single instance + no batching -> 요청 직렬 처리
- instance_group: CPU 인스턴스 수 증가 -> 병렬 추론 처리
- dynamic_batching: 요청 자동 묶음 -> 배치 단위 추론으로 처리량 향상
- 적용 시점: explicit mode에서는 model load 시 config.pbtxt 반영
- 실측 결과: 136 RPS, p95 553ms, 에러율 0% (100 VU, CPU-only 3노드)
1️⃣ 기본 설정만으로는 무엇이 부족한가
Triton을 처음 실행하면 기본 동작은 다음과 같습니다.
요청 A → 추론 처리 → 응답
요청 B → 대기 → 추론 처리 → 응답
요청 C → 대기 → 대기 → 추론 처리 → 응답
즉 요청이 하나씩 직렬로 처리됩니다.
config.pbtxt에 아무 설정이 없으면 다음 상태입니다.
instance_group: 1개 (기본값)
batching: 없음 (기본값)
이 상태에서 동시 요청이 100개 들어오면 1개 처리 중, 99개 대기입니다.
결과: 처리량 낮음, latency 증가, 큐 대기 시간 급증.
이 문제를 해결하기 위해 두 가지 설정을 추가합니다.
instance_group: 병렬 처리 인스턴스 수 증가
dynamic_batching: 요청 자동 묶음 처리
2️⃣ instance_group 설정
instance_group은 Triton이 모델을 몇 개의 인스턴스로 동시에 실행할지를 정의합니다.
KIND_CPU vs KIND_GPU
| 설정 | 의미 |
|---|---|
KIND_CPU | CPU 기반 추론 인스턴스 |
KIND_GPU | GPU 기반 추론 인스턴스 (GPU ID 지정 가능) |
KIND_AUTO | 환경에 따라 자동 선택 |
CPU-only 환경에서는 KIND_CPU를 사용합니다.
instance_group [
{
kind: KIND_CPU
count: 2
}
]
count와 병렬 처리
count: 2는 모델 인스턴스 2개가 동시에 추론 가능하다는 의미입니다.
즉 동시 요청이 들어왔을 때:
요청 A → 인스턴스 1 처리 (병렬)
요청 B → 인스턴스 2 처리 (병렬)
요청 C → 대기
단일 인스턴스 대비 2배의 병렬 처리가 가능합니다.
count 설정 기준
CPU 코어 수와 메모리를 고려해서 설정합니다.
너무 높으면 메모리 부족과 스케줄링 경쟁이 발생하고, 너무 낮으면 병렬 처리 이점이 없습니다.
3노드 CPU-only 클러스터 기준으로 count: 2는 합리적인 시작값입니다.
3️⃣ dynamic_batching 설정
dynamic_batching은 Triton이 들어오는 요청을 자동으로 묶어서 배치 단위로 추론하는 기능입니다.
기본 동작 원리
요청 A 도착
요청 B 도착 (거의 동시)
요청 C 도착 (거의 동시)
↓
Triton이 A+B+C를 하나의 배치로 묶어서 추론
↓
배치 결과를 각 요청에 분리해서 응답
1건씩 추론 3회보다 3건 배치 추론 1회가 처리 오버헤드가 적어 처리량이 향상됩니다.
preferred_batch_size
dynamic_batching {
preferred_batch_size: [ 8, 16 ]
}
preferred_batch_size: [8, 16]의 의미: 8건이 모이면 우선 처리하고, 8건이 안 되면 최대 16건까지 기다렸다가 처리합니다.
이 설정은 처리량 향상과 latency 증가 사이의 균형점입니다.
max_queue_delay_microseconds
배치가 채워지지 않을 때 최대 대기 시간을 설정할 수 있습니다.
dynamic_batching {
preferred_batch_size: [ 8, 16 ]
max_queue_delay_microseconds: 5000 # 5ms
}
5000 microseconds = 5ms 안에 배치가 채워지지 않으면
기다리지 않고 현재 쌓인 요청만으로 추론합니다.
이 값을 높이면 처리량이 오르지만 latency도 올라갑니다.
4️⃣ latency vs throughput 트레이드오프
dynamic_batching은 처리량과 latency 사이의 트레이드오프가 존재합니다.
| 상황 | 권장 설정 |
|---|---|
| 실시간 응답 중요 (챗봇 등) | 작은 batch_size, 짧은 queue_delay |
| 처리량 중요 (배치 API 등) | 큰 batch_size, 긴 queue_delay |
| 균형 (ML serving 일반) | preferred_batch_size: [8, 16] |
이 프로젝트에서는 ML 서빙 일반 케이스로 [8, 16]을 선택했습니다.
5️⃣ explicit mode에서 배치 설정 적용 시점
이 프로젝트에서는 Triton을 explicit 모드로 실행합니다.
--model-control-mode=explicit
이 모드에서 모델은 자동으로 로드되지 않습니다.
DAG에서 명시적으로 load API를 호출해야 합니다.
config.pbtxt 반영 시점:
load API 호출
↓
Triton이 model repository에서 config.pbtxt 읽음
↓
dynamic_batching + instance_group 설정 적용
↓
READY 상태
즉 config.pbtxt를 수정한 뒤에는
반드시 unload -> load 순서로 재적용해야 합니다.
POST /v2/repository/models/best_model/unload
POST /v2/repository/models/best_model/load
6️⃣ 실제 config.pbtxt 코드
이 프로젝트의 Triton 모델 설정은 dags/mlops_lib/core/triton_config.py의 build_config_pbtxt() 함수가 생성합니다.
name: "best_model"
platform: "onnxruntime_onnx"
max_batch_size: 32
input [
{
name: "input"
data_type: TYPE_FP32
dims: [ -1, 4 ]
}
]
output [
{
name: "output_probability"
data_type: TYPE_FP32
dims: [ -1, 3 ]
},
# ... (output_label 생략)
]
dynamic_batching {
preferred_batch_size: [ 8, 16 ]
max_queue_delay_microseconds: 5000
}
instance_group [
{
kind: KIND_CPU
count: 2
}
]
주요 설계 포인트:
platform: onnxruntime_onnx– ONNX Runtime 기반 추론dims: [ -1, 4 ]– 배치 차원(-1) + feature 차원(4)max_batch_size: 32– dynamic_batching 활성화를 위해 반드시 0이 아닌 값 필요
dynamic_batching과 instance_group은 Airflow Variable로 런타임 제어가 가능합니다.
triton_dynamic_batching_enabled: true/false
triton_instance_group_enabled: true/false
Variable이 미설정이면 두 블록 모두 config.pbtxt에서 생략됩니다.
7️⃣ 부하 테스트 결과와 연결
이 설정을 적용한 후 k6 부하 테스트를 수행했습니다.
테스트 환경: 3노드 Kubernetes (CPU-only), FastAPI 2 replica, Triton 1 replica, 100 VU
결과:
처리량: 136 RPS
p50 latency: 126ms
p95 latency: 553ms
에러율: 0%
instance_group count: 2의 효과: 인스턴스 1개 예상 ~70 RPS에서 2개 실측 136 RPS로, 병렬 처리 효과가 처리량에 직접 반영되었습니다.
설계 판단 (Why This Way?)
preferred_batch_size [8, 16]으로 배치 오버헤드 감소와 대기 latency 증가 사이의 균형을 맞추고, instance_group count 2로 CPU 경합 없는 안정적 병렬 추론 시작값을 설정했습니다. Airflow Variable로 배치/인스턴스 설정을 런타임 제어하여 config.pbtxt 재생성 없이 A/B 성능 비교와 장애 대응 유연성을 확보했습니다.
다음에 읽을 글
→ Feature Store & Feast - Feature Store-lite — 경량 Feature Store 설계