Зачем это нужно
Inference request проходит: Ingress → Istio → churn-serving → Feature API → (cache) → model forward. Latency выросла на 200 ms. Metrics показывают p95; trace показывает, какой hop съел время. Без tracing вы оптимизируете model, а виноват сетевой вызов фич.
OpenTelemetry (OTel) — открытый стандарт traces (и metrics/logs). В курсе — propagation через Istio и instrumentation в Python-сервисе.
Основные идеи
Trace, span, context.
Trace — один end-to-end request (trace_id).
Span — один участок работы (HTTP call,
model.predict).Parent-child spans формируют дерево.
W3C Trace Context. Header traceparent передаётся между сервисами. Istio sidecar генерирует/продолжает trace.
OpenTelemetry components.
| Piece | Role |
|---|---|
| OTel SDK | Instrument app, create spans |
| OTel Collector | Receive, process, export to backend |
| Backend | Jaeger, Tempo, Zipkin |
Auto vs manual instrumentation.
Auto: some frameworks HTTP clients.
Manual:
@tracer.start_as_current_span("predict")around model inference — видеть GPU forward отдельно от HTTP handler.
Sampling. 100% traces дорого. Head-based sampling 1–10% in prod; always sample errors (tail sampling in Collector — advanced).
Istio + tracing. Mesh config enables tracing provider; spans for ingress and outbound calls without app changes — good baseline.
ML-specific spans.
validate_inputfetch_featurespreprocessmodel_inferencepostprocess
Compare p95 model_inference vs fetch_features — guides optimization.
Correlation.
trace_idin structured logs (5.2.1).Grafana: jump from trace to logs with same trace_id.
Tempo vs Jaeger. Grafana Tempo integrates natively with Loki/Prometheus; Jaeger classic UI. Both accept OTLP export.
Как это выглядит на практике
Python (conceptual):
` from opentelemetry import trace tracer = trace.get_tracer("churn-serving")
@app.post("/predict") async def predict(data: Features): with tracer.start_as_current_span("predict") as span: with tracer.start_as_current_span("fetch_features"): feats = await feature_client.get(data.user_id) with tracer.start_as_current_span("model_inference"): score = model.predict(feats) span.set_attribute("model.version", MODEL_VERSION) return {"score": score} `
Incident: p95 800 ms, GPU idle.
Open Grafana Tempo → filter
service.name=churn-serving.Trace waterfall:
fetch_features750 ms.Drill Feature API traces — DB query slow.
Fix index upstream; inference team not retraining model.
Istio telemetry: enable tracing sample 5%; compare app span vs sidecar span for overhead audit.
Что сделать после занятия
Нарисуйте span tree для
/predictс минимум 4 spans.Объясните, зачем
trace_idв JSON logs.Прочитайте OTel docs: что такое OTLP exporter.