Gymterview
middle

Что такое distributed tracing?

Distributed tracing (распределённая трассировка) — метод отслеживания прохождения запроса через множество сервисов в распределённой системе. Каждый запрос получает уникальный идентификатор (traceId), который передаётся между сервисами, позволяя восстановить полную картину обработки.

Зачем нужен distributed tracing

В микросервисной архитектуре один пользовательский запрос может вызвать цепочку вызовов:

Пример
Пользователь → API Gateway → Order Service → Payment Service → Notification Service
                                  │                                    │
                                  └── Inventory Service                └── Email Service
                                         │
                                         └── Warehouse Service

Без distributed tracing невозможно:

  • Понять, какой сервис в цепочке вызвал задержку
  • Отследить, где произошла ошибка
  • Увидеть зависимости между сервисами
  • Оценить влияние одного сервиса на остальные

Основные концепции

Концепция Описание
Trace Полная запись обработки одного запроса через все сервисы (уникальный traceId)
Span Единица работы внутри trace: spanId, parentSpanId, operationName, startTime, duration, tags, status
Context Propagation Механизм передачи traceId/spanId между сервисами через HTTP-заголовки, Kafka headers, gRPC metadata

W3C Trace Context (стандарт)

Пример
GET /api/orders HTTP/1.1
Host: order-service
traceparent: 00-4bf92f3577b34da6a3ce929d0e0e4736-00f067aa0ba902b7-01

# traceparent формат:
# {version}-{trace-id}-{parent-id}-{trace-flags}
# 00       - 4bf92f...  - 00f067...  - 01 (sampled)

Waterfall-диаграмма (визуализация трейса)

Пример
TraceID: abc123def456

├── API Gateway: GET /api/orders [250ms] ────────────────────────────────────
│   ├── Order Service: getOrders [200ms] ────────────────────────────────
│   │   ├── PostgreSQL: SELECT * FROM orders [15ms] ──────
│   │   ├── Redis: GET cache:orders [2ms] ──
│   │   ├── Inventory Service: checkStock [120ms] ─────────────────
│   │   │   └── Warehouse DB: SELECT stock [10ms] ────
│   │   └── Payment Service: validatePayments [50ms] ──────────
│   │       └── Stripe API: GET /charges [40ms] ────────
│   └── Auth: validateToken [5ms] ──

По этой диаграмме видно:

  • Общее время запроса — 250ms
  • Самая долгая операция — checkStock (120ms) — кандидат на оптимизацию
  • Запросы к Redis и Auth выполняются быстро
  • Order Service ждёт последовательно Inventory и Payment — можно параллелить

Стратегии семплирования (Sampling)

Трейсить 100% запросов в production дорого. Стратегии:

Стратегия Описание Когда использовать
Head-based Решение о семплировании принимается в начале трейса Простая, но может пропустить интересные трейсы
Tail-based Решение принимается после завершения трейса Позволяет сохранять трейсы с ошибками или высокой задержкой
Rate limiting Фиксированное количество трейсов в секунду Контроль нагрузки
Probabilistic Фиксированный процент (1%, 10%) Простейший вариант
Пример tail-based sampling в OTel Collector
processors:
  tail_sampling:
    decision_wait: 10s
    policies:
      - name: errors
        type: status_code
        status_code: {status_codes: [ERROR]}
      - name: slow-traces
        type: latency
        latency: {threshold_ms: 1000}
      - name: probabilistic
        type: probabilistic
        probabilistic: {sampling_percentage: 10}

Важное

  • Context propagation — критически важен. Если хотя бы один сервис в цепочке не передаёт контекст, трейс обрывается.
  • Span — не лог. Span описывает единицу работы с началом и концом. Не создавайте span для каждой строки кода.
  • Instrumentation библиотеки (JDBC, HTTP-клиенты, Kafka, gRPC) автоматически создают spans — не нужно оборачивать каждый вызов вручную.
  • Sampling обязателен в production: без него overhead на трейсинг может составлять 5-15% ресурсов.

Частые ошибки

  • Потеря контекста при асинхронных вызовах: при использовании @Async, CompletableFuture, реактивных цепочек контекст нужно передавать явно.
  • Слишком детальные спаны: создание span на каждый вызов метода перегружает систему. Спаны нужны для I/O-операций и бизнес-логики.
  • Игнорирование семплирования: 100% трейсов в production — это огромный объём данных и нагрузка на хранилище.
  • Несогласованные имена операций: getOrder, GET_ORDER, order.get — разные имена для одной операции усложняют анализ.

Как используется в 2026

  • W3C Trace Context — стандарт де-факто для propagation.
  • OpenTelemetry — единый API и SDK для трейсинга, заменивший Jaeger client, Zipkin Brave и OpenTracing.
  • Grafana Tempo и Jaeger v2 — популярные бэкенды для хранения трейсов.
  • Trace-based testing (Tracetest) — использование трейсов для написания интеграционных тестов.
  • Continuous profiling + tracing — связка профилирования с трейсами (Grafana Pyroscope).

На собеседовании: объясните концепции Trace/Span/Context Propagation и покажите, что умеете читать waterfall-диаграмму. Упомяните необходимость семплирования в production и W3C Trace Context как стандарт. Частая ошибка — забыть про потерю контекста в асинхронных вызовах.