Как стать автором
Обновить

Коротко и по делу про механизм propagation в OpenTelemetry

Уровень сложностиПростой
Время на прочтение3 мин
Количество просмотров1.9K

Всем привет! Сегодня хочется поговорить про механизм распространения контекста трассировки в OpenTelemetry. Разберем, как он работает, и посмотрим простой пример на Go. Всё — коротко и по делу!

Меня зовут Носорев Константин, я backend-разработчик в Яндекс Пей, автор канала "Константин про IT" и просто любознательный инженер.

OpenTelemetry уже давно стал стандартом для построения системы наблюдаемости (observability) в микросервисной архитектуре. Начнем с небольшого ликбеза, чтобы проще воспринимать материал.

Трассировка строится вокруг двух базовых понятий: trace и span.

  • Trace — это путь, который проходит запрос.

  • Span — это отдельный шаг в обработке запроса.

Один trace начинается с корневого span'а, который порождает дочерние span'ы. Все они образуют дерево вызовов, которое можно визуализировать в системах наблюдаемости.

Пример трейсов
Пример трейсов

У каждого trace и span есть соответствующие идентификаторы — trace_id и span_id. Когда мы создаем первый span, библиотека OpenTelemetry (далее будем говорить просто otel) генерирует эти идентификаторы, сохраняет их в памяти и затем экспортирует во внешнюю систему. Для понимания принципа работы нам достаточно знать, что вся информация о трассировках каким-то образом доходит до системы мониторинга.

Каждый новый span привязан к trace'у и, при наличии, к родительскому span'у — так формируется полная цепочка.

Когда мы остаемся в рамках одного приложения или потока, сохранить эту цепочку довольно просто. Но сила трассировки именно в том, что она позволяет связать действия, происходящие между сервисами, в единую историю.

Возникает вопрос: как otel передает идентификаторы между сервисами?

Для этого используется механизм Propagation. Он позволяет передавать контекст трассировки с помощью двух компонентов:

  • traceparent — обязательный заголовок, содержащий версию протокола, trace_id и span_id родителя;

  • tracestate — дополнительная информация, специфичная для вендора.

В случае HTTP-запросов эти значения передаются в заголовках. В большинстве случаев вам не нужно делать это вручную — otel предоставляет готовые инструменты для встраивания заголовков в HTTP-запросы. Рекомендую изучить библиотеку otel для вашего языка.

Теперь рассмотрим более интересный случай — передачу контекста в фоновые процессы, например, при реализации асинхронных API. В этом случае контекст нужно передавать через внешние системы: очереди сообщений, БД и т.д.

Пример: передача контекста через БД

Представим, что у нас есть сервис с двумя обработчиками:

  • POST-ручка сохраняет задачу в БД и возвращает task_id;

  • GET-ручка по task_id возвращает статус задачи;

  • Плюс есть фоновый воркер, который обрабатывает задачи и обновляет статус в БД.

Мы хотим получить сквозной trace, в котором будет видно всё: создание задачи, её обработку и обновление.

Для этого нужно передать trace-контекст от POST-запроса в воркер. Сохраним его в БД вместе с задачей. Otel предоставляет для этого TextMapPropagator — механизм, позволяющий сериализовать контекст в словарь (map[string]string), который можно, например, сохранить в поле jsonb в PostgreSQL.

Такой объект будем называть traceContext.

Код на Go:

package trace

import (
	"context"
	"go.opentelemetry.io/otel/propagation"
)
type TraceContext struct {
	Trace propagation.MapCarrier `json:"trace"`
}

func Inject(ctx context.Context) TraceContext{
	md := propagation.MapCarrier{}
	traceContext := propagation.TraceContext{}
	traceContext.Inject(ctx, md)
	return TraceContext{Trace: md}
}

func Extract(ctx context.Context, tc TraceContext) context.Context {
	traceContext := propagation.TraceContext{}
	ctx = traceContext.Extract(ctx, tc.Trace)
	return ctx
}

Мы опустили часть с сохранением traceContext в БД — оставим это в качестве домашнего задания ;)

На стороне воркера всё просто: извлекаем traceContext из БД, восстанавливаем контекст, создаем новый span, и он автоматически становится частью исходного trace'а.

Резюме

Сегодня мы познакомились с механизмом propagation в OpenTelemetry и рассмотрели практический пример на Go. Этот механизм позволяет обеспечить связность трассировки даже при передаче контекста через внешние хранилища.


На этом всё! Если вам зашёл такой формат — ставьте лайк, делитесь мнением в комментариях и подписывайтесь на мой телеграм-канал Константин про IT. Если будет интерес, продолжу рассказывать про полезные инструменты разработки — коротко и по делу!

Только зарегистрированные пользователи могут участвовать в опросе. Войдите, пожалуйста.
Используешь механизм Propagation?
33.33% Да4
50% Слышал, но не использовал самостоятельно6
16.67% Нет, впервые услышал про него2
Проголосовали 12 пользователей. Воздержались 2 пользователя.
Теги:
Хабы:
-2
Комментарии3

Публикации

Работа

Go разработчик
78 вакансий

Ближайшие события