Ответ
Jaeger — это open-source система для распределенной трассировки (distributed tracing). Её основная задача — мониторинг и отладка транзакций в сложных микросервисных архитектурах.
Когда один запрос проходит через несколько сервисов, Jaeger позволяет отследить весь его путь, визуализировать зависимости между сервисами и находить узкие места (bottlenecks) или ошибки.
Интеграция с Go-приложениями
Современный стандарт для интеграции — это OpenTelemetry (OTel), который предоставляет API и SDK для инструментирования кода. Jaeger выступает в роли бэкенда (хранилища) для собранных трейсов.
Основные шаги интеграции:
-
Инициализация Трейсера: Настройка экспортера, который будет отправлять данные (трейсы) в Jaeger.
import ( "go.opentelemetry.io/otel" "go.opentelemetry.io/otel/exporters/jaeger" "go.opentelemetry.io/otel/sdk/resource" sdktrace "go.opentelemetry.io/otel/sdk/trace" semconv "go.opentelemetry.io/otel/semconv/v1.4.0" ) func initTracer(serviceName, jaegerEndpoint string) (*sdktrace.TracerProvider, error) { exporter, err := jaeger.New(jaeger.WithCollectorEndpoint(jaeger.WithEndpoint(jaegerEndpoint))) if err != nil { return nil, err } tp := sdktrace.NewTracerProvider( sdktrace.WithBatcher(exporter), sdktrace.WithResource(resource.NewWithAttributes( semconv.SchemaURL, semconv.ServiceNameKey.String(serviceName), )), ) otel.SetTracerProvider(tp) return tp, nil } -
Инструментирование кода: Создание "спанов" (spans), которые представляют собой отдельные операции (например, HTTP-запрос, вызов БД). Это часто делается автоматически с помощью middleware для веб-серверов (http, gRPC).
-
Контекстная Пропагация: Передача контекста трассировки (
trace id,span id) между сервисами. В Go это делается через стандартныйcontext.Context, который OTel обогащает нужными данными.
Мой опыт включает:
- Настройку сэмплинга для контроля объема отправляемых данных (например,
TraceIDRatioBased). - Использование middleware для автоматической трассировки входящих и исходящих HTTP/gRPC запросов.
- Анализ производительности и поиск причин задержек (latency) с помощью UI Jaeger.
- Отладку распределенных транзакций для понимания, на каком этапе и в каком сервисе произошла ошибка.
Ответ 18+ 🔞
А, Jaeger, блядь! Ну это такая штука, которая, когда у тебя куча микросервисов, как тараканы по кухне, бегают, позволяет понять, кто из них где и на каком этапе обосрался. Открыл глаза — овердохуища запросов, закрыл — нихуя не понятно, где тормозит. А Jaeger — он как рентген, сука, просвечивает всю эту хуйню.
Короче, что это за зверь? Это система для распределенной трассировки. Представь, что запрос — это пьяный мужик, который идет из бара в бар (из сервиса в сервис). Jaeger следит за ним, записывает, в каком баре он сколько времени проторчал, кого там обматерил и в каком именно кабаке его в итоге вырвало. Визуализирует весь путь, показывает, где узкое горлышко, а где просто всё легло, как после пятой стопки.
Как его в Go-приложение впихнуть, чтобы не сдохло?
Сейчас модно и правильно использовать OpenTelemetry (OTel). Это такой универсальный адаптер, а Jaeger — это уже конкретная дыра в стене (бэкенд), куда все логи летят.
Что делать, по шагам:
-
Трейсер инициализировать. Это как настроить скрытую камеру, которая будет всё снимать.
import ( "go.opentelemetry.io/otel" "go.opentelemetry.io/otel/exporters/jaeger" "go.opentelemetry.io/otel/sdk/resource" sdktrace "go.opentelemetry.io/otel/sdk/trace" semconv "go.opentelemetry.io/otel/semconv/v1.4.0" ) func initTracer(serviceName, jaegerEndpoint string) (*sdktrace.TracerProvider, error) { // Создаём экспортер, который будет пачками слать данные прямиком в Jaeger exporter, err := jaeger.New(jaeger.WithCollectorEndpoint(jaeger.WithEndpoint(jaegerEndpoint))) if err != nil { return nil, err // Если не вышло — ну, пизда, иди разбирайся } // А тут собираем нашего шпиона в кучу tp := sdktrace.NewTracerProvider( sdktrace.WithBatcher(exporter), // Чтобы не дёргать Jaeger по каждому чиху, пакуем в пачки sdktrace.WithResource(resource.NewWithAttributes( semconv.SchemaURL, semconv.ServiceNameKey.String(serviceName), // Подписываемся, кто мы такие, а то непонятно будет )), ) otel.SetTracerProvider(tp) // Говорим всей системе: "Вот, смотри, твой главный стукач — он" return tp, nil } -
Код нашпиговать. Но руками это делать — заебёшься. Поэтому берём готовые middleware для HTTP или gRPC. Они сами будут создавать "спаны" (это отдельные операции, типа "обработал запрос", "сходил в базу") — как кадры в кино про нашего пьяного мужика.
-
Контекст таскать. Самое важное, блядь! Когда запрос перепрыгивает из одного сервиса в другой, нужно не забыть передать контекст с
trace id. OpenTelemetry это обычно делает за тебя, через тот жеcontext.Context. Главное — не потерять его по дороге, а то вся трассировка разъёбется, как карточный домик.
Что я с этим делал, пока не поседел:
- Сэмплинг настраивал (
TraceIDRatioBased), чтобы Jaeger не захлебнулся от данных, если трафика — овердохуища. Записываем, например, каждый десятый запрос, а не все подряд. - Middleware цеплял на всё, что движется — входящие запросы, исходящие вызовы. Чтобы автоматически, мать его, трассировка работала.
- В UI Jaeger лазил и искал, какой же пидорас из сервисов тормозит всю малину. Находил эти долгие спаны и понимал — ага, вот тут он 2 секунды в Redis стучался, потому что пароль три раза ввёл неправильно.
- Отлаживал ебаную распределённую транзакцию, когда ошибка как чесотка — непонятно, где началась. Jaeger показывает всю цепочку, и видно, в каком именно сервисе всё пошло по пизде, а не гадать на кофейной гуще.
В общем, вещь, блядь, нужная. Когда сервисов больше трёх, без неё — как без рук и без мозгов одновременно.