Налаштування Distributed Tracing (Jaeger/Zipkin) для мікросервісів
Distributed Tracing дозволяє відстежити шлях запиту через кілька мікросервісів як один "трейс". Коли HTTP-запит користувача проходить через API Gateway → Order Service → Inventory Service → Payment Service, трейс показує час у кожному сервісі, які DB-запити були виконані і де сталося уповільнення.
Ключові концепції
Trace — повний шлях запиту від початку до кінця. Складається зі спанів.
Span — одиниця роботи (HTTP-запит, виклик БД, виклик зовнішнього API). Кожен спан містить: імя операції, час початку/закінчення, теги (key-value), логи, посилання на батьківський спан.
Context Propagation — trace-id та span-id передаються в HTTP-заголовках (traceparent у W3C Trace Context або X-B3-TraceId у Zipkin).
OpenTelemetry — стандарт інструментування
OpenTelemetry (OTel) — незалежний від постачальника SDK. Один раз інструментуєте код, а дані можуть надсилатися в Jaeger, Zipkin, Datadog або будь-який інший backend.
// tracing.ts — ініціалізація, імпортуйте перед усім іншим
import { NodeSDK } from '@opentelemetry/sdk-node';
import { getNodeAutoInstrumentations } from '@opentelemetry/auto-instrumentations-node';
import { OTLPTraceExporter } from '@opentelemetry/exporter-trace-otlp-http';
import { Resource } from '@opentelemetry/resources';
import { SEMRESATTRS_SERVICE_NAME } from '@opentelemetry/semantic-conventions';
const sdk = new NodeSDK({
resource: new Resource({
[SEMRESATTRS_SERVICE_NAME]: 'order-service',
}),
traceExporter: new OTLPTraceExporter({
url: process.env.OTEL_EXPORTER_OTLP_ENDPOINT || 'http://jaeger:4318/v1/traces',
}),
instrumentations: [
getNodeAutoInstrumentations({
'@opentelemetry/instrumentation-http': { enabled: true },
'@opentelemetry/instrumentation-express': { enabled: true },
'@opentelemetry/instrumentation-pg': { enabled: true },
'@opentelemetry/instrumentation-redis': { enabled: true },
}),
],
});
sdk.start();
Авто-інструментації перехоплюють Express, pg, redis, axios без написання коду.
Ручне створення спанів
Для бізнес-операцій, які не перехоплюються авто-інструментаціями:
import { trace, SpanStatusCode, context } from '@opentelemetry/api';
const tracer = trace.getTracer('order-service');
async function processOrder(orderId: string): Promise<void> {
const span = tracer.startSpan('processOrder', {
attributes: {
'order.id': orderId,
'service.operation': 'process'
}
});
try {
await context.with(trace.setSpan(context.active(), span), async () => {
const order = await loadOrder(orderId); // дочірній спан створюється авто
await validateOrder(order);
await reserveInventory(order); // виклик іншого сервісу з propagation
await chargePayment(order);
});
span.setStatus({ code: SpanStatusCode.OK });
} catch (error) {
span.recordException(error);
span.setStatus({ code: SpanStatusCode.ERROR, message: error.message });
throw error;
} finally {
span.end();
}
}
Встановлення Jaeger через Docker
# docker-compose.yml
services:
jaeger:
image: jaegertracing/all-in-one:1.52
ports:
- "16686:16686" # UI
- "4317:4317" # OTLP gRPC
- "4318:4318" # OTLP HTTP
environment:
COLLECTOR_OTLP_ENABLED: "true"
SPAN_STORAGE_TYPE: "badger" # для продакшну — Elasticsearch
Jaeger з Elasticsearch (продакшн)
services:
jaeger-collector:
image: jaegertracing/jaeger-collector:1.52
environment:
SPAN_STORAGE_TYPE: elasticsearch
ES_SERVER_URLS: http://elasticsearch:9200
ES_INDEX_PREFIX: jaeger
depends_on:
- elasticsearch
jaeger-query:
image: jaegertracing/jaeger-query:1.52
ports:
- "16686:16686"
environment:
SPAN_STORAGE_TYPE: elasticsearch
ES_SERVER_URLS: http://elasticsearch:9200
Sampling
У продакшні неможливо трейсити 100% запитів — дорого. Стратегії Sampling:
import { ParentBasedSampler, TraceIdRatioBased } from '@opentelemetry/sdk-trace-base';
// Трейсити 10% запитів, але завжди якщо батьківський уже трейсується
const sampler = new ParentBasedSampler({
root: new TraceIdRatioBased(0.1)
});
Head-based sampling — рішення приймається при старті трейсу (дешево, але втрачає рідкісні помилки). Tail-based sampling — у Jaeger Agent, рішення після отримання цілого трейсу, можна зберігати всі трейсу з помилками.
Zipkin проти Jaeger
| Zipkin | Jaeger | |
|---|---|---|
| Сховище | MySQL, Elasticsearch, Cassandra | Elasticsearch, Cassandra, Kafka |
| UI | Базовий | Багатший |
| OTel підтримка | Є | Нативна |
| Sampling | Базовий | Розширений |
Для нових проектів — Jaeger. Zipkin — якщо вже використовується або потрібна сумісність.
Терміни реалізації
- OpenTelemetry SDK + Jaeger + авто-інструментація для 3–5 сервісів — 3–5 днів
- Ручне інструментування бізнес-операцій + налаштування sampling — ще 3–5 днів
- Налаштування алертів на p95 latency через Prometheus + Grafana — 2–3 дні







