Это небольшой гайд о том, как обеспечить наблюдаемость в вашей событийно-ориентированной облачной системе.
Немного теории
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/
Добавить комментарий