Одна платформа, чтобы мониторить всех: как мы осуществляем трассировку, работаем с логами и метриками во всей экосистеме
Привет, Хабр! Меня зовут Филипп Бочаров, я руководитель направления мониторинга и наблюдаемости в МТС Диджитал. В нашей экосистеме более 400 продуктов, которые активно взаимодействуют между собой. Для такого обширного ландшафта мы используем единую платформу мониторинга: она устанавливает общие стандарты, дает возможность легкого перехода на новый стек и снижает трудозатраты на типовые операции.
В этой статье расскажу, как мы с ее помощью осуществляем распределенную трассировку, сбор и хранение метрик и централизованное логирование для всех продуктов МТС. И покажу, что в нашем случае платформа — единственное работающее решение.
Распределенная трассировка
Это первый сервис, который у нас появился. Реализовать его без платформы достаточно сложно. Ниже расскажу, почему.
Предположим, у нас есть подписка на некую услугу. Ее оформление выглядит как взаимодействие нескольких сервисов: один общается с пользователем, второй сохраняет информацию в базу и так далее.
Если произошел сбой и продление подписки не проходит, мы начинаем последовательно смотреть работу разных сервисов. Например, мы видим, что причина во взаимодействии между А и Б, но Б не виноват. Он работает с В, который постоянно выдает ошибку.
Распределенная трассировка как раз позволяет SRE-специалистам и сотрудникам эксплуатации видеть схему взаимодействия сервисов и находить причины проблем. Трассировка представляет собой древовидную структуру (трейс), которая состоит из отдельных шагов (спан). Каждый спан — это входящий или исходящий запрос к системе или шаг алгоритма:
В этом примере первый шаг — get-запрос к методу dispatch. Мы видим, какой сервис стартовал trace, и знаем, сколько времени каждый шаг занимал и есть ли там ошибка. В последнем спане у нас что-то произошло с Redis
Для локализации проблемы нам нужно получить end-to-end-трейс во всей экосистеме: от старта запроса до завершения обработки. Но создать его без платформы почти невозможно.
Между сервисами передается контекст трассировки — уникальный идентификатор запроса. Он генерируется первым сервисом и отправляется дальше по цепочке.
Есть разные форматы передачи контекста, например:
OpenZipkin описывает несколько B3-хедеров, каждый из которых содержит свой идентификатор:
Мы используем Jaeger — в нем ID трейса и спана передаются одной строкой:
W3C — новый формат на замену этому зоопарку:
Единого трейса не получится, если в ландшафте будут разные системы трассировки. Они передают контекст в разных форматах и не понимают друг друга. Тут нужен общий стандарт. Мы используем два совместимых — старый OpenTracing и новый OpenTelemetry — и потихоньку переводим пользователей на второй.
Чтобы собирать end-to-end-трейсы от разных продуктов в единую структуру, нужны общие стандарты и хранилище, куда будут складываться все спаны. Именно поэтому распределенная трассировка у нас реализована в составе платформы, а не у каждого отдельного продукта.
Чтобы любой инженер мог правильно пользоваться трассировкой, мы установили единые best practices для всех команд. Например, описываем теги, их название и содержимое:
Например, тег Product ID показывает, откуда пришел трейс
Архитектура распределенной трассировки
Слева находится продукт, инструментированный SDK OpenTelemetry. А справа — backend нашей платформы
Трассировка передается по HTTP или по gRPC, в зависимости от того, как было инструментировано приложение. На бэкенде она поступает либо в Jaeger-коллектор, либо в OpenTelemetry-коллектор и складывается в Kafka. Отсюда есть две ветки:
Верхняя ведет в операционное хранилище. Jaeger вычитывает трассировку и переносит ее в кластер ClickHouse, а по Jaeger UI можно искать трейсы и смотреть их структуру. Эта ветка используется инженерами эксплуатации для операционной работы, например устранения аварий.
Нижняя предназначена для аналитики. Наш самописный сервис Stream Metrics перебирает и идентифицирует спаны, считает по ним различные счетчики и метрики. Метрики отправляются в кластер Victoria Metrics и визуализируются в Grafana. Так мы легко можем посчитать время работы и результативность тех или иных методов, количество ошибок.
Если трассировку мы храним две недели, то метрики — один год. Это позволяет создавать аналитические запросы и видеть длительные тренды, например деградацию времени работы методов API с ростом нагрузки или новыми релизами.
Когда мы начинали создавать платформу, то все трейсы лежали в Elasticsearch. Мы уперлись в ее производительность, потратили много времени на тюнинг и решили искать хранилище другого типа. Провели R&D и поняли, что с ClickHouse все работает гораздо быстрее.
После перехода на ClickHouse у нас на 20% увеличилась скорость поиска, а хранение стало в несколько раз компактнее. А самое главное, что схема начала линейно масштабироваться: с прибавлением нод в кластере ClickHouse кратно росла производительность. Подробнее об этом переходе — в расшифровке моего доклада с HighLoad++.
Самый важный бонус — возможность аналитических запросов. У ClickHouse практически стандартный язык SQL, и можно довольно быстро научить коллег анализировать трассировку.
Работа с метриками
Если каждый из 400 продуктов начнет собирать метрики по-своему, то единого хранилища и аналитики не получится: у них будут разные названия и разрезы. Чтобы этого избежать, мы стандартизировали агент.
Любая виртуальная машина, которая создается на ландшафте, уже содержит агент Telegraf. Он предназначен для сбора базовых метрик с операционной системы и типового ПО на ней. Разные input-плагины telegraf позволяют собирать метрики с огромного количества приложений: всех популярных баз данных, веб-серверов и так далее.
Каждый агент Telegraf подключен к нашей платформе. Мы можем удаленно запускать те или иные плагины и собирать с хоста нужные нам метрики:
На этом примере у нас есть два хоста: Linux с Postgres и Windows с Redis. Для всех хостов, которые подпадают под маску PG*, правило запускает плагин inputs.postgresql. Агенты Telegraf на всех хостах, которые попали под маску, включают этот плагин и начинают собирать метрики Postgres
Агент Telegraf на каждом хосте обновляет конфигурацию из централизованного хранилища на нашей платформе. Он получает правила, по которым включает нужные плагины.
Такая стандартизация дает нам важные бонусы:
Экономится время: агент уже встроен в образ операционной системы и ставится вместе с ней.
Метрики выглядят абсолютно одинаково, так как собираются одним агентом с типовыми плагинами.
Снижаются трудозатраты за счет прединтеграции. У нас есть своя платформа разработки, и она предоставляет набор готовых сервисов — например, Managed Kubernetes, DBaaS или Kafka-as-a-Service. При их использовании любой продукт получает типовой дашборд и может мониторить там свои метрики.
Стандартизируются алерты, так как для всех общий набор метрик и формулы расчета.
Архитектура сбора метрик
Кроме агента Telegraf мы поддерживаем vmagent (часть стека Victoria Metrics) и Prometheus exporter. Полученные тем или иным способом метрики уходят на бэкенд нашей платформы, где стоит «Prometheus на стероидах» — Victoria Metrics.
Она представляет собой кластерное решение с компонентами, которые отдельно отвечают за вставку (vminsert), хранение (vmstorage) и чтение метрик (vmselect). Такая структура позволяет легко масштабироваться в зависимости от профиля нагрузки. Данные мы визуализируем в Grafana, в качестве промежуточного хранилища используется Kafka.
К Victoria Metrics через Telegraf подключено более 300 продуктов и 50 тысяч хостов. От них нам летит почти 12 млн сэмплов в секунду — это действительно впечатляет. Подробнее об архитектуре метрик я рассказывал на Saint Highload++.
Работа с логами
Когда мы запустили сервис логирования, то сначала стандартизировали протокол доставки. Используем самое простое решение — JSON по HTTP. Мы добавили дополнительные поля:
Обязательные: идентификатор продукта потребителя, дату, уровень логирования (LogLevel).
Рекомендуемые: например, идентификаторы для связи с распределенной трассировкой (trace ID и span ID).
Так как эти поля заранее описаны, мы можем настроить переход между разными типами телеметрии. Зная, что вот в это поле придет код trace ID, мы делаем его в Kibana ссылкой и прямо оттуда переходим в Jaeger.
Архитектура сервиса логирования
Сейчас мы строим распределенную архитектуру и разносим сервис логирования по разным ЦОДам (юнитам). В каждом ЦОДе находится кластер OpenSearch 10 на 10: 10 hot node и 10 warm node для горячего и теплого хранилища. Благодаря GeoDNS запись идет в ближайший к продукту ЦОД: логи по HTTP пишутся на определенное доменное имя и резолвятся на IP-адрес нужного ЦОДа.
Таким образом нагрузка распределяется, а чтение выполняется с помощью отдельного поискового кластера OpenSearch. Он через cross-cluster search соединен с другими кластерами OpenSearch в каждом ЦОДе. Для пользователей это выглядит как некая облачная структура: пользователь обращается к поисковому кластеру, а тот сам ищет нужный ЦОД. Они видят в OpenSearch Dashboard свои логи, но не знают, где конкретно те лежат.
Почему платформа в нашем случае — единственное решение
Многое из того, что я описал выше, просто не получится реализовать иначе, чем через платформу. Благодаря ей мы:
Снижаем трудозатраты продуктовых команд. Все метрики собраны в единую структуру и позволяют настраивать типовые правила мониторинга.
Можем незаметно для пользователей переходить на другой стек или технологию (например, в связи с импортозамещением или устареванием стека). Детали реализации скрыты от продукта внутри платформы, а интеграция идет по открытым протоколам, например OpenTelemetry.
Ускоряем подключение продуктов к платформе. Прединтеграция с внутренним облаком и ключевыми технологическими сервисами экосистемы позволяет получить большую часть мониторинга продукта «из коробки».
На этом у меня все. Если у вас появились вопросы по работе нашей платформы, готов ответить на них в комментариях.