C API
C API (인프로세스)
Triton 서버 기능은 core 저장소에서 만든 공유 라이브러리에 담겨 있어요. 여러분은 이 공유 라이브러리를 자신의 애플리케이션에 링크하고, tritonserver.h에 정의된 C API를 쓰면 Triton의 모든 기능을 포함할 수 있어요.
중요한 점은, 이렇게 Triton 공유 라이브러리를 애플리케이션에 링크할 때 별도의 Triton 프로세스를 띄우는 것이 아니라 Triton 코어 로직을 여러분의 애플리케이션에 직접 포함하게 된다는 거예요. 이 경우 HTTP/REST나 gRPC 프로토콜로 통신하지 않아요. 애플리케이션과 Triton 코어 로직 사이의 모든 통신은 Server API를 통해 이뤄져야 해요.
출처: 공식문서
TRITONSERVER_Server: 최상위 추상화
Server API가 쓰는 최상위 추상화는 TRITONSERVER_Server예요. 이 객체는 Triton의 모든 기능을 구현하는 Triton 코어 로직을 나타내요. TRITONSERVER_Server 객체는 TRITONSERVER_ServerNew에 객체를 어떻게 초기화할지 나타내는 옵션들을 넘겨서 만드는데, 사용법은 simple.cc에 나와 있어요. Server 객체를 만들고 나면 아래에서 설명하는 나머지 Server API를 쓰기 시작하면 됩니다.
에러 처리
대부분의 Server API 함수는 성공/실패를 나타내는 에러 객체를 반환해요. 성공은 nullptr(NULL)을 반환하고, 실패는 TRITONSERVER_Error 객체를 반환해요. 에러 코드와 메시지는 TRITONSERVER_ErrorCode와 TRITONSERVER_ErrorMessage로 가져올 수 있어요.
모든 Server API 객체의 수명과 소유권 규칙은 tritonserver.h에 문서화되어 있어요. TRITONSERVER_Error의 경우 객체의 소유권이 Server API 함수를 호출한 쪽(여러분 애플리케이션)으로 넘어가요. 그래서 사용이 끝나면 TRITONSERVER_ErrorDelete로 에러 객체를 삭제해야 해요. common.h에 있는 FAIL_IF_ERR 같은 매크로가 에러 객체 수명 관리에 유용해요.
버전 관리와 하위 호환성
simple.cc에 나온 대표적인 패턴으로, 공유 라이브러리가 제공하는 Server API 버전과 여러분이 애플리케이션을 컴파일할 때 사용한 Server API 버전을 비교할 수 있어요. Server API는 하위 호환이 되므로, 공유 라이브러리가 제공하는 메이저 버전이 컴파일할 때 쓴 메이저 버전과 같고, 마이너 버전이 컴파일할 때 쓴 마이너 버전보다 크거나 같으면 애플리케이션이 그 Server API를 사용할 수 있어요.
#include "tritonserver.h"
// Error checking removed for clarity...
uint32_t api_version_major, api_version_minor;
TRITONSERVER_ApiVersion(&api_version_major, &api_version_minor);
if ((TRITONSERVER_API_VERSION_MAJOR != api_version_major) ||
(TRITONSERVER_API_VERSION_MINOR > api_version_minor)) {
// Error, the shared library implementing the Server API is older than
// the version of the Server API that you compiled against.
}
추론이 아닌 API (Non-Inference APIs)
Server API에는 헬스/준비 상태 확인, 모델 정보 조회, 모델 통계·메트릭 조회, 모델 로드/언로드 등의 함수가 있어요. 이 함수들의 사용은 단순하고, 일부는 simple.cc에서, 전부는 tritonserver.h에서 확인할 수 있어요.
추론 API (Inference APIs)
추론 요청을 수행하려면 많은 Server API 함수와 객체를 사용해야 해요. simple.cc에 나온 일반적인 사용 흐름은 다음과 같아요.
-
TRITONSERVER_ResponseAllocator만들기 —TRITONSERVER_ResponseAllocatorNew로 만드는데, 모든 추론 요청에 같은 할당자를 쓸 수도 있고 여러 개를 만들 수도 있어요. Triton이 출력 텐서를 만들 때 그 텐서 내용을 저장할 메모리 버퍼가 필요한데, Triton은 이 출력 버퍼 할당을 여러분 애플리케이션의 콜백 함수를 호출해 지연시켜요. 이 콜백 함수들을TRITONSERVER_ResponseAllocator객체로 Triton에 전달해요. 버퍼 할당용 콜백 하나와 버퍼 해제용 콜백 하나, 총 두 개를 구현해야 하는데, 시그니처는 tritonserver.h의TRITONSERVER_ResponseAllocatorAllocFn_t·TRITONSERVER_ResponseAllocatorReleaseFn_t예요.simple.cc에서는 이 콜백들을ResponseAlloc·ResponseRelease로 구현해요. -
추론 요청 객체 만들기 —
TRITONSERVER_InferenceRequest객체로, 어떤 모델을 쓸지, 입력 텐서와 값, 반환받을 출력 텐서, 기타 요청 파라미터를 지정해요.TRITONSERVER_InferenceRequestNew로 만들고, 각 입력 텐서는TRITONSERVER_InferenceRequestAddInput으로, 입력 텐서 데이터는TRITONSERVER_InferenceRequestAppendInputData(또는 tritonserver.h에 정의된TRITONSERVER_InferenceRequestAppendInputData*변형)로 설정해요. 기본적으로 Triton은 모든 출력 텐서를 반환하지만,TRITONSERVER_InferenceRequestAddRequestedOutput으로 일부 출력만 반환하도록 제한할 수도 있어요.요청 객체의 수명을 제대로 관리하려면
TRITONSERVER_InferenceRequestSetReleaseCallback으로 여러분 애플리케이션의 함수 콜백을 지정해야 해요. Triton이 이 콜백을 호출해TRITONSERVER_InferenceRequest객체의 소유권을 돌려주는데, 보통은 콜백 안에서TRITONSERVER_InferenceRequestDelete로 삭제해요. 물론 객체를 재사용하는 경우처럼 다른 수명 관리를 구현해도 돼요.선택적으로
TRITONSERVER_InferenceRequestSetId로 사용자 정의 ID를 붙일 수 있는데, 이 ID는 Triton이 쓰지 않고 응답에 그대로 실려 돌아와요.기존
TRITONSERVER_InferenceRequest객체를 새 추론 요청에 재사용할 수도 있는데, 방법과 유용한 이유가simple.cc에 예시로 나와 있어요. -
TRITONSERVER_ServerInferAsync로 추론 실행 요청 — 이 함수는 즉시 반환하는 비동기 호출이에요. 추론 응답은 여러분 애플리케이션의 콜백으로 돌아오는데,TRITONSERVER_ServerInferAsync를 호출하기 전에TRITONSERVER_InferenceRequestSetResponseCallback으로 이 콜백을 등록해요.simple.cc에서는 이 콜백이InferResponseComplete예요.TRITONSERVER_ServerInferAsync를 호출해 오류 없이 반환되면, 그 시점부터TRITONSERVER_InferenceRequest객체의 소유권이 Triton으로 넘어가요. 그래서TRITONSERVER_InferenceRequestSetReleaseCallback으로 등록한 콜백을 통해 Triton이 소유권을 돌려줄 때까지 그 객체를 어떤 식으로도 접근하면 안 돼요. -
추론 응답 처리 — 응답은
TRITONSERVER_InferenceRequestSetResponseCallback으로 등록한 콜백 함수로 돌아와요. 콜백은TRITONSERVER_InferenceResponse객체로 응답을 받고, 이 객체의 소유권을 가지므로 다 쓰고 나면TRITONSERVER_InferenceResponseDelete로 해제해야 해요.응답 처리의 첫 단계는
TRITONSERVER_InferenceResponseError로 응답이 에러인지 정상 결과인지 확인하는 거예요. 정상이면TRITONSERVER_InferenceResponseOutputCount로 출력 텐서를 순회하고,TRITONSERVER_InferenceResponseOutput으로 각 출력 텐서 정보를 가져와요.
참고로 simple.cc 예제는 std::promise로 단순히 응답을 기다리지만, 꼭 이렇게 동기식으로 처리할 필요는 없어요. 동시에 여러 추론 요청을 처리할 수 있고, 같은 스레드나 서로 다른 여러 스레드에서 추론 요청을 보낼 수 있어요.
더 알아보기 (Learn more)
- 인프로세스 Triton 서버 API — Server API 개요
- Java 인프로세스 API 바인딩 — Java에서 활용하기