Что такое трассировка запроса (distributed tracing)?

Ответ

Трассировка запроса (Distributed Tracing) — это метод мониторинга и диагностики, который позволяет отследить путь единого запроса через распределённую систему (микросервисы, базы данных, внешние API). Каждый шаг (операция) записывается как Span, а вся цепочка — как Trace.

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

  • Trace ID: Глобально уникальный идентификатор для всего запроса.
  • Span ID: Идентификатор отдельной операции в рамках Trace.
  • Context: Контекст (Trace ID, Span ID, флаги), который передаётся между сервисами (обычно через HTTP-заголовки, например, traceparent).

Практическая реализация в .NET (OpenTelemetry):

  1. Установка и настройка:

    // Установка пакетов: OpenTelemetry, OpenTelemetry.Extensions.Hosting,
    // OpenTelemetry.Instrumentation.AspNetCore, OpenTelemetry.Exporter.Console
    
    builder.Services.AddOpenTelemetry()
        .WithTracing(tracing =>
        {
            tracing.AddAspNetCoreInstrumentation() // Инструментирует входящие HTTP-запросы
                  .AddHttpClientInstrumentation() // Инструментирует исходящие HTTP-вызовы
                  .AddEntityFrameworkCoreInstrumentation() // Инструментирует запросы к БД
                  .AddConsoleExporter(); // Вывод трассировок в консоль (для отладки)
        });
  2. Ручное создание Span:

    using System.Diagnostics;
    
    // Создание Activity (реализация Span в .NET)
    using var activity = ActivitySource.StartActivity("ProcessPayment", ActivityKind.Internal);
    activity?.SetTag("payment.amount", amount);
    activity?.SetTag("payment.currency", "USD");
    // ... выполнение логики
    activity?.SetStatus(ActivityStatusCode.Ok);

Зачем это нужно?

  • Диагностика проблем: Быстро найти, в каком сервисе или запросе к БД произошла ошибка или задержка.
  • Анализ производительности: Визуализировать и измерить время выполнения каждого этапа запроса.
  • Понимание зависимостей: Автоматически строить карту взаимодействий между сервисами.

Ответ 18+ 🔞

Да ты посмотри, что эти умники придумали! Трассировка запросов в распределённых системах — это, по сути, как если бы ты, блядь, прикрутил к каждому своему запросу жучок с GPS и диктофоном, и этот жучок летает по всем твоим микросервисам, базам данных и прочей хуйне, записывая, кто, куда и как долго ебётся.

Суть, если по-простому:

  • Trace (След) — это вся история одного запроса от начала и до пизды. Как пачка сигарет за одну вечеринку.
  • Span (Шаг/Отрезок) — это каждая отдельная операция в этой истории. Один затяг, одна поездка за пивом, один звонок бывшей.
  • Trace ID — уникальный номер твоей вечеринки. Все шаги знают этот номер.
  • Context (Контекст) — это как та самая байка, которую один друг шепчет другому на ушко («Вася звонит Кате»), и так по цепочке. Передаётся между сервисами через заголовки HTTP, обычно traceparent.

Как это впихнуть в .NET (через OpenTelemetry):

  1. Ставим и настраиваем. Открываешь консоль и начинаешь впихивать пакеты, как будто последний раз. Потом в Program.cs пишешь вот эту простыню:

    builder.Services.AddOpenTelemetry()
        .WithTracing(tracing =>
        {
            tracing.AddAspNetCoreInstrumentation() // Ловит все входящие HTTP-запросы (кто стучится к тебе)
                  .AddHttpClientInstrumentation() // Ловит все исходящие HTTP-вызовы (куда ты стучишься сам)
                  .AddEntityFrameworkCoreInstrumentation() // Подслушивает, какую хуйню твой код спрашивает у базы данных
                  .AddConsoleExporter(); // А это чтобы всё это богатство вываливалось прямо в консоль, для отладки. В продакшене, ясное дело, меняешь на Jaeger или что там у тебя.
        });
  2. Если хочешь ручками пометить что-то. Допустим, у тебя есть особо хитрая операция «Оплатить заказ». Хочешь её выделить.

    using System.Diagnostics;
    
    // Создаёшь новый отрезок (Span) с именем
    using var activity = ActivitySource.StartActivity("ProcessPayment", ActivityKind.Internal);
    // Вешаешь на него метки, как ёлочные игрушки
    activity?.SetTag("payment.amount", amount);
    activity?.SetTag("payment.currency", "USD");
    // ... тут твоя бизнес-логика, которая может ебнуться...
    // В конце ставишь статус: ОК или, если всё пошло по пизде, Error.
    activity?.SetStatus(ActivityStatusCode.Ok);

А нахуя это всё, спрашивается?

  • Найти, где сломалось. Раньше, когда всё падало, ты полдня бегал между сервисами с криком «Это ты сломал? Нет, это ты!». Теперь просто открываешь трассировку и видишь: ага, UsersService на запросе к PaymentsService получил пизды, статус 500, и всё это за 2 секунды до конца.
  • Увидеть, кто тормозит. Визуально видно, что запрос к CatalogService летит 50 мс, а вот вызов какого-то старого легаси-API жрёт 5 секунд, как удав кролика. Прямо мишень для оптимизации.
  • Понять, кто с кем дружит. Система автоматически строит карту: «Ага, значит OrderService дергает PaymentService, InventoryService и EmailService». Удивляешься иногда неожиданным связям, ёпта.

Короче, вещь архиполезная. Без неё в микросервисах — как без фонаря в тёмной подворотне: шаришь руками, надеясь, что нащупаешь выключатель, а не что-то другое.