Обо мне
Внедрял SIEM-системы и системы комплексного мониторинга. Подключал и парсил источники, нормализировал события различных доменов данных. Сейчас занимаюсь анализом данных, разработкой контентных модулей для решения задач мониторинга и информационной безопасности в компании VolgaBlob.
Вводная информация
Ознакомившись с опытом использования трассировок для мониторинга микросервисных архитектур от сообщества и крупных игроков в области Observability (DataDog):
Как мы делаем трейсинг в условиях тысяч сервисов и миллионов спанов в секунду
Как мы в Авито анализируем 5 миллионов трейсов и проводим архитектурный надзор
Мы решили реализовать инструменты анализа трассировок на нашем продукте Smart Monitor
, чтобы оценить правильность выбранного направления в разработке функциональных модулей и возможности системы.
Трассировки и стандарт OpenTelemetry
Стандарт хорошо задокументирован, включая основные компоненты и способы интеграции. Поэтому подробно останавливаться на этом не буду. Вот полезные ссылки:
Что такое Smart Monitor
Немного про сам продукт. Smart Monitor является платформой сбора и анализа данных. Ключевые возможности:
Движок pipeline like запросов
Набор компонентов и модулей для IT-мониторинга (РСМ, инвентаризация) и SIEM систем (UBA, Менеджер инцидентов)
Дашборды, задачи по расписанию
Подробнее описано на сайте. Под капотом хранилище OpenSearch
, плюс возможность использовать ClickHouse
(нативно), либо подключать иные базы данных через jdbc
.
Какие задачи мы хотели решить
Вдохновившись докладом Как мы в Авито анализируем 5 миллионов трейсов и проводим архитектурный надзор, было принято решение на базе платформы Smart Monitor
решить следующие задачи:
Сделать удобные визуальные инструменты анализа трассировок и сервисов — решается дашбордами и поисковым движком.
Построить карту инфраструктуры (провести инвентаризацию сервисов и операций, построить модель зависимостей) — решается модулем инвентаризации.
Сформировать инструмент поиска первопричин проблем — решается формированием ресурсно-сервисной модели микросервисов.
Предоставить возможность создания и управления жизненным циклом инцидентов — решается поисковым движком и модулем Менеджер инцидентов.
В результате, задачи архитектурного надзора хорошо соотносились с реализованными модулями, поэтому решения сводились к корректной трансформации данных для имеющихся модулей.
Как выглядит архитектура сбора
Здесь ничего нового не было изобретено. Использовался базовый механизм сбора данных в OpenSearch, предполагающий использование Otel Collector в связке с Data Prepper для формирования документов трассировок и их отправки в кластер OpenSearch
. В дальнейшем мы планируем отказаться от Data Prepper
в пользу собственного сервиса трансформации данных. Однако для первой версии модуля трассировок этого компонента достаточно.

Откуда данные
Для быстрого старта нам нужен был продукт, построенный на микросервисной архитектуре. Мы взяли демо-приложение, предоставляемое OpenTelemetry
. Сервис является магазином телескопического оборудования, который состоит из 19 сервисов. Сервисы разворачиваются в докере.


Как выглядят данные
В модуле использовалась два домена данных:
спаны трассировок
записи связей сервисов
Вот так выглядят события трассировки
{
"_index": "otel-v1-apm-span-000001",
"_type": "internal:otel-v1-apm-span:",
"_id": "efcf79b98104f430",
"_score": 0,
"_source": {
"droppedLinksCount": 0,
"traceId": "3371e97cd5b83f8e0619c919e39cda6a",
"instrumentationScope": {
"name": "go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc",
"version": "0.60.0"
},
"resource": {
"attributes": {
"process@runtime@name": "go",
"host@name": "1ad5865b3c7d",
"os@description": "Alpine Linux 3.21.3 (Linux 1ad5865b3c7d 6.10.14-linuxkit #1 SMP Sat May 17 08:28:57 UTC 2025 aarch64)",
"service@name": "product-catalog",
"telemetry@sdk@version": "1.35.0",
"process@executable@name": "product-catalog",
"telemetry@sdk@name": "opentelemetry",
"docker@cli@cobra@command_path": "docker compose",
"process@command_args": "[\"./product-catalog\"]",
"process@pid": 1,
"process@executable@path": "/usr/src/app/product-catalog",
"process@runtime@description": "go version go1.22.12 linux/arm64",
"os@type": "linux",
"telemetry@sdk@language": "go",
"process@owner": "root",
"process@runtime@version": "go1.22.12"
}
},
"kind": "SPAN_KIND_SERVER",
"traceGroupFields": {
"endTime": "2025-07-22T10:49:41.200Z",
"durationInNanos": 24000000,
"statusCode": 0
},
"droppedEventsCount": 0,
"traceGroup": "HTTP GET",
"serviceName": "product-catalog",
"parentSpanId": "3a803bed798334f4",
"spanId": "efcf79b98104f430",
"traceState": "",
"name": "oteldemo.ProductCatalogService/GetProduct",
"startTime": "2025-07-22T10:49:41.197253796Z",
"links": [],
"droppedAttributesCount": 0,
"durationInNanos": 57583,
"endTime": "2025-07-22T10:49:41.197311379Z",
"events": [
{
"name": "feature_flag",
"attributes": {
"feature_flag@variant": "on",
"feature_flag@key": "productCatalogFailure",
"feature_flag@provider_name": "flagd"
},
"time": "2025-07-22T10:49:41.197286712Z",
"droppedAttributesCount": 0
},
{
"name": "Error: Product Catalog Fail Feature Flag Enabled",
"attributes": {},
"time": "2025-07-22T10:49:41.197289962Z",
"droppedAttributesCount": 0
}
],
"status": {
"code": 2,
"message": "Error: Product Catalog Fail Feature Flag Enabled"
},
"span": {
"attributes": {
"rpc@method": "GetProduct",
"rpc@service": "oteldemo.ProductCatalogService",
"app@product@id": "OLJCESPC7Z",
"rpc@grpc@status_code": 13,
"rpc@system": "grpc"
}
}
}
}
А так связи между сервисами через операции
{
"_index": "otel-v1-apm-service-map",
"_type": "internal:otel-v1-apm-service-map:",
"_id": "KXDQMdubpQ73lmXPjpx3vA==",
"_score": 1,
"_source": {
"kind": "SPAN_KIND_CLIENT",
"traceGroupName": "HTTP GET",
"destination": {
"resource": "Currency/Convert",
"domain": "currency"
},
"serviceName": "frontend",
"hashId": "KXDQMdubpQ73lmXPjpx3vA==",
"target": null
}
}
События карты сервисов формируются компонентом Data Prepper
и являются результатом ETL-процесса трансформации данных трассировок. Сущность связи интерпретируется вот так:
сервис
frontend
вызывает ресурсCurrency/Convert
у сервисаcurrency
.
Дашборды для анализа трассировок
Первый этап — формирование дашбордов мониторинга и анализа трассировок и сервисов. Структура дашбордов и переходов между ними построена по логике от общего к частному.

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


На дашборде детализации трассировки есть пара интересных моментов:
-
Диаграмму вызовов мы позаимствовали у
OpenSearch Dashboards
, реализацию собственной диаграммы отложили на следующий релиз модуля.Диаграмма вызовов -
Граф вызовов очень приятный (написали сами) и визуализирует маршруты с ошибками в контексте трассировки.
Карта маршрутов трассировки
Остальные дашборды.



Визуализации строятся на движке поиска, который использует pipeline like язык.

$service$
и $resource$
— это токены, значения для которых формируются из фильтров на дашборде.
Инвентаризация сервисов
Механизм инвентаризации простой:
Из
otel-v1-apm-service-map
формируем измерения (сервисы, ресурсы) и связи.Используем измерения и связи в модуле инвентаризации.
В результате имеем два типа актива, связанные между собой.


Это позволяет построить маршруты между сервисами через ресурсы.

И получить полную карту маршрутов.

Модель здоровья микросервисов
Модель здоровья строиться на трех основных показателях сервисов:
Количество операций в единицу времени — деградирует при отсутствии операций.
Количество ошибок операций — деградирует при росте ошибок.
Продолжительность операций — деградирует при увеличении задержек.
Вручную формировать модель здоровья для продукта, в котором более 1000 сервисов, невозможно. Поэтому формирование модели выполняется скриптом, который использует:
Шаблоны метрик (для каждого сервиса всегда доступны три метрики).
Сформированные связи между сервисами в рамках инвентаризации.
Вот так выглядит шаблон метрики - используется jinja template
{
"title": "Ошибки операций",
"description": "Количество спанов, выполненных с ошибкой",
"source": {
"search": {
"query": "source otel-v1-apm-span\n| search serviceName=\"{{ service }}\"\n| peval is_error_span = if(status.code > 1, 1, 0)\n| aggs sum(is_error_span) as errors by name",
"time_field": "startTime",
"earliest": "now-4m",
"latest": "now"
},
"schedule": {
"cron": {
"expression": "* * * * *",
"timezone": "Europe/Moscow",
"schedule_delay": 0
}
},
"lock_duration_seconds": 10,
"calculation_field_name": "errors"
},
"type": "NUMBER",
"units": "ед",
"drilldown": null,
"thresholds": {
"static": {
"base_severity": "NORMAL",
"ranges": [
{
"above": 0,
"severity": "NORMAL"
},
{
"above": 2,
"severity": "HIGH"
}
]
}
},
"split_by_entity_params": {
"enabled": true,
"entity_key_field_name": "name",
"aggregation_function": "MAX",
"entity_thresholds": [
{
"entity_pattern": "*",
"thresholds": {
"static": {
"base_severity": "MEDIUM",
"ranges": [
{
"above": 0,
"severity": "NORMAL"
},
{
"above": 2,
"severity": "HIGH"
}
]
}
}
}
]
}
}
Скрипт запускается по расписанию и не является частью системы. Он использует API для создания сервисов и метрик в нотации РСМ и запускается отдельной службой.
В результате, мы получаем модель здоровья.


Помимо прямой зависимости от собственных метрик, на состояние сервиса влияет состояние дочерних сервисов.

Регистрация инцидентов
Завершает упаковку модуля анализа трассировок правило для регистрации инцидентов. Мы сформировали правило, срабатывающее при наличии ошибок в распределённой трассировке. Оно выявляет ошибки в трассировке относительного родительского сервиса — того, с которого началась обработка запроса.

В рамках данного правила формируется следующий инцидент.

Выводы
Итак, мы решили задачу прикладного применения современных стандартов мониторинга в нашей платформе и упаковали объекты знаний и конфигурации в контентный модуль. Компоненты продукта решают задачи построения системы мониторинга состояния микросервисов на базе трассировок OpenTelementry
. Но сделана только база, адаптировать решение придется на каждой инсталляции. Помимо этого остается ряд вопросов, которые необходимо решить:
Операции агрегации спанов трассировок на
OpenSearch
выполняются медленно при больших объемах данных. Возможности для оптимизации такого рода появились только в 3.0. В частности — Star-tree index. Но, кажется, вариант использоватьClickHouse
для процессинга трассировок выглядит более удачным. Такие задачи уже решались и не раз. Поэтому смотрим в эту сторону.Ввиду количества микросервисов в продуктах и значимой разнице в профилях нагрузки (количество запросов, длительность обработки, сложность операций), метрики должны рассчитываться адаптивно. Использования заданных порогов для метрик приведет только к большому количеству false-positive состояний. Доверия к такой системе не будет.
Веса между сервисами в рамках ресурсно-сервисной модели должны рассчитываться динамически, используя коэффициент GB (Graceful Degradation).
От использования
Data Prepper
и визуализацииOpenSearch Dashboards
нужно отказываться. Качество этих open-source решений не соответствует качеству продукта.Большие инсталляции содержат очень много сервисов (тысячи), строить модели и инвентаризировать такие инсталляции нужно с применением дополнительных логических фильтров. Делать множество моделей по доменам продукта, критичности для бизнеса и пользователей.
На этом все, если у вас есть опыт работы с трассировками и альтернативными решениями для их анализа — буду рад обменяться опытом в комментариях.