
В инфраструктуре Яндекса работают тысячи микросервисов, которые каждую секунду генерируют миллионы временных рядов — метрик. Это могут быть количества запросов, принятых микросервисом, текущая загрузка процессора на сервере и так далее. Все эти метрики хранятся и обрабатываются в общеяндексовой системе Monium. Эта система предназначена для хранения и обработки метрик и логов.
Для контроля за метриками в системе Monium существует механизм алертов — небольших микропрограмм, которые анализируют временные ряды и, если значения ряда выходят за разрешённые пороги, отправляют дежурным сообщения об инциденте. Проблема в том, что для многих рядов сложно заранее определить разрешённые пороги. А для некоторых рядов сделать это попросту невозможно, потому что нормальное поведение ряда сильно зависит от дня недели, времени суток, сезона и ещё десятка факторов, которые сложно учесть. В результате контролировать такие временные ряды было довольно нетривиальной задачей.
Мы в команде ML Research в Городских сервисах Яндекса давно поняли, что руками такие системы не масштабируются. Нужна автоматика, которая сама фиксирует нормальное поведение метрики и засекает отклонения. Звучит как задача для тяжёлого ML: трансформеров, автоэнкодеров — целого арсенала алгоритмов. Однако на бенчмарках мы доказали, что простая авторегрессия обгоняет сложные модели. Чтобы она заработала в продакшене, нам пришлось решить несколько нетривиальных инженерных задач.
Давайте вместе пройдём этот путь от «Почему пороги не работают?» до рабочей системы детекции аномалий в общеяндексовой системе Monium и наблюдения за 800+ городами в Яндекс Такси с бенчмарками и конкретными цифрами. С рассказом мне помогут Дима Успенский @black_chick, Никита Лазарев @vaaven и Андрей Матвеев @Ra1ze505, которые проделали этот путь.
Зачем нужны временные ряды
Все метрики — от процента ошибок API и потребления памяти до времени ответа сервисов и конверсии — можно представить как временные ряды. Это база современного мониторинга и наблюдаемости систем. Вот, например, «количество заказов в минуту» в сервисе доставки. В обычный день график показывает предсказуемые паттерны: утренний рост активности, пики в обеденное время и спад к вечеру, но однажды в 14:30 заказы падают с 800 до 200 без видимых причин. Это и есть аномалия, то есть значительное отклонение метрики от ожидаемого поведения.

Как правило, аномалии говорят о надвигающихся проблемах. Так, резкий скачок времени ответа может предвещать перегрузку сервиса, необычное падение конверсии — намекать на поломку в UI, а повышенное потребление памяти — указывать на утечку. Чем быстрее заметишь такие отклонения, тем меньше финансовых потерь и репутационного ущерба понесёт компания.

Обычно для мониторинга используют пороговые алерты, работающие по принципу «если RPS выше 1000 — отправить уведомление дежурному». Однако почему именно 1000 — правильный порог? А как учесть, что нормальный RPS в понедельник утром отличается от пятничного вечера? Что делать, если поведение метрики меняется?
Если у вас пара временных рядов, ещё можно корректировать пороги срабатывания вручную по необходимости, но в масштабной инфраструктуре это фактически нереально. Здесь нужна автоматическая детекция аномалий, где система анализирует исторические данные, выучивает нормальные паттерны поведения метрики и автоматически определяет, когда обнаружит статистически значимое отклонение от выученной нормы.
Многообразие детекторов аномалий
Чтобы выбрать оптимальный алгоритм, мы изучили доступные решения и разобрали основные семейства детекторов аномалий:
Prediction‑based/forecasting‑based‑алгоритмы предсказывают «норму» на следующий шаг (или окно), а аномалию считают по остатку (residual). К ним относятся, например, AR/ARIMA, ETS и регрессии. Такие алгоритмы работают быстро, результаты, как правило, интерпретируемые, но их предсказания легко ломаются о сезонность и сдвиги режима. Надо отдельно определять, когда модель должна адаптироваться к изменениям в ряду, а когда отмечать их как аномалию.
Reconstruction‑based‑подход подразумевает обучение модели восстановлению нормальных окон временного ряда. Алерт срабатывает, если алгоритм обнаруживает сильное расхождение между реконструкцией и фактическими данными. Здесь часто используются автоэнкодеры и VAE. Это достаточно тяжёлые модели, и результаты их работы труднее интерпретировать, зато они хорошо ловят сложные формы на графиках.
Distance‑based/discord‑based‑алгоритмы считают аномалиями редкие подстроки и подпоследовательности, далёкие от ближайших соседей. Они очень сильны в поиске необычных форм, но дороги в массовом использовании и не всегда хорошо работают в реальном времени.
Grammar‑based/encoding‑based‑подход довольно сложен с инженерной точки зрения, зато ловит аномалии на уровне паттернов, не конкретных значений. Подход основан на символьном кодировании ряда, грамматики и последующем сжатии. Редкие и плохо сжимаемые фрагменты временного ряда считаются аномальными.
Классические статистические подходы: robust z‑score, ESD‑тесты, STL‑декомпозиции — часто самый практичный старт и хороший baseline.

К сожалению, в этом списке нет ни одного универсального решения, поэтому крупные компании, которым нужен мониторинг, как правило, делают свои детекторы либо используют различные сочетания алгоритмов и собирают вокруг них платформы.
Twitter/X развивает S‑H‑ESD и пакет AnomalyDetection (пост, GitHub), которые базируются на тесте Граббса и заточены под сезонные ряды.
Meta (признана в России экстремистской организацией) делает аддитивную модель Prophet с ручным заданием праздников и точек перелома (сайт, GitHub).
Datadog описывает в документации три алгоритма: сезонную декомпозицию, ARIMA, running quantiles (пост).
В Anodot выбрали быстрое экспоненциальное сглаживание с тройной сезонностью (статья).
Оценка качества детекторов
Чтобы сделать обоснованный выбор, мы решили ориентироваться на результаты тестов алгоритмов на базе временных рядов с заранее размеченными аномалиями и произвольной сеткой, разной длиной и пропусками. Мы использовали шесть публичных датасетов, всего 834 ряда:
Датасет |
Описание |
Рядов |
NAB |
Метрики AWS, клики, трафик и упоминания компаний в Twitter |
10 |
Yahoo |
Датасет от Yahoo Labs, состоящий из реальных и синтетических временных рядов на основе production‑трафика к системам Yahoo |
367 |
AIOPS |
Показатели производительности, отражающие масштаб, качество веб‑сервисов и состояние здоровья машин |
29 |
WSD |
Датасет веб‑сервисов, содержащий реальные KPI, собранные в крупных интернет‑компаниях |
210 |
TODS |
Синтетический датасет с различными глобальными, контекстуальными, сезонными и трендовыми аномалиями |
15 |
UCR |
Коллекция одномерных временных рядов из различных доменов: температура воздуха, артериальное давление, астрономия, ЭКГ и другие. Большинство аномалий искусственные |
203 |
В целом эти датасеты довольно репрезентативны и покрывают широкий спектр сценариев: от очень шумных рядов с неидеальной разметкой до синтетических данных с точной априорной разметкой.

Каждый ряд идёт в детектор в unsupervised‑режиме: модель анализирует весь ряд и возвращает anomaly‑score для каждой точки. Под капотом происходит восстановление гранулярности, применение модели и интерполяция предсказаний обратно в исходную сетку времени.
По результатам детекции для каждого временного ряда рассчитываются метрики качества детекции аномалий на основе полученных anomaly‑score и эталонной разметки, а также технические характеристики работы алгоритма (время обработки, использование памяти). После обработки всех рядов в датасете метрики усредняются, что даёт общую оценку производительности детектора.
Метрики качества
С метриками качества в детекции аномалий всё не так просто, как в классических ML‑задачах. Аномалии представляют собой не отдельные точки, а временные окна, причём во временных рядах их обычно меньше 10%. Хотя легко вычислить поточечную (pointwise) точность, полноту и F1-меру, эти метрики не отражают то, что действительно важно для дежурных инженеров.
Другая сложность — пороги. В продакшене дежурные настраивают чувствительность под себя, поэтому оценивать алгоритм при каком‑то фиксированном пороге бессмысленно. Нужно измерять потенциал: насколько хорошо алгоритм в принципе разделяет аномальные и нормальные точки. Поэтому вместо обычной F1-меры мы используем F1-best, которая вычисляется как наилучшая F1 по всем возможным порогам: берём предсказанные anomaly‑score, сортируем их, рассматриваем все пороги как набор средних значений между двумя последовательными скорами, вычисляем F1 для каждого порога и выбираем максимальную.
Другая важная метрика — AUC‑PR, которая заменяет AUC‑ROC, потому что ROC чувствительна к дисбалансу классов и может давать завышенные оценки при малом количестве аномалий. А для учёта сегментной природы аномалий мы применили Revised‑Point‑Adjusted‑подход для метрик F1, precision и recall:
Если хотя бы одна точка в окне истинной аномалии помечена как аномальная, засчитывается одно true positive.
Если в окне истинной аномалии не обнаружено ни одной аномальной точки, засчитывается одно false negative.
Любые предсказанные аномалии за пределами аномальных окон считаются false positive.

Для каждого временного ряда мы сохраняли визуализации с исходным рядом, эталонной разметкой, предсказанными аномалиями и anomaly‑score с порогом. Заодно логировали технические характеристики: время обработки, оптимальный порог срабатывания, поточечные метрики для сравнения подходов — и делали попарные сравнения.

Результаты бенчмаркинга
Для воспроизведения и сравнения с академическими исследованиями мы опирались на TimeSeriesBench — исследование ZTE и Китайской академии наук, где протестировали 17 методов на 6 датасетах в трёх режимах:
Naive schema — отдельная модель для каждого временного ряда.
All‑in‑one schema — обучение на всех рядах датасета.
Zero‑shot schema — обучение на части рядов, тестирование на остальных.
Мы сфокусировались на Naive schema, поскольку планировали применять алгоритмы в stateless‑режиме, где каждый временной ряд обрабатывается независимо, без сохранения состояния между запросами.

Основной вывод исследования: чем больше и сложнее модель, тем хуже детекция. Простые алгоритмы с индуктивными предположениями о природе временных рядов (авторегрессия, LSTM) значительно превосходят универсальные архитектуры. Мы провели собственный бенчмарк на тех же датасетах с нашими реализациями алгоритмов, метрика F1-best:
Датасет |
autoreg stable |
seasonal |
spectral residual |
prophet |
AIOPS |
0,75 |
0,61 |
0,77 |
0,68 |
NAB |
0,64 |
0,73 |
0,66 |
0,72 |
TODS |
0,70 |
0,66 |
0,76 |
0,23 |
UCR |
0,35 |
0,21 |
0,35 |
0,13 |
WSD |
0,83 |
0,82 |
0,85 |
0,86 |
Yahoo |
0,91 |
0,84 |
0,93 |
0,88 |
В итоге мы остановились на двух детекторах, у которых малое потребление памяти и предсказуемая стоимость при масштабировании, также они неплохо интерпретируются и устойчивы к форме инцидентов:
Авторегрессия — это удачный выбор для метрик без чёткой сезонности, которые могут меняться быстро. Её легко учить в рантайме, она устойчива к переобучению и имеет мало гиперпараметров. Несмотря на простоту, улавливает множество паттернов.
MEDIFF (декомпозиция для выявления нарушений в долгосрочных паттернах) хорошо засекает негладкие паттерны (а такие в технических метриках встречаются часто), при этом не шумит и работает быстро. Его мы решили использовать для ярко выраженных сезонных рядов.
Алгоритм работы детектора аномалий:
Берём временной ряд
.
-
Делаем прогноз (с помощью авторегрессии, сглаживания или чего угодно):
— прогноз модели в точке
,
.
Прогноз может строиться на основе окна предыдущих
‑значений (авторегрессия) или на основе всего ряда,
(MEDIFF).
-
Рассчитываем остатки:
— на сколько предсказания отходят от реальных наблюдений.
Предполагаем, что остатки распределены нормально:
.
Получаем z‑score (переводим в стандартное полунормальное распределение):
Проводим тест: точка аномальна, если
(по умолчанию 3).
Интерпретируем результат: значение выходит за пределы 3-сигма‑интервала (99,7% — вероятность стандартного полунормального распределения).
Смотрим на доверительный интервал:
.
Получаем итог: аномальные наблюдения соответствуют точкам, где исходный временной ряд выходит за доверительный интервал.
Это довольно простой принцип работы, но дьявол в деталях. Оба детектора пришлось корректировать, чтобы они стабильно работали в продакшене.
Стабилизация авторегрессии
На основе бенчмарков мы выбрали бейзлайн — авторегрессию. Она хороша на замерах, но на практике она со временем теряет стабильность. Дело в том, что аномалии вносят шум в данные, на которых модель строит предсказания значений, которые должны быть вместо аномальных. Как следствие, модель становится непредсказуемой, и это убивает интерпретируемость.

Чтобы исправить этот недостаток стандартного авторегрессионного алгоритма, мы внесли в него некоторые изменения. А именно — добавили учёт степени аномальности очередной наблюдаемой точки в алгоритм вычисления следующего предсказания. Этот подход позволяет восстанавливать наиболее правдоподобные значения ряда и использовать их для интерпретации следующих. Таким образом аномалии существенно меньше просачиваются в данные для предсказания, и вся детекция становится гораздо более стабильной и интерпретируемой. Этот алгоритм мы назвали autoreg_stable.

В результате метрики модели на всех датасетах выросли, а время работы детектора почти не увеличилось.
Адаптивная дисперсия для MEDIFF
Несмотря на то что сам по себе MEDIFF из коробки работает хорошо, у него есть один явный недостаток: он считает дисперсию наблюдений постоянной. Если ряд «шумит» днём больше, чем ночью, то MEDIFF этого не уловит и будет использовать одинаковые пороги для обоих моментов.
Мы исправили это, добавив оценку локальной дисперсии на основе соседних по времени точек внутри периода. Это работает так: берём окно с 300 точками (для статзначимости), считаем среднюю квадратичную ошибку по точкам окна внутри этого окна и получаем дисперсию в данный момент.
Такая модификация алгоритма помогает, например, в Такси, где ряды типа «число заказов в городе X» имеют значимо бо́льшую дисперсию днём, чем ночью.
Настройка алертов поверх аномалий
К сожалению, нельзя просто взять один из этих алгоритмов и настроить уведомления на каждую детекцию аномалии. Авторегрессия и MEDIFF работают поточечно и решают, насколько текущая точка похожа на норму. Если кидать алерт на каждую подозрительную точку, неизбежно получится полный бардак. Одиночные всплески, случайный шум и серии уведомлений на один длинный инцидент быстро замучают дежурных, и вскоре они просто перестанут доверять детектору и заглушат предупреждения.
Хороший компромиссный вариант — сначала решить, какие точки считать аномальными, а потом смотреть не на одну точку, а на поведение метрики во временном окне:
Задаём порог, насколько сильно должно отклониться значение, чтобы точка считалась аномальной.
Смотрим на последние N минут (скажем, 30) и считаем долю аномальных точек.
Алертим, только если доля аномальных точек превысила X% в этом окне.
Таким образом можно настроить и чувствительность детектора, и минимальное количество срабатываний за последние N минут, чтобы интерпретировать их как инцидент. Это позволит игнорировать редкие одиночные аномалии.
Осталось проверить, как всё это работает.
Мониторинг регионов Яндекс Такси на практике
Яндекс Такси работает в 800+ городах, и это хороший полигон для проверки наших алгоритмов. Даже кратковременный сбой в обработке заказов может привести к недовольству пользователей, а масштаб не оставляет шансов для ручных настроек.

Каждый регион уникален по своим масштабам, часовому поясу, праздникам и местным особенностям. Туристические города отличаются от промышленных центров динамикой заказов такси в будни и в выходные дни. Да и сезонность постоянно дрейфует: зимой заказов больше из‑за плохой погоды, летом — меньше из‑за отпусков. Кроме того, в данных много исторических аномалий и шума.
Для пилота мы выбрали 46 ключевых регионов по объёму GMV и количеству ежедневных поездок. На каждый регион настроили алерты по четырём критическим метрикам:
assigned — заказы с назначенным водителем;
created — общее количество созданных заказов;
found_share — доля заказов, для которых был найден водитель;
seen_timeout — доля заказов, которые мы не успели предложить водителю.

Калибровка порогов
После запуска 46 × 4 алертов быстро выяснилось, что базовой детекции аномальных точек недостаточно.
Одиночная аномальная точка сама по себе редко означает инцидент. Для дежурного важнее не разовый выброс, а устойчивое отклонение, которое продолжается некоторое время.
Для разных метрик важно учитывать направление аномалии. Резкий рост числа заказов сам по себе не обязательно говорит о проблеме в сервисе — это может быть дождь, снегопад или локальное событие в городе. А вот рост seen_timeout или падение found_share уже гораздо больше похожи на ситуацию, требующую реакции.
Уровень естественного шума различается от города к городу. То, что для крупного региона выглядит как нормальная флуктуация, для небольшого города может быть заметным отклонением, и наоборот.
Ключевая доработка, которая позволила превратить детекцию в рабочий алертинг, — это окно аномалий. Вместо реакции на каждую отдельную аномальную точку алерт стал срабатывать, если за выбранный интервал времени аномальными оказались значения, составляющие не менее заданной доли. Например, можно задать окно 30 минут и порог 30%: тогда уведомление придёт, только если аномалия держится достаточно долго, а не возникает на одном‑двух выбросах. На практике это резко снизило количество ложных срабатываний.

Отдельный класс ложных срабатываний был связан с погодой. Дождь или снег могут резко изменить спрос на поездки, и с точки зрения статистики это действительно аномалия. Но для команды надёжности это не инцидент: такие изменения не требуют вмешательства SRE. Поэтому в детектор добавили возможность задавать направление аномалии — вверх, вниз или в обе стороны. Это позволило, например, игнорировать всплески created, но продолжать реагировать на просадки assigned или рост seen_timeout.
После этого осталось вручную скорректировать чувствительность модели только для нескольких слишком «шумных» городов с небольшим числом поездок. Таких регионов за месяц наблюдений нашлось всего три. После этой калибровки к настройкам алертов не приходилось возвращаться уже более полугода.

Система сразу показала высокую эффективность в обнаружении реальных проблем. Команда SRE теперь реагирует на все уведомления из канала. Сейчас мы переносим свой подход на доступность тарифов, количество водителей на линии и готовим интеграцию с системами анализа инцидентов на основе больших языковых моделей.
Если вы решаете похожую задачу и выбираете между «написать свой детектор» и «взять готовый», надеемся, наш опыт поможет с выбором. Главный вывод, пожалуй, один: не начинайте с трансформеров. Начните с авторегрессии, поставьте бенчмарк и посмотрите, насколько далеко она вас уведёт. Скорее всего, дальше, чем вы ожидаете.
Сейчас мы совместно с коллегами из Monium активно работаем над тем, чтобы предоставить алерты по аномалиям не только внутренним пользователям Яндекса, но и внешним пользователям Yandex Cloud.
Будем рады вопросам в комментариях, особенно если у вас есть опыт других подходов к детекции в большом масштабе.