Этот пост — расшифровка моего выступления с нашей секции на РИТ++. Многие просили нас сделать текстовые версии докладов оттуда. Если вы были на конференции или смотрели видео, то не найдете ничего нового. А всем остальным — добро пожаловать под кат. Расскажу, как мы пришли к такой системе, как она работает и как мы планируем её обновлять.
Прошлое: схемы и планы
Как мы пришли к существующей системе мониторинга? Для того, чтобы ответить на этот вопрос, нужно отправиться в 2015 год. Вот как это выглядело тогда:
У нас существовало порядка 24 узлов, которые отвечали за мониторинг. Здесь есть целая пачка различных кронов, скриптов, демонов, которые что-то где-то каким-то образом мониторят, отправляют сообщения, выполняют функции. Мы подумали, что чем дальше, тем менее такая система будет жизнеспособна. Развивать её нет смысла: слишком громоздкая.
Мы решили выбрать те элементы мониторинга, которые мы оставим и будем развивать, и те, от каких откажемся. Их оказалось 19. Остались только графиты, агрегаторы и Grafana в качестве дашборда. Но как же будет выглядеть новая система? Вот так:
У нас есть хранилище метрик: это графиты, которые будут базироваться на быстрых SSD-дисках, это определенные агрегаторы для метрик. Далее — Grafana для вывода дашбордов и Moira в качестве алертинга. Также мы хотели разработать систему для поиска аномалий.
Стандарт: Мониторинг 2.0
Так выглядели планы в 2015. Но нам надо было готовить не только инфраструктуру и сам сервис, но и документацию к нему. Мы для себя разработали корпоративный стандарт, который назвали мониторинг 2.0. Какие требования были к системе?
- постоянная доступность;
- интервал хранения метрик = 10 секунд;
- структурированное хранение метрик и дашбордов;
- SLA > 99,99%
- cбор ивентовых метрик по UDP (!).
Нам был необходим UDP, так как у нас большой поток трафика и событий, которые генерируют метрики. Если их все сразу писать в графит, хранилище ляжет. Также мы выбрали префиксы первого уровня для всех метрик.
Каждый из префиксов носит какое-то свойство. Есть метрики по серверам, сетям, контейнерам, ресурсам, приложениям и так далее. Реализована четкая, строгая, типизированная фильтрация, где мы принимаем метрики первого уровня, а остальные просто дропаем. Вот как мы планировали эту систему в 2015 году. Что же в настоящем?
Настоящее: схема взаимодействия компонентов мониторинга
В первую очередь мы мониторим аппликейшны: наш PHP-код, приложения и микросервисы — словом, все, что пишут наши разработчики. Все аппликейшны через UDP отправляют метрики в агрегатор Brubeck (statsd, переписанный на С). Он оказался самым быстрым по итогам синтетических тестов. И он отправляет уже агрегированные метрики в Graphite через TCP.
У него есть такой тип метрик, как таймеры. Это очень удобная штука. Например, на каждое соединение пользователя с сервисом вы отправляете в Brubeck метрику с responce time. Пришел миллион ответов, а агрегатор выдал всего 10 метрик. У вас есть количество пришедших людей, максимальное, минимальное и среднее время отклика, медиана и 4 персентиля. Потом данные передаются в Graphite и мы видим их все вживую.
Также у нас есть агрегация для метрик по железу, софту, системных метрик и нашей старой системы мониторинга Munin (она работала у нас до 2015 года). Все это мы собираем через C'ишный демон CollectD (в него вшита целая пачка различных плагинов, он умеет опрашивать все ресурсы хостовой системы, на которой он установлен, просто укажите в конфигурации, куда писать данные) и пишем через него данные в Graphite. Также он поддерживает плагины python и shell скрипты, так что вы можете писать свои кастомные решения: CollectD будет собирать эти данные с локального или удаленного хоста (предположим, есть Curl) и отправлять их в Graphite.
Дальше все метрики, которые мы собрали, отправляем в Carbon-c-relay. Это решение Carbon Relay от Graphite, доработанное на C. Это роутер, который собирает в себе все метрики, которые мы отправляем с наших агрегаторов, и маршрутизирует их по нодам. Также на стадии маршрутизации он проверяет валидность метрик. Они, во-первых, должны соответствовать той схеме с префиксами, которую я показал раньше и, во-вторых, валидны для графита. Иначе они дропаются.
Потом Carbon-c-relay отправляет метрики в кластер Graphite. Мы используем в качестве основного хранилища метрик Carbon-cache, переписанные на Go. Go-carbon по причине его многопоточности намного превосходит по производительности Carbon-cache. Он принимает данные в себя и записывает их на диски с помощью пакета whisper (стандартный, написан на python). Для того, чтобы прочитать данные с наших хранилищ, мы используем Graphite API. Он работает намного быстрее, чем стандартный Graphite WEB. Что происходит с данными дальше?
Они идут в Grafana. В качестве основного источника данных мы используем наши кластеры графитов, плюс у нас есть Grafana как веб-интерфейс, для отображения метрик, построения дэшбордов. На каждый свой сервис разработчики заводят собственный дэшборд. Далее они строят по ним графики, на которых отображаются метрики, которые они пишут со своих приложений. Помимо Grafana у нас есть еще SLAM. Это питонячий демон, который считает SLA на основании данных из графита. Как я уже говорил, у нас есть несколько десятков микросервисов, у каждого из которых есть свои требования. С помощью SLAM мы ходим в документацию и сравниваем её с тем что есть в Graphite и сравниваем, насколько требования соответствуют доступности наших сервисов.
Идем далее: алертинг. Он организован с помощью сильной системы — Moira. Она независимая потому, что у нее под капотом — свой собственный Graphite. Разработана ребятами из СКБ контура, написана на python и Go, полностью опенсорсная. Moira получает в себя весь тот же поток, что уходит в графиты. Если по какой-то причине у вас умрет хранилище, то ваш алертинг будет работать.
Moira мы развернули в Kubernetes, в качестве основной базы данных она использует кластер Redis-серверов. В итоге получилась отказоустойчивая система. Она сравнивает поток метрик со списком триггеров: если в нем нет упоминаний, то дропает метрику. Так она способна переварить гигабайты метрик в минуту.
Еще мы к ней прикрутили корпоративный LDAP, с помощью которого каждый пользователь корпоративной системы может создавать для себя нотификации по существующим (или вновь созданным) триггерам. Так как Moira содержит в себе Graphite, она поддерживает все его функции. Поэтому вы сначала берете строчку и копируете ее в Grafana. Смотрите, как отображаются данные на графиках. А потом берете эту же строчку и копируете ее в Moira. Обвешиваете ее лимитами и получаете на выходе алертинг. Чтобы все это делать, вам не нужны никакие специфические знания. Moira умеет алертить по смс, email, в Jira, Slack… Также она поддерживает выполнение кастомных скриптов. Когда у нее случается триггер, и она подписана на кастомный скрипт или бинарник, она его запускает, и отдает на stdin этому бинарнику JSON. Соответственно, ваша программа должна его распарсить. Что вы будете с этим JSONом делать — решайте сами. Хотите — отправляйте в Telegram, хотите — открывайте таски в Jira, делайте что угодно.
У нас для алертинга используется ещё и собственная разработка — Imagotag. Мы адаптировали панель, которая применяется обычно для электронных ценников в магазинах, под наши задачи. Мы вывели на нее триггеры из Moira. Там указано, в каком они состоянии, когда произошли. Часть ребят из разработки отказались от уведомлений в Slack и в почту в пользу вот этой панельки.
Ну и так как мы — прогрессивная компания, то замониторили в этой системе еще и Kubernetes. Включили его в систему с помощью Heapster, который мы установили в кластер, он собирает данные и отправляет их в Graphite. В итоге схема выглядит вот так:
Компоненты мониторинга
Вот список ссылок на те компоненты, которые мы использовали для этой задачи. Все они — опенсорсные.
Graphite:
- go-carbon: http://ift.tt/2jZw0Cp
- whisper: http://ift.tt/2vVo5ka
- graphite-api: http://ift.tt/2vVdUMh
Carbon-c-relay:
http://ift.tt/2kK9FwW
Brubeck:
http://ift.tt/1BJUAiW
Collectd:
collectd.org
Moira:
http://ift.tt/2vVBw3u
Grafana:
grafana.com
Heapster:
http://ift.tt/2vVo3ZA
Статистика
И вот немного цифр о том, как система работает у нас.
Aggregator (brubeck)
Количество метрик: ~ 300 000 / sec
Интервал отправки метрик в Graphite: 30 sec
Использование ресурсов сервера: ~ 6% CPU (речь идет о полноценных серверах); ~ 1Gb DDR; ~ 3 Mbps LAN
Graphite (go-carbon)
Количество метрик: ~ 1 600 000 / min
Интервал обновления метрик: 30 sec
Схема хранения метрик: 30sec 35d, 5min 90d, 10min 365d (дает понимание что происходит с сервисом на продолжительном этапе времени)
Использование ресурсов сервера: ~ 10% CPU; ~ 20Gb DDR; ~ 30 Mbps LAN
Гибкость
Мы в Avito очень ценим в нашем сервисе мониторинга гибкость. Почему, он собственно получился таким? Во первых, его составные части взаимозаменяемы: как сами компоненты, так и их версии. Во-вторых — поддерживаемость. Так как весь проект построен на опенсорсе, вы сами можете править код, вносить изменения, можете реализовывать функции, недоступные из коробки. Используются достаточно распространенные стеки, в основном, Go и Python, поэтому это делается достаточно просто.
Вот пример реально возникшей проблемы. Метрика в Graphite — это файл. У него есть название. Имя файла = имя метрики. И есть путь до него. Названия файлов в Linux ограничены 255 символами. А у нас есть (в качестве “внутренних заказчиков”) ребята из отдела баз данных. Они нам говорят: “Мы хотим мониторить наши SQL-запросы. А они — не 255 символов, а 8 МБ каждый. Мы их хотим отображать в Grafana, видеть параметры по этому запросу, а еще лучше, мы хотим видеть топ таких запросов. Будет здорово, если он будет отображаться в реальном времени. А совсем круто было бы запихнуть их в алертинг”.
Пример SQL-запроса взят в качестве примера с сайта postgrespro.ru
Мы поднимаем сервер Redis и нашими Collectd-плагинами, которые ходят в Postgres и берут оттуда все данные, отправляем метрики в Graphite. Но заменяем имя метрики на хэши. Этот же хэш одновременно отправляем в Redis в качестве ключа, и весь SQL-запрос в качестве значения. Нам осталось сделать так, чтобы Grafana умела ходить в Redis и брать эту информацию. Мы открываем Graphite API, т.к. это основной интерфейс взаимодействия всех компонентов мониторинга с графитом, и вписываем туда новую функцию, которая называется aliasByHash() — от Grafana получаем имя метрики, и используем его в запросе к Redis как ключ, в ответ получаем значение ключа, которым является наш “SQL запрос”. Таким образом, мы вывели в Grafana отображение SQL-запроса, который по идее отобразить там было никак нельзя, вместе со статистикой по нему (calls, rows, total_time, ...).
Итоги
Доступность. Наш сервис мониторинга доступен 24 на 7 из любого аппликейшна и любого кода. Если у вас есть доступ к хранилищам, вы можете писать в сервис данные. Язык неважен, решения не важны. Вам нужно только знать как открыть сокет, закинуть туда метрику и закрыть сокет.
Надежность. Все компоненты отказоустойчивы и справляются с нашими нагрузками хорошо.
Низкий порог вхождения. Для того, чтобы пользоваться этой системой, вам не надо изучать языки программирования и запросы в Grafana. Просто открываете ваше приложение, вписываете в него сокет, который будет отправлять метрики в Graphite, закрываете его, открываете Grafana, создаете там дэшборды и смотрите на поведение ваших метрик, получая уведомления через Moira.
Самостоятельность. Все это можно делать самим, без использования DevOps. И это оверфича, потому что вы можете мониторить свой проект прямо сейчас, никого не надо просить — ни для начала работы, ни для изменений.
К чему мы стремимся?
Все перечисленное ниже — это не просто абстрактные мысли, а то, к чему сделаны хотя бы первые шаги.
- Детектор аномалий. Хотим запилить у себя сервис, который будет ходить в наши Graphite-хранилища и каждую метрику проверять по различным алгоритмам. Уже есть алгоритмы, которые мы хотим просматривать, есть данные, мы умеем с ними работать.
- Метаданные. У нас много сервисов, со временем они меняются, так же как и люди, которые с ними работают. Постоянно вести документацию вручную — не вариант. Поэтому сейчас в наши микросервисы встраиваются метаданные. Там прописано, кто его разработал, языки, с которыми он взаимодействует, требования по SLA, куда и кому высылать нотификации. При деплое сервиса все данные сущности создаются самостоятельно. В итоге вы получаете две ссылки — одна на триггеры, другая — на дэшборды в Grafana.
- Мониторинг в каждый дом. Мы считаем, что подобной системой должны пользоваться все разработчики. В этом случае вы всегда понимаете, где ваш трафик, что с ним происходит, где он падает, где у него слабые места. Если, допустим, придёт нечто и завалит ваш сервис, то вы узнаете об этом не во время звонка от менеджера, а от алерта, и сразу сможете открыть свежие логи и посмотреть, что там произошло.
- Высокая производительность. Наш проект постоянно растет, и сегодня в нём обрабатывается около 2 000 000 значений метрик в минуту. Год назад этот показатель составлял 500 000. А рост продолжается, и это значит, что через какое-то время Graphite (whisper) начнет очень сильно нагружать дисковую подсистему. Как я уже говорил, эта система мониторинга довольно универсальна за счёт взаимозаменяемости компонентов. Кто-то специально под Graphite обслуживает и постоянно расширяет свою инфраструктуру, но мы решили пойти другим путем: использовать ClickHouse в качестве хранилища наших метрик. Этот переход практически завершен, и совсем скоро я расскажу поподробнее, как это было сделано: какие были трудности и как они были преодолены, как проходил процесс миграции, опишу выбранные в качестве обвязки компоненты и их конфигурации.
Спасибо за внимание! Задавайте свои вопросы по теме, постараюсь ответить здесь или в следующих постах. Возможно, у кого-то есть опыт построения подобной системы мониторинга или перехода на Clickhouse в сходной ситуации — делитесь им в комментариях.
Комментарии (0)