요청 트레이싱
요청 트레이싱 (Request Tracing)
Triton은 개별 추론 요청에 대한 상세 트레이스를 생성하는 기능을 제공해요. 트레이싱은 tritonserver 실행파일을 실행할 때 명령줄 인자로 활성화합니다.
--trace-config 명령줄 옵션으로 전역·트레이스 모드별 설정을 지정할 수 있어요. 형식은 --trace-config <mode>,<setting>=<value>이고, <mode>는 triton 또는 opentelemetry 중 하나예요. 기본적으로 트레이스 모드는 triton으로 설정되고 서버는 Triton의 트레이스 API를 사용해요. opentelemetry 모드에서는 서버가 OpenTelemetry API를 사용해 개별 추론 요청의 트레이스를 생성·수집·내보냅니다.
전역 트레이스 설정(level, rate, count, mode)을 지정할 때는 --trace-config <setting>=<value> 형식을 씁니다.
Triton의 트레이스 API를 호출하는 예시는 다음과 같아요.
$ tritonserver \
--trace-config triton,file=/tmp/trace.json \
--trace-config triton,log-frequency=50 \
--trace-config rate=100 \
--trace-config level=TIMESTAMPS \
--trace-config count=100 ...
트레이스 설정
전역 설정
--trace-config에 넘길 수 있는 전역 트레이스 설정은 다음과 같습니다.
| 설정 | 기본값 | 설명 |
|---|---|---|
rate |
1000 | 샘플링 비율. 폐기된 --trace-rate와 동일. 예를 들어 1000이면 1000번째 추론 요청마다 트레이스. |
level |
OFF | 수집할 트레이스 상세 수준. 여러 번 지정해 여러 정보를 트레이스 가능. 폐기된 --trace-level과 동일. 선택지: TIMESTAMPS, TENSORS. 참고: opentelemetry 모드는 현재 TENSORS 수준을 지원하지 않음. |
count |
-1 | 수집할 남은 트레이스 수. 기본 -1은 트레이스를 멈추지 않는 뜻. 100이면 100개 트레이스 수집 후 Triton이 트레이싱을 중단. 폐기된 --trace-count와 동일. |
mode |
triton | 트레이스 수집에 사용할 트레이스 API. 선택지: triton, opentelemetry. |
Triton 트레이스 API 설정
--trace-config triton,<setting>=<value>에 넘길 수 있는 Triton 트레이스 API 설정은 다음과 같습니다.
| 설정 | 기본값 | 설명 |
|---|---|---|
file |
빈 문자열 | 트레이스 출력을 쓸 위치. 폐기된 --trace-file과 동일. |
log-frequency |
0 | 트레이스를 파일에 쓰는 빈도. 예를 들어 50이면 50개 트레이스를 수집할 때마다 파일에 기록. 폐기된 --trace-log-frequency와 동일. |
명령줄의 트레이스 설정 외에도 트레이스 프로토콜을 이용해 트레이스 설정을 수정할 수 있어요. 다만 트레이스 모드가 opentelemetry일 때는 이 옵션이 현재 지원되지 않습니다.
참고: 아래 플래그들은 폐기(deprecated) 됐어요. --trace-file은 트레이스 출력 위치, --trace-rate는 샘플링 비율(예: 매 100번째 요청마다 트레이스), --trace-level은 수집할 상세 수준(여러 번 지정 가능), --trace-log-frequency는 파일 기록 빈도(예: 50개마다 기록), --trace-count는 수집할 남은 트레이스 수(예: 100개 후 중단)입니다. 자세한 내용은 --help 옵션을 이용하세요.
지원되는 트레이스 수준 옵션
TIMESTAMPS: 각 요청의 실행 타임스탬프를 트레이스.TENSORS: 실행 중 입력·출력 텐서를 트레이스.
JSON 트레이스 출력
트레이스 출력은 다음 스키마를 따르는 JSON 파일입니다.
[
{
"model_name": "$string",
"model_version": "$number",
"id": "$number",
"request_id": "$string",
"parent_id": "$number"
},
{
"id": "$number",
"timestamps": [
{ "name" : "$string", "ns" : "$number" }
]
},
{
"id": "$number"
"activity": "$string",
"tensor":{
"name": "$string",
"data": "$string",
"shape": "$string",
"dtype": "$string"
}
},
...
]
각 트레이스에는 추론 요청의 모델 이름·버전을 나타내는 "id"가 할당돼요. 트레이스가 앙상블의 일부로 실행된 모델에서 온 것이라면 "parent_id"가 그 앙상블의 "id"를 가리킵니다. 예:
[
{
"id": 1,
"model_name": "simple",
"model_version": 1
},
...
]
각 TIMESTAMPS 트레이스는 하나 이상의 "timestamps"를 가지며, 각 타임스탬프는 이름과 나노초 단위("ns") 타임스탬프로 구성돼요. 예:
[
{"id": 1, "timestamps": [{ "name": "HTTP_RECV_START", "ns": 2356425054587444 }] },
{"id": 1, "timestamps": [{ "name": "HTTP_RECV_END", "ns": 2356425054632308 }] },
{"id": 1, "timestamps": [{ "name": "REQUEST_START", "ns": 2356425054785863 }] },
{"id": 1, "timestamps": [{ "name": "QUEUE_START", "ns": 2356425054791517 }] },
{"id": 1, "timestamps": [{ "name": "INFER_RESPONSE_COMPLETE", "ns": 2356425057587919 }] },
{"id": 1, "timestamps": [{ "name": "COMPUTE_START", "ns": 2356425054887198 }] },
{"id": 1, "timestamps": [{ "name": "COMPUTE_INPUT_END", "ns": 2356425057152908 }] },
{"id": 1, "timestamps": [{ "name": "COMPUTE_OUTPUT_START", "ns": 2356425057497763 }] },
{"id": 1, "timestamps": [{ "name": "COMPUTE_END", "ns": 2356425057540989 }] },
{"id": 1, "timestamps": [{ "name": "REQUEST_END", "ns": 2356425057643164 }] },
{"id": 1, "timestamps": [{ "name": "HTTP_SEND_START", "ns": 2356425057681578 }] },
{"id": 1, "timestamps": [{ "name": "HTTP_SEND_END", "ns": 2356425057712991 }] }
]
각 TENSORS 트레이스는 "activity"와 "tensor"를 담아요. "activity"는 텐서 유형으로 현재 "TENSOR_QUEUE_INPUT", "TENSOR_BACKEND_OUTPUT"이 있으며, "tensor"는 "name"·"data"·"dtype" 같은 상세 정보를 가집니다. 예:
[
{
"id": 1,
"activity": "TENSOR_QUEUE_INPUT",
"tensor":{
"name": "input",
"data": "0.1,0.1,0.1,...",
"shape": "1,16",
"dtype": "FP32"
}
}
]
트레이스 요약 도구
Triton에서 수집한 트레이스 집합을 요약하는 예제 도구를 사용할 수 있어요. 기본 사용법은 다음과 같습니다.
$ trace_summary.py <trace file>
그러면 파일 안의 모든 트레이스에 대한 요약 보고서가 나오고, HTTP·gRPC 추론 요청이 따로 보고됩니다.
File: trace.json
Summary for simple (-1): trace count = 1
HTTP infer request (avg): 403.578us
Receive (avg): 20.555us
Send (avg): 4.52us
Overhead (avg): 24.592us
Handler (avg): 353.911us
Overhead (avg): 23.675us
Queue (avg): 18.019us
Compute (avg): 312.217us
Input (avg): 24.151us
Infer (avg): 244.186us
Output (avg): 43.88us
Summary for simple (-1): trace count = 1
GRPC infer request (avg): 383.601us
Send (avg): 62.816us
Handler (avg): 392.924us
Overhead (avg): 51.968us
Queue (avg): 21.45us
Compute (avg): 319.506us
Input (avg): 27.76us
Infer (avg): 227.844us
Output (avg): 63.902us
참고: "Receive (avg)" 메트릭은 gRPC 요약에 포함되지 않아요. gRPC 라이브러리는 네트워크에서 메시지를 읽는 시간을 감지할 비침습적 후크를 제공하지 않기 때문입니다. HTTP 요청을 트레이스하면 네트워크에서 요청을 읽는 시간을 정확히 측정할 수 있어요.
-t 옵션을 쓰면 파일 안의 각 트레이스에 대한 요약을 얻을 수 있어요. 이 요약은 추론 요청 처리의 서로 다른 지점 사이의 시간(마이크로초)을 보여줍니다. 아래 출력은 요청 처리가 시작된 뒤 스케줄링 큐에 enqueue되기까지 15us가 걸렸다는 걸 보여줘요.
$ trace_summary.py -t <trace file>
...
simple (-1):
request handler start
15us
queue start
20us
compute start
266us
compute end
4us
request handler end
19us
grpc send start
77us
grpc send end
...
파일에 TENSORS 트레이스가 있으면 스크립트는 첫 요청의 데이터 흐름(data flow)도 보여줘요. TENSORS 트레이스가 앙상블에서 온 것이라면 각 모델의 의존성을 반영한 데이터 흐름이 표시됩니다.
...
Data Flow:
==========================================================
Name: ensemble
Version:1
QUEUE_INPUT:
input: [[0.705676 0.830855 0.833153]]
BACKEND_OUTPUT:
output: [[1. 2. 7. 0. 4. 7. 9. 3. 4. 9.]]
==========================================================
==================================================
Name: test_trt1
Version:1
QUEUE_INPUT:
input: [[0.705676 0.830855 0.833153]]
BACKEND_OUTPUT:
output1: [[1. 1. ...]]
==================================================
==================================================
Name: test_trt2
Version:1
QUEUE_INPUT:
input: [[0.705676 0.830855 0.833153]]
BACKEND_OUTPUT:
output2: [[2. 2. ...]]
==================================================
==================================================
Name: test_py
Version:1
QUEUE_INPUT:
output1: [[1. 1. ...]]
QUEUE_INPUT:
output2: [[2. 2. ...]]
BACKEND_OUTPUT:
output: [[1. 2. 7. 0. 4. 7. 9. 3. 4. 9.]]
==================================================
...
트레이스 타임스탬프의 의미는 다음과 같습니다.
- HTTP Request Receive: HTTP 프로토콜을 사용하는 추론 요청에만 수집. 네트워크에서 추론 요청을 읽는 데 걸린 시간.
- Send: 추론 응답을 보내는 데 걸린 시간.
- Overhead: HTTP 엔드포인트에서 추론 요청·응답을 처리하는 데 필요한 추가 시간.
- Handler: HTTP·gRPC 요청/응답 처리를 제외한, 추론 요청 처리에 쓴 총 시간.
- Queue: 추론 요청이 스케줄링 큐에서 보낸 시간.
- Compute: 실제 추론을 실행하는 데 쓴 시간. 입력·출력 텐서 복사 시간 포함.
--trace-level=TIMESTAMPS면 compute 시간이 아래처럼 세분화됩니다.- Input: 추론 프레임워크/백엔드가 요구하는 입력 텐서 데이터 복사 시간(GPU로의 입력 텐서 복사 포함).
- Infer: 모델을 실행해 추론하는 데 쓴 시간.
- Output: 추론 프레임워크/백엔드가 요구하는 출력 텐서 데이터 복사 시간(GPU에서의 출력 텐서 복사 포함).
- Overhead: Queue나 Compute 시간에 포함되지 않는 요청 처리 추가 시간.
- Data Flow: 첫 요청의 데이터 흐름. 실행 각 부분의 입력·출력 텐서를 포함.
- Name: 모델 이름.
- Version: 모델 버전.
- QUEUE_INPUT: 스케줄링 대기를 위해 백엔드의 큐로 들어가는 텐서.
- BACKEND_OUTPUT: 백엔드 응답 속의 텐서.
BLS 모델 트레이싱
Triton은 기본적으로 BLS 모델에서 호출한 하위(child) 모델의 트레이스를 수집하지 않아요.
하위 모델을 수집 트레이스에 포함하려면, 아래 예시처럼 InferenceRequest 객체를 만들 때 trace 인자를 제공해야 합니다. 이렇게 하면 Triton이 하위 모델을 부모 모델의 트레이스(request.trace())와 연결할 수 있어요.
import triton_python_backend_utils as pb_utils
class TritonPythonModel:
...
def execute(self, requests):
...
for request in requests:
...
inference_request = pb_utils.InferenceRequest(
model_name='model_name',
requested_output_names=['REQUESTED_OUTPUT_1', 'REQUESTED_OUTPUT_2'],
inputs=[<pb_utils.Tensor object>], trace = request.trace())
OpenTelemetry 트레이스 지원
Triton은 OpenTelemetry API와 SDK를 사용해 트레이스를 생성·내보낼 수 있는 옵션을 제공해요.
트레이싱에 OpenTelemetry 모드를 지정하려면 --trace-config 플래그를 다음과 같이 지정합니다.
$ tritonserver --trace-config mode=opentelemetry \
--trace-config opentelemetry,url=<endpoint> ...
Triton의 OpenTelemetry 트레이스 모드는 Batch Span Processor를 사용해 종료된 span을 배치로 묶어 한 번에 보내요. 배칭은 데이터 압축에 도움이 되고 데이터 전송에 필요한 아웃바운드 연결 수를 줄여줍니다. 이 프로세서는 크기·시간 기반 배칭을 모두 지원해요. 크기 기반 배칭은 bsp_max_export_batch_size·bsp_max_queue_size 2개 파라미터로, 시간 기반 배칭은 bsp_schedule_delay로 제어합니다. 배치 크기가 bsp_max_export_batch_size에 도달하거나, 마지막 내보내기 이후 지연이 bsp_schedule_delay에 도달하면(둘 중 먼저 오는 쪽) 수집된 span이 내보내져요. 또 bsp_max_export_batch_size가 항상 bsp_max_queue_size보다 작도록 해야 하는데, 그렇지 않으면 넘치는 span이 버려져 트레이스 데이터가 유실될 수 있어요.
Batch Span Processor의 기본 파라미터는 OpenTelemetry 트레이스 API 설정에 있어요. 일반적인 권장 사항으로 bsp_max_queue_size는 수집된 span을 모두 담을 수 있을 만큼 크게, bsp_schedule_delay는 잦은 내보내기로 Triton 서버의 지연시간에 영향을 주지 않도록 설정하세요. 최소한의 Triton 트레이스는 3개 span(최상위 span, 모델 span, compute span)으로 구성됩니다.
- 최상위 span(Top level span): 요청이 Triton에 수신된 시점과 응답이 전송된 시점의 타임스탬프를 수집해요. 모든 Triton 트레이스는 최상위 span 1개만 가집니다.
- 모델 span(Model span): 이 모델의 요청이 시작된 시점, 큐에 들어간 시점, 종료된 시점의 정보를 수집해요. 최소 Triton 트레이스는 모델 span 1개를 포함합니다.
- Compute span: compute 타임스탬프를 기록해요. 최소 Triton 트레이스는 compute span 1개를 포함합니다.
전체 span 수는 모델의 복잡도에 따라 달라져요. 일반적인 규칙은, 계산을 수행하는 단일 모델(기본 모델)은 모델 span 1개와 compute span 1개를 생산한다는 것입니다. 앙상블이라면 앙상블용 모델 span 1개에 더해 각 하위 모델이 모델·compute span을 생산하고, BLS 모델은 BLS 요청에 관여한 전체 모델 수(메인 BLS 모델 포함)만큼 모델·compute span을 생산합니다.
Triton 트레이스 출력과의 내용 차이
OpenTelemetry API는 Triton 트레이스 API와 같은 타임스탬프를 수집하는 span을 생산해요. 각 span에는 attribute로 model_name·model_version·request_id·parent_id도 포함됩니다.
span은 이름과 나노초 단위 타임스탬프로 구성된 TIMESTAMPS를 수집하는데, 이는 Triton 트레이스 API와 비슷해요. 다만 OpenTelemetry는 이벤트 타임스탬프를 시스템의 실시간 시계(real-time clock)에 의존하는 반면, Triton 트레이스 API는 단조 시계(steady clock, 항상 앞으로 나아가는 시계)를 사용해 타임스탬프를 보고해요. 이 시계는 벽시계 시간과 무관하며, 예를 들어 마지막 재부팅 이후 경과 시간을 측정할 수 있습니다.
OpenTelemetry 트레이스 API 설정
--trace-config opentelemetry,<setting>=<value>에 넘길 수 있는 OpenTelemetry 트레이스 API 설정은 다음과 같습니다.
| 설정 | 기본값 | 설명 |
|---|---|---|
url |
http://localhost:4318/v1/traces |
리시버가 트레이스 데이터를 받을 host:port. |
resource |
service.name=triton-inference-server |
리소스 속성으로 쓸 key-value 쌍. 템플릿: --trace-config opentelemetry,resource=<key>=<value>. 예: --trace-config opentelemetry,resource=service.name=triton, --trace-config opentelemetry,resource=service.version=1. 또는 OTEL_RESOURCE_ATTRIBUTES 환경변수로 지정 가능. |
| Batch Span Processor | ||
bsp_max_queue_size |
2048 | 최대 큐 크기. OTEL_BSP_MAX_QUEUE_SIZE 환경변수로도 지정 가능. |
bsp_schedule_delay |
5000 | 두 내보내기 사이의 지연 구간(밀리초). OTEL_BSP_SCHEDULE_DELAY 환경변수로도 지정 가능. |
bsp_max_export_batch_size |
512 | 최대 배치 크기. bsp_max_queue_size보다 작거나 같아야 함. OTEL_BSP_MAX_EXPORT_BATCH_SIZE 환경변수로도 지정 가능. |
OpenTelemetry 컨텍스트 전파
Triton은 24.01부터 OpenTelemetry 모드에서 컨텍스트 전파(context propagation)를 지원해요. 전파된 OpenTelemetry 컨텍스트가 있는 요청은 rate·count 트레이스 설정과 무관하게 전부 트레이스된다는 점에 주의하세요. 클라이언트 쪽에서 OpenTelemetry 컨텍스트를 주입한 요청만 트레이스하고 싶다면 --trace-config rate=0으로 Triton을 시작하면 됩니다:
$ tritonserver \
--trace-config rate=0 \
--trace-config level=TIMESTAMPS \
--trace-config count=-1 \
--trace-config mode=opentelemetry
이 옵션은 향후 릴리스에서 바뀔 수 있음을 유의하세요.
클라이언트 쪽에서 OpenTelemetry 컨텍스트 주입하는 방법
C++ 클라이언트는 gRPC·HTTP 예제를 참고하세요.
Python 클라이언트는 OpenTelemetry Python을 설치하고, opentelemetry.propagate.inject 메서드로 요청에 넘길 헤더를 준비하면 됩니다(여기 참고). 그 다음 infer 메서드에 헤더를 지정하면 돼요. 참고로 테스트를 보세요(예: http context propagation test).
커스텀 백엔드 트레이싱
백엔드에서 커스텀 activity를 트레이스해야 하는 경우 TRITONSERVER_InferenceTraceReportActivity API를 사용하세요. 예시는 identity backend를 참고합니다.
openTelemetry 트레이스 모드에서 새 span을 시작하려면 커스텀 activity 이름이 _START로 끝나야 하고, span을 끝내려면 해당 activity가 _END로 끝나야 합니다. 예를 들어 identity backend에서는 CUSTOM_ACTIVITY_START 이벤트를 보고해 CUSTOM_ACTIVITY span을 시작하고, CUSTOM_ACTIVITY_END 이벤트를 보고해 그 span을 닫아요.
시작한 모든 커스텀 span이 제대로 닫히도록 하는 것은 사용자의 책임입니다.
제약 사항
- Triton은 OTLP/HTTP Exporter만 지원하고, 이 exporter에
--trace-config로 url만 지정할 수 있어요. 다른 옵션과 기본값은 여기에서 찾을 수 있습니다. - Triton은 Triton 실행 중에 opentelemetry 트레이스 설정을 구성하는 것을 지원하지 않으며, opentelemetry 전용 설정은 Triton의 트레이스 확장으로 조회할 수 없어요.