Трассировка сервисов через очередь сообщений. OpenTelemetry, NATS

от автора

Это небольшой гайд о том, как обеспечить наблюдаемость в вашей событийно-ориентированной облачной системе.

Немного теории

Cloud application

Облачные технологии позволяют организациям создавать и запускать масштабируемые приложения в современных динамических окружениях, таких как общедоступные, частные и гибридные облака…

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

– Cloud Native Computing Foundation (CNCF)

Согласно этому определению, облачные приложения – больше, чем просто приложения, которые действуют в облаке. Они также масштабируемы, слабо связаны, устойчивы, управляемы и доступны для наблюдения. Можно сказать, что наличие этих «облачных атрибутов» позволяет называть системы облачными.

Event-driven architecture (EDA)

Архитектура, управляемая событиями, способствует слабой взаимозависимости между компонентами системы, что приводит к большей гибкости. Микросервисы могут масштабироваться независимо, выходить из строя без влияния на другие сервисы и снижать сложность рабочих процессов.

Observability

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

OpenTelemetry

OpenTelemetry, также известный как OTel, представляет собой открытый стандарт CNCF, который обеспечивает распределенную трассировку и сбор метрик из ваших приложений.

Trace Context

Это метаданные о span-ах в трассировке. Например, предположим, что служба A вызывает службу B, и вы хотите отследить вызов. В этом случае OpenTelemetry будет использовать Trace Context для захвата идентификатора трассировки и текущего span-а из службы A, чтобы span-ы, созданные в службе B, могли подключаться и добавляться к трассировке.

Это известно как распространение контекста.

Context Propagation

Распространение контекста — это основная концепция, которая обеспечивает распределенную трассировку. При распространении контекста span-ы могут быть соотнесены друг с другом и собраны в трассировку, независимо от того, где они генерируются. OpenTelemetry определяет распространение контекста с помощью двух субконцептов: Context и Propagation.

Context — это объект, который содержит информацию для отправляющей и принимающей служб, позволяющую соотнести один span с другим и связать его с трассировкой в целом.

Propagation — это механизм, который перемещает контекст между службами и процессами. Поступая таким образом, он собирает распределенную трассировку. Он сериализует или десериализует Span Context и предоставляет соответствующую информацию трассировки для распространения от одной службы к другой.

На практике

Хорошо, давайте создадим экземпляр propagation и инициализируем его:

import ( "go.opentelemetry.io/otel" "go.opentelemetry.io/otel/propagation" )  tc := propagation.TraceContext{} // Register the TraceContext propagator globally. otel.SetTextMapPropagator(tc)

В сервисе A, контекст которого мы хотим передать:

// GetTextMapPropagator returns the global TextMapPropagator. prop := otel.GetTextMapPropagator() // HeaderCarrier adapts http.Header to satisfy the TextMapCarrier interface. headers := make(propagation.HeaderCarrier) prop.Inject(ctx, headers)

после этого мы должны каким-то образом передать эти заголовки, в теле запроса, в заголовках запроса, все зависит от вашей реализации.

В сервисе B, в котором мы хотим получить контекст:

var headers propagation.HeaderCarrier // we get the headers and convert them to HeaderCarrier... prop := otel.GetTextMapPropagator() // Extract reads cross-cutting concerns from the carrier into a Context. ctx = prop.Extract(ctx, headers)

NATS

// Simple Async Subscriber nc.Subscribe("foo", func(m *nats.Msg) {     fmt.Printf("Received a message: %s\n", string(m.Data)) })  // Header represents the optional Header for a NATS message, // based on the implementation of http.Header. type Header map[string][]string  // Msg represents a message delivered by NATS. This structure is used // by Subscribers and PublishMsg(). type Msg struct { Header  Header }

нетрудно заметить что propagation.HeaderCarrier и nats.Header основан на реализации http.Header. Поэтому, чтобы скопировать данные из одной структуры в другую, я воспользовался реализацией http.Header.Clone()

В заключении

Всё достаточно просто, если немного почитать документацию. Было очень сложно подобрать русские термины, под устоявшиеся английские определения, поэтому большую часть я просто не стал переводить, что бы не ввести вас в заблуждение.

Полный код проекта доступен в моем репозитории — nats-tracing.

Так же при написании гайда я использовал открытые источники:


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


Комментарии

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

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