Что такое распределённая трассировка (Distributed Tracing) в микросервисах?

Ответ

Распределённая трассировка — это метод мониторинга и диагностики, который позволяет отслеживать путь (трассу) единого запроса через цепочку микросервисов. Она визуализирует поток выполнения, задержки на каждом этапе и зависимости между сервисами.

Ключевые концепции:

  • Trace (Трасса): Полная запись пути запроса от начала до конца. Имеет уникальный traceId.
  • Span (Спан): Представляет собой отдельную логическую операцию/этап внутри трассы (например, вызов одного сервиса). Имеет spanId и ссылку на parentSpanId. Содержит метки, события и временные метки (начало, конец).
  • Распространение контекста (Context Propagation): Механизм автоматической передачи traceId и spanId через HTTP-заголовки или шину сообщений между сервисами.

Как это работает:

  1. Входящий запрос получает или генерирует traceId.
  2. Каждый сервис, обрабатывая запрос, создаёт свой span, добавляя в него информацию (имя сервиса, операция, тайминги, ошибки).
  3. traceId и spanId передаются дальше при любых исходящих вызовах.
  4. Все спаны отправляются в централизованную систему сбора (например, Jaeger).

Пример кода с использованием OpenTelemetry (стандарт де-факто):

import io.opentelemetry.api.trace.Span;
import io.opentelemetry.api.trace.Tracer;

// Создание и активация span в сервисе
Tracer tracer = OpenTelemetry.getGlobalTracer("order-service");
Span span = tracer.spanBuilder("processOrder").startSpan();

try (Scope scope = span.makeCurrent()) {
    // Логика обработки заказа
    span.addEvent("Order validated");
    // Вызов другого сервиса (traceId автоматически передастся в заголовках)
    inventoryService.reserveItems(orderId);
    span.setAttribute("order.total", order.getTotal());
} catch (Exception e) {
    span.recordException(e); // Фиксация ошибки в span
    span.setStatus(StatusCode.ERROR);
    throw e;
} finally {
    span.end(); // Завершение span и отправка данных
}

Популярные инструменты: Jaeger, Zipkin, AWS X-Ray. Они собирают трассы, предоставляя UI для анализа латентности, поиска узких мест и отладки ошибок в сложных распределённых сценариях.

Ответ 18+ 🔞

А, распределённая трассировка! Ну это, блядь, такая штука, когда у тебя запрос, как пьяный матрос по борделям, по всем твоим микросервисам шляется, а ты сидишь и думаешь: "Ну и где же он, сука, сейчас завис, этот пидорас?"

Основные пизделки, о которых речь:

  • Trace (Трасса): Это как полный маршрут этого самого матроса от первого бара до того, как его вынесут в говно. У него есть свой уникальный паспорт — traceId.
  • Span (Спан): А это уже посещение каждого конкретного заведения. Зашёл в "Сервис-А" — один спан, оттрахался там, пошёл в "Сервис-Б" — второй спан. У каждого своя spanId и запись, кто его родитель (parentSpanId). Там всё: во сколько зашёл, во сколько вышел, что делал, не обосрался ли.
  • Распространение контекста: Самый, блядь, важный трюк! Это когда наш матрос, уходя из одного сервиса, не забывает свою бирку (traceId) и квитанцию от текущего бара (spanId) пришпилить к пиджаку, чтобы в следующем заведении знали, откуда он идёт.

Как это, сука, работает:

  1. Приходит запрос — ему тут же в лоб штампуют traceId. Всё, пошла пьянка.
  2. Каждый сервис, которого он касается, создаёт свой спан и пишет туда всё: "Я такой-то сервис, делал такую-то хуйню, начал в 14:00, кончил в 14:03, ошибок не было (или были, пидор)".
  3. Когда сервису надо позвать другого, он эти бирки (traceId, spanId) суёт в заголовки HTTP-запроса, как засланного казачка. "На, передай дальше".
  4. Все эти спаны летят в какую-нибудь центральную помойку для логов, типа Jaeger, где их уже можно разглядывать.

Вот, смотри, как на Java с OpenTelemetry это выглядит (это сейчас, блядь, стандарт такой):

import io.opentelemetry.api.trace.Span;
import io.opentelemetry.api.trace.Tracer;

// Создаём и запускаем спан в сервисе
Tracer tracer = OpenTelemetry.getGlobalTracer("order-service");
Span span = tracer.spanBuilder("processOrder").startSpan();

try (Scope scope = span.makeCurrent()) {
    // Тут твоя бизнес-логика, ебать её в сраку
    span.addEvent("Order validated"); // Событие зафиксировал
    // Вызов другого сервиса — traceId улетит сам, в рот меня чих-пых!
    inventoryService.reserveItems(orderId);
    span.setAttribute("order.total", order.getTotal()); // Атрибут какой-то
} catch (Exception e) {
    span.recordException(e); // ОЙ, БЛЯДЬ! Записываем ошибку в спан
    span.setStatus(StatusCode.ERROR);
    throw e;
} finally {
    span.end(); // Всё, спан закрыли, данные полетели в систему
}

Инструменты, которые это всё собирают: Jaeger, Zipkin, AWS X-Ray. Они, эти мартышлюшки, рисуют тебе красивые картинки, где видно, какой сервис сколько времени ебался, где задержка, а где всё просто накрылось медным тазом. Без этого в микросервисах — нихуя не отладишь, один сплошной волшебный пиздец.