Never Fail Twice, или как построить мониторинговую систему с нуля
У нас было 2 виртуальные машины, 75 сайтов, десятки тысяч машин для мониторинга, тысячи метрик, две базы данных и одна очередь ActiveMQ, Python и целое множество библиотек всех сортов и расцветок, pandas, а также numpy, dash, flask, SQL Alchemy. Не то чтобы это был необходимый запас для системы, но если начал собирать компоненты, становится трудно остановиться. Единственное, что вызывало у меня опасение — это JavaScript. Ничто в мире не бывает более беспомощным, безответственным и порочным, чем JS зомби. Я знал, что рано или поздно мы перейдем и на эту дрянь.
Never fail twice is impossible, but failing on fails detection is even worse
Мониторинг распределенных систем — это довольно нетривиальная задача, где имеются свои подводные камни. С другой стороны, существует огромное количество как коммерческих, так и open-source решений для различных задач мониторинга. Под катом о том, почему нам не подошли открытые решения, что мы поняли из анализа успешных и неуспешных проектов по мониторингу, и почему было решено строить Yet Another Alert System. Это было увлекательное приключение, где на этапах от анализа данных на Python до финального решения и построения системы нам встретился почти весь Computer Science и даже немного матана.
Если рассмотреть проблему мониторинга в целом, то задачи делятся на две основные группы.
- Low Level Monitoring — мониторинг инфраструктуры по параметрам CPU, Disk usage networking, Java Heap Usage, GC cycles и так далее. Здесь все достаточно просто и существует много работающих готовых решений. Во многих случаях достаточно простых thresholds; в случае JVM, можно мониторить регулярность процессов по пилообразным графикам Java heap — увеличение частоты пиков может говорить о проблемах в управлении памятью и частых GC циклах.
- High Level Monitoring — когда в качестве метрик выбираются бизнес-индикаторы (BI) или Key Performance Indicators (KPI), такие как объемы пользовательских сессий, транзакций, платежей и т.д. Low level monitoring не может в адекватной мере отражать происходящее в системе на уровне бизнес логики.
Почему это сложно?
— Мониторинг сложной распределенной системы — уже само по себе инженерная проблема
— Различные проблемы ведут к неявным изменениям поведения системы
— Множество различных метрик одной системы
— Различные метрики коррелируют между собой
Я работаю Техническим Архитектором в большой компании, и у нас возникли проблемы со своевременным обнаружением проблем в продакшн системах.
Мы оперируем финансовыми транзакциями на крайне регулируемых рынках. Архитектура систем сервисно-ориентирована, компоненты имеют сложную бизнес-логику, есть разные варианты бэкенда для разных клиентов(B2B) компании.
Low level monitoring и тесты не покрывают целый ряд проблем
Во-первых, из-за высокой сложности продуктов и огромного количества настроек существуют ситуации, когда неправильные настройки приводят к деградации финансовых показателей, или скрытые баги в логике отражаются на общем функционале всей системы.
Во-вторых, есть специфические 3d-party интеграции для разных стран, и проблемы, возникающие у партнеров, начинают протекать к нам. Проблемы такого рода не ловятся low level monitoring; для их решения нужно мониторить ключевые индикаторы (KPI), сравнивать их со статистикой по системе и искать корреляции.
В компании было ранее внедрено решение от Hewlett Packard Service Health Analyzer, которое было (мягко говоря) неидеально. Судя по маркетинговому проспекту, это система, которая сама обучается и обеспечивает раннее обнаружение проблем (SHA can take data streams from multiple sources and apply advanced, predictive algorithms in order to alert to and diagnose potential problems before they occur). По факту же это был черный ящик, который невозможно настроить, со всеми проблемами нужно было обращаться в HP и ждать месяцами, пока инженеры поддержки сделают что-то, что тоже не будет работать, как нужно. А еще — ужасный пользовательский интерфейс, старая JVM экосистема (Java 6.0), и, что самое главное — большое число False Positives и (что еще хуже) False Negatives, то есть некоторые серьезные проблемы либо не обнаруживались, либо были пойманы намного позже чем следует, что выражалось во вполне конкретном финансовом убытке.
На рисунке видно, что гранулярность SHA 15 минут — это значит, что даже в случае проблем минимальное время реакции 15 минут…
То есть это все часто выглядело как то так…
На плечах гигантов
Множество компаний пытались построить свои мониторинг-системы. Это не всегда были success stories.
Etsy — Kale System
Etsy — это онлайн-маркетплэйс товаров ручной работы. Штаб-квартира компании находится в Нью-Йорке. Компания собирала более 250 000 различных метрик со своих серверов и пыталась искать аномалии в метриках, используя сложные математические алгоритмы. Но…
Знакомьтесь, Kale.
Одна из проблем Kale была в том, что система использовала множество различных технологических стеков. На схеме вы можете увидеть 4 различных стека, плюс 2 фреймворка. Чтобы развивать и поддерживать систему, требовались высококвалифицированные инженеры, знакомые с этими стеками. Поиск багов тоже требовал знаний во многих стеках.
Вторая проблема — это сам подход к мониторингу. Kale искал только аномалии. Но если у вас 250 000 метрик, то на каждый тик статистически будут наблюдаться сотни аномалий. Если расширять допустимые границы, то будут проскальзывать проблемы. Если сужать, то будет огромное количество ложных срабатываний.
Инженеры Etsy пытались бороться с числом False Positives, но после трех лет разработки проект закрыли. На эту тему есть хорошее видео от Andrew Clegg.
Я хочу выделить один слайд с этого видео.
Поиск аномалий — это больше, чем просто ловля outliers. Выбросы outliers будут наблюдаться на любых реальных данных продакшн в нормальном режиме функционирования. Не все аномалии должны вести к включению тревоги на всех уровнях.
Универсальный подход не подходит ни для чего; бесплатных ланчей не бывает. Вот почему решение SHA от HP не работает как надо, пытаясь быть универсальным инструментом.
И что интересно, возможные подходы к решению этих проблем.
Посылать Alert на аномалиях в бизнес и пользовательских метриках
Использовать другие метрики для Root Cause анализа.
Google SRE teams BorgMon
В книге Site Reliability Engineering есть целая глава, посвященная проблеме мониторинга продакшн систем Google. Если вкратце, то
- Гугл стремился к более простым и быстрым системам мониторинга с лучшими инструментами для post hoc анализа.
- Их целью было избегать магических систем, которые автоматически учат thresholds или автоматически ищут корреляции. Человек должен хорошо понимать, что происходит в системе и по каким правилам генерируются алерты.
- Правила для систем реагирования на проблемы сохранялись как можно простыми. Они давали очень быстрое время реагирования на простые, локализованные, серьезные аномалии.
- Человек должен хорошо понимать что происходит в системе и по каким правилам генерируются alerts.
На этих принципах Гугл построил успешную систему BorgMon.
Временные ряды
Временные ряды — это ряд данных, индексированный по времени. Если мы берем в качестве ряда экономические процессы (от производства шампанского до продаж в магазинах или онлайн-транзакций), то они обладают некоторыми общими свойствами: процессы регулярны, имеют некоторую периодичность, обычно имеют сезонные периоды и линии тренда. Используя эту информацию, можно упростить анализ.
Возьмем недельный ряд реальных данных по количеству транзакций. Мы можем видеть ярко выраженную регулярность (два пика — это перфоманс тесты). Есть дневная регулярность, плюс нарастание активности в пятницу и на выходных, после чего активность начинает спадать до следующих выходных.
На Хабре было много неплохих материалов по этой теме, например тут.
На Медиум есть мое введение в моделирование временных рядов (in english): Time series modelling.
В двух словах: каждое измерение содержит в себе компоненты сигнала и ошибки измерения/шума. Есть множество факторов, влияющих как на сами процессы, так и на собранные метрики.
Point = Sig + err
У нас есть модель, которая описывает сигнал. Если из измерения вычесть модель, то чем лучше модель будет схватывать сигнал, тем больше результат вычитания будет стремиться к стационарности или белому шуму — а это уже легко проверить.
В статье на Медиум я приводил примеры моделирования линейной и сегментированной регрессией.
Для системы мониторинга я выбрал моделирование с использованием скользящей статистики для среднего и разброса. Скользящее среднее по сути является low pass фильтром, который сглаживает шум и оставляет основные линии трендов. Вот наши данные по количеству транзакций на другой неделе, после прохода скользящего среднего с окном 60 минут (пики убраны):
Так же мы собираем и moving variancе для задания допустимых границ модели. В итоге у нас получается нечто от Сальвадора Дали.
Впишем сюда данные по другой неделе и сразу можем видеть outliers.
Теперь у нас есть все необходимое чтобы строить нашу Алерт Систему.
Важное отступление.
Опыт проекта Kale говорит об очень важном моменте. Алертинг — это не то же самое, что и поиск аномалий и outliers в метриках, поскольку, как уже говорилось, аномалии на единичных метриках будут всегда.
В действительности, у нас есть два логических уровня.
— Первый — это поиск аномалий в метриках и посылка нотификации о нарушении, если аномалия найдена. Это уровень эмиссии информации.
— Второй уровень — это компонент, получающий информацию о нарушениях и принимающий решения о том, является это критическим инцидентом или нет.
Таким образом действуем и мы, люди, когда исследуем проблему. Мы смотрим на что-либо, при обнаружении отклонений от нормы смотрим еще, и затем принимаем решение на основании наблюдений.
В начале проекта мы решили попробовать Kapacitor, поскольку в нем есть возможность определения пользовательских функций на Python. Но каждая функция сидит в отдельном процессе, что создало бы overhead для сотен и тысяч метрик. Из-за этой и некоторых других проблем от него решено было отказаться.
Для построения собственной системы в качестве основного стека был выбран Python, поскольку существует отличная экосистема для анализа данных, быстрые библиотеки (pandas, numpy и т.д.), отличная поддержка веб-решений. You name it.
Для меня это был первый большой проект, целиком и полностью выполненный на Python. Сам я пришел к Python из Java мира. Мне не хотелось множить зоопарк стеков для одной системы, что в конечном счете было вознаграждено.
Общая архитектура.
Система построена в виде набора слабо связанных компонентов или сервисов, которые крутятся в своих процессах на своих Python VM. Это естественно для общего логического разбиения (events emitter / rules engine) и дает другие плюсы.
Каждый компонент делает ограниченное количество специфических вещей. В дaльнейшем это позволит очень быстро расширять систему и добавлять новые пользовательские интерфейсы, не затрагивая основную логику и не боясь ее сломать. Между компонентами проведены достаточно четкие границы.
Распределенный deploy удобен, если нужно разместить агент локально к ближе к сайту, который он мониторит — или же можно аггрегировать вместе большое количество разных систем.
Коммуникация должна быть построена на базе сообщений, поскольку вся система должна быть асинхронной.
В качестве Message Queue я выбрал ActiveMQ, но при желании сменить, например, на RabbitMQ, проблем не возникнет, поскольку все компоненты общаются по стандартному протоколу STOMP.
Event streamer — это компонент, который хранит статистические модели, с некой периодичностью выбирает данные, и находит outliers. Он достаточно просто устрoен:
Worker — это основной рабочий юнит, который хранит одну модель одной метрики вместе с мета-информацией. Он состоит из дата коннектора и хендлера, которому передает данные. Хендлер тестирует их на статистической модели, и если обнаруживает нарушения, то передает их агенту, который посылает событие в очередь.
Workers полностью независимы друг от друга, каждый цикл выполняется через пул потоков. Поскольку большая часть времени тратится на I/O операции, то Global Interpreter Lock Python не сильно влияет на результат. Количество потоков ставится в конфиге; на текущей конфигурации оптимальным количеством оказалось 8 потоков.
Теперь перейдем к части Consumer. Компонент подписан на топик в очереди и при поступлении сообщения добавляет его в dictionary, ассоциированный с тиком и с каждым сайтом. Система хранит все события в некотором окне и при получении каждого нового сообщения удаляет самые старые. Чтобы не просматривать весь dictionary, ключи хранятся в Priority Queue, упорядоченной по timestamp.
Архитектурно компонент выглядит так.
Каждое сообщение отправляется в Rule Engine, и тут начинается самое интересное. В самом начале разработки я жестко задал правила в коде: когда одна метрика падает, а другая растет, то послать алерт. Но это решение не универсально и требует залезать в код для любого расширения. Поэтому нужен был какой-то язык, задающий правила. Тут пришлось вспоминать Абстрактные Синтаксические Деревья и дефинировать простой язык для описания правил.
Правила описываются в формате YAML, но можно использовать любой другой, достаточно добавить свой парсер. Правила задаются в виде регулярных выражений имен метрик или просто префиксов метрик. Speed — это скорость деградации метрик, об этом ниже.
При запуске компонента правила считываются и строится синтаксическое дерево. При получении каждого сообщения все события с этого сайта за один тик проверяются согласно заданным правилам, и если правило срабатывает, то генерируется алерт. Сработавших правил может быть несколько.
Если рассматривать динамику инцидентов, развивающихся во времени, то можно учитывать также скорость падения (уровень severity) и изменение скорости (прогноз изменения severity)
Скорость — это угловой коэффициент или дискретная производная, который подсчитывается для каждого нарушения. То же касается и акселерации, дискретной производной второго порядка.
Это значения можно задавать в правилах. Кумулятивные производные первых и вторых порядков могут учитываться в общей оценке инцидента.
Для хранения исторических событий используется база данных через ORM (SQL Alchemy)
Итак, у нас есть работающий бэкенд. Теперь необходим пользовательский интерфейс для управления системой и репортинг о метриках, сработавших на специфическом правиле.
Мне хотелось остаться по максимуму в одном стеке. И тут на помощь приходит Dash dash.plot.ly
Это фреймворк для визуализации данных надстройка над Flask и Plotly. Вы можете делать интерактивные веб-интерфейсы не за неделю-две, а за считанные часы. Ни строчки Javascript, легкая расширяемость, и на выходе — ReactJS-based WebUI и идеальная интеграция с Python.
Один из компонентов через WebUI управляет запуском, остановкой, сборкой Workers. Поскольку мы не знаем, в каком состоянии компонент, хранящий воркеры, закончились ли вычисления или нет, то все вызовы API идут через сообщения (Remote Procedures Call over Messaging).
Отдельный компонент строит on-demand динамический репорт, где собраны метрики, ассоциированные с этим алертом. При генерации алерта в одном из свойств генерируется ссылка на репорт. Также при желании возможно получать live stream.
Также сделана интеграция с Grafana и можно по ссылке перейти в Графану.
Остался еще один момент. Поскольку алерты вылетают каждый раз, когда срабатывают правила, то при долгом даунтайме каждую минуту будет генерироваться несколько алертов. Нужна система учета и дедупликации. У нас в компании уже была такая система и я интегрировался туда, но мой коллега нашел отличное альтернативное решение.
Знакомьтесь, Алерта.
The alerta monitoring system is a tool used to consolidate and de-duplicate alerts from multiple sources for quick ‘at-a-glance’ visualisation. With just one system you can monitor alerts from many other monitoring tools on a single screen.Алерта — это инструмент, используемый для консолидации и дедупликации сигналов из многих источников вместе с их визуализацией и учетом.
Это отличный инструмент, который очень легко интегрировался, в том числе и пользовательский интерфейс, который я встроил в WebUI системы. У Алерты есть готовые интеграции с Email, Slack, HipChat и так далее. Она может записывать Alerts обратно в influxDB для дальнейшей визуализации в Grafana.
С момента первого митинга до выхода в продакшн прошло чуть более 6 месяцев. Мы ловим большинство инцидентов на несколько минут раньше (в среднем 12-15), чем старая система алертинга HP. Кроме того, система обнаруживает и сигнализирует о некоторых проблемах, которые проскальзывали через другие системы мониторинга.
Сейчас мы нарабатываем статистику в проде, чтобы точнее настроить правила. Есть дальнейшие планы по развитию системы, например, попробовать смотреть на метрики через Convolution Networks (сторонний проект).
Это было очень интересное приключение, на котором встретились абстрактные синтаксические деревья, очереди с приоритетами, матан и много чего еще. На данный момент система состоит из 5 компонентов(microservices), вместе с Алертой — 7 компонентов. У компании есть намерение выпустить эту систему в open source, но для этого необходимо еще несколько месяцев.
Приключение которое все еще продолжается.