[SGLang] Observability: 추적, 메트릭, 프로파일링 인프라
들어가며
프로덕션 LLM 서빙에서는 성능 병목, 지연 원인, 리소스 사용량을 실시간으로 파악해야 한다. SGLang은 observability/ 패키지를 통해 OpenTelemetry 추적, Prometheus 메트릭, 함수 레이턴시 측정, CPU 모니터링 등의 관측 도구를 제공한다.
구조도
observability/
├── trace.py ── OpenTelemetry 분산 추적
├── metrics_collector.py ── Prometheus 메트릭 수집
├── func_timer.py ── 함수 레이턴시 히스토그램
├── cpu_monitor.py ── CPU 사용량 모니터링
├── req_time_stats.py ── 요청별 시간 통계
├── request_metrics_exporter.py ── 메트릭 파일 내보내기
├── scheduler_metrics_mixin.py ── 스케줄러 메트릭 믹스인
├── startup_func_log_and_timer.py ── 시작 시 로깅/타이머
├── label_transform.py ── 메트릭 레이블 변환
└── utils.py ── 유틸리티 (버킷 생성 등)
핵심 코드 분석
OpenTelemetry 추적 (trace.py)
trace.py는 OpenTelemetry를 사용한 분산 추적을 구현한다. gRPC와 HTTP 양쪽 프로토콜을 지원한다.
try:
from opentelemetry import context, propagate, trace
from opentelemetry.exporter.otlp.proto.grpc.trace_exporter import (
OTLPSpanExporter as GRPCSpanExporter)
from opentelemetry.exporter.otlp.proto.http.trace_exporter import (
OTLPSpanExporter as HTTPSpanExporter)
from opentelemetry.sdk.trace import TracerProvider, id_generator
from opentelemetry.sdk.trace.export import BatchSpanProcessor
opentelemetry_imported = True
except ImportError:
logger.debug("opentelemetry package is not installed, tracing disabled")
추적 컨텍스트는 W3C TraceContext 형식(traceparent, tracestate)을 따른다.
TRACE_HEADERS = ["traceparent", "tracestate"]
def extract_trace_headers(headers: Mapping[str, str]) -> Optional[Dict]:
return {h: headers[h] for h in TRACE_HEADERS if h in headers}
추적 이벤트와 슬라이스를 구조화한 데이터클래스도 제공한다.
@dataclass
class TraceSliceContext:
slice_name: str
start_time_ns: int
end_time_ns: Optional[int] = None
span: Optional[trace.span.Span] = None
Prometheus 메트릭 수집 (metrics_collector.py)
SchedulerStats는 스케줄러의 핵심 지표를 수집한다. 실행 중 요청 수, 토큰 사용량, 캐시 히트율, 처리량 등을 추적한다.
@dataclass
class SchedulerStats:
num_running_reqs: QueueCount = field(default_factory=QueueCount)
num_used_tokens: int = 0
token_usage: float = 0.0
gen_throughput: float = 0.0
num_queue_reqs: QueueCount = field(default_factory=QueueCount)
cache_hit_rate: float = 0.0
max_total_num_tokens: int = 0
spec_accept_length: float = 0.0
spec_accept_rate: float = 0.0
우선순위 스케줄링이 활성화된 경우 우선순위별 요청 수도 추적한다.
@dataclass
class QueueCount:
total: int = 0
by_priority: Optional[Dict[int, int]] = None
@classmethod
def from_reqs(cls, reqs, enable_priority_scheduling=False):
by_priority = (
dict(Counter(req.priority for req in reqs))
if enable_priority_scheduling else None)
return cls(total=len(reqs), by_priority=by_priority)
함수 레이턴시 타이머 (func_timer.py)
time_func_latency 데코레이터는 동기/비동기 함수의 실행 시간을 Prometheus Histogram으로 기록한다.
def enable_func_timer():
global enable_metrics, FUNC_LATENCY
enable_metrics = True
FUNC_LATENCY = Histogram(
"sglang:func_latency_seconds",
"Function latency in seconds",
buckets=exponential_buckets(start=0.05, width=1.5, length=18),
labelnames=["name"],
)
동기와 비동기 함수를 모두 지원한다.
def time_func_latency(func=None, name=None):
def measure(func):
@wraps(func)
async def async_wrapper(*args, **kwargs):
if not enable_metrics:
return await func(*args, **kwargs)
start = time.monotonic()
ret = await func(*args, **kwargs)
FUNC_LATENCY.labels(name=name).observe(time.monotonic() - start)
return ret
@wraps(func)
def sync_wrapper(*args, **kwargs):
if not enable_metrics:
return func(*args, **kwargs)
start = time.monotonic()
ret = func(*args, **kwargs)
FUNC_LATENCY.labels(name=name).observe(time.monotonic() - start)
return ret
메트릭이 비활성화되면 오버헤드 없이 원래 함수를 직접 호출한다.
CPU 모니터링 (cpu_monitor.py)
별도 데몬 스레드에서 psutil을 사용하여 CPU 시간을 주기적으로 측정한다.
def start_cpu_monitor_thread(component: str, interval: float = 5.0):
cpu_seconds_total = Counter(
name="sglang:process_cpu_seconds_total",
documentation="Total CPU time consumed by this process",
labelnames=["component"],
)
def monitor():
process = psutil.Process()
last_times = process.cpu_times()
while True:
time.sleep(interval)
curr_times = process.cpu_times()
delta = (curr_times.user - last_times.user) + \
(curr_times.system - last_times.system)
cpu_seconds_total.labels(component=component).inc(delta)
last_times = curr_times
t = threading.Thread(target=monitor, daemon=True)
t.start()
활성화 방법
| 기능 | 서버 인자 | 설명 |
|---|---|---|
| Prometheus 메트릭 | --enable-metrics |
스케줄러/요청 통계 |
| OpenTelemetry 추적 | --enable-trace |
분산 추적 |
| OTLP 엔드포인트 | --otlp-traces-endpoint |
기본: localhost:4317 |
| 메트릭 HTTP 포트 | --metrics-http-port |
Prometheus scrape 포트 |
| 파일 내보내기 | --export-metrics-to-file |
메트릭을 파일로 저장 |
관련 포스트
- Server Args: 300+ 서버 인자 완전 가이드
- Debug Utils: 텐서 비교, 스케줄 시뮬레이터
참고
- 소스 코드:
python/sglang/srt/observability/ - OpenTelemetry Python SDK
- Prometheus Client Python
관련 포스트
SGLang 의 다른글
- 이전글 [SGLang] sgl-kernel: 커스텀 C++/CUDA 커널 라이브러리
- 현재글 : [SGLang] Observability: 추적, 메트릭, 프로파일링 인프라
- 다음글 [SGLang] Debug Utils: 텐서 비교, 스케줄 시뮬레이터
댓글