Настройка Distributed Tracing (Jaeger/Zipkin) для микросервисов
Distributed Tracing позволяет отследить путь запроса через несколько микросервисов как единый «трейс». Когда HTTP-запрос пользователя проходит через API Gateway → Order Service → Inventory Service → Payment Service, трейс показывает время в каждом сервисе, какие БД-запросы выполнялись и где возникло замедление.
Ключевые концепции
Trace — полный путь запроса от начала до конца. Состоит из спанов.
Span — единица работы (HTTP-запрос, вызов БД, вызов внешнего API). Каждый спан содержит: имя операции, время начала/конца, теги (key-value), логи, ссылку на родительский спан.
Context Propagation — trace-id и span-id передаются в HTTP-заголовках (traceparent в W3C Trace Context или X-B3-TraceId в Zipkin).
OpenTelemetry — стандарт инструментирования
OpenTelemetry (OTel) — vendor-neutral SDK. Один раз инструментируете код, а данные отправляете в Jaeger, Zipkin, Datadog или любой другой бэкенд.
// 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); // дочерний span создаётся авто
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 vs 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 дня







