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

от автора

Всем привет! Сегодня хочется поговорить про механизм распространения контекста трассировки в 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?

50% Да1
50% Слышал, но не использовал самостоятельно1
0% Нет, впервые услышал про него0

Проголосовали 2 пользователя. Воздержались 2 пользователя.

ссылка на оригинал статьи https://habr.com/ru/articles/901156/


Комментарии

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *