Что для пользователя считается успехом
Процесс жив, эндпоинт отдаёт HTTP 200, а заказ не оформился. Или оформился с неправильной суммой. Поэтому первым делом определяем, что для продукта означает успешная операция: корректное подтверждение заказа, найденный товар, доступный файл, готовый фоновый отчёт.
SLI измеряет качество, SLO задаёт целевой уровень. Например, для нашего сервиса выберем не меньше 99,9% корректных подтверждений за 30 дней. Затем договоримся, какие попытки входят в расчёт и что считаем плохим результатом. Иначе команда будет видеть зелёный график, исключив из знаменателя именно проблемные запросы.
Рядом держим RPS, ошибки, latency и насыщение ресурсов. Они помогают понять, что происходит с потоком и где кончается запас. CPU полезен для диагностики, но его высокий уровень сам по себе ещё не повод разбудить дежурного. Срочность зависит от влияния на работу продукта и времени до ухудшения.
Для оформления заказа различаем принятие запроса и завершение результата. Если сервис вернул 202 и задача осталась в очереди, быстрый ответ ещё не означает успешный заказ. SLI может считать долю операций, завершённых правильно в пределах нужного времени, а не только число ответов без серверной ошибки.
Место измерения влияет на картину. Внутренний сервис не увидит запрос, который не прошёл через входной слой. Клиентский сигнал может увидеть сетевую проблему, но не всегда отправит данные. Поэтому выбираем источник под обещание и понимаем, какую часть пути он не покрывает.
Правила исключения тоже требуют смысла. Ошибка в пользовательском вводе может не считаться отказом сервиса, но отказ из-за нашей неправильной проверки уже относится к качеству. Если исключать все ответы 4xx без разбора, можно случайно спрятать сломанную авторизацию или потерянный доступ.
Для критичных сценариев нужны отдельные показатели. Общая доступность, почти полностью состоящая из просмотра каталога, способна скрыть неработающую оплату. Разрез выбираем по важности продукта, а не по количеству эндпоинтов. Не каждому маршруту нужен свой SLO, но ключевые обещания не должны растворяться.
Цель согласуем с ценой и потребностью бизнеса. Дополнительная девятка требует ресурса, времени и изменений процесса. Если люди работают с продуктом только в рабочие часы, условия могут отличаться от круглосуточной оплаты. SLO полезен как договорённость о качестве и реакции, а не как красивое число в презентации.
График тоже может вводить в заблуждение
Успешные операции и ошибки смотрим отдельно. Во время аварии сервис может быстро отказывать, и средняя latency даже улучшится. Перцентили лучше показывают хвост, но p99 на маленькой выборке сильно гуляет. Рядом нужны объём трафика и разрез по важным эндпоинтам.
Среднее от p99 нескольких инстансов не становится p99 всего сервиса. Чтобы получить общую оценку, нужно объединить наблюдения подходящим способом, например через совместимые гистограммы. Границы бакетов выбираем под цель. Если SLO касается одной секунды, грубые бакеты вокруг этой границы сделают проверку неточной.
Для очереди мало длины. Смотрим скорость входа и обработки, а также возраст самой старой задачи. Сто задач могут рассосаться за секунду или висеть часами. Для периодической джобы нужна метрика последнего успешного запуска: ноль ошибок может означать, что она вообще перестала запускаться.
Счётчик показывает накопление событий, поэтому для потока нужен корректный расчёт прироста за окно. Рестарт процесса не должен превращаться в отрицательную нагрузку. Когда график резко меняется после деплоя, сначала проверяем семантику измерения, а не сразу поведение пользователей.
Гистограмма даёт приближённое распределение по бакетам. Чем лучше границы соответствуют нужному диапазону, тем полезнее оценка. Увеличивать их число бесконечно тоже нельзя: растут ряды и стоимость хранения. Выбор точности зависит от решения, например сравнения с порогом одной секунды.
Latency нужно измерять на подходящей границе. SQL занимает 30 мс, но заказ ждёт в очереди пять минут. Метрика обработчика покажет быстрый сервис, а пользовательский результат останется медленным. Для фонового пути отдельно считаем ожидание, обработку и время от принятия до завершения.
Отсутствие данных не равно нулю. Если сборщик перестал читать метрики, линия может пропасть без нового значения ошибки. Нужны правила обнаружения отсутствующего сигнала и понимание допустимого интервала. Для редко выполняемой джобы интервал отличается от постоянного HTTP-трафика.
Перед выводами проверяем окно и объём. Короткое окно быстро реагирует, но шумит, длинное скрывает начало. Для сравнения релизов нужны сопоставимые нагрузки. Один p99 без числа наблюдений, маршрута и периода измерения недостаточен для решения, что приложение стало быстрее.
Полезные метрики без взрыва кардинальности
Для поиска причин добавляем ожидание пула, блокировки, время вызова апстрима, память и диск. У каждой метрики должна быть понятная единица и точка измерения. Тогда за фразой "заказ тормозит" можно увидеть, на каком участке запрос провёл время.
Кардинальность растёт с числом сочетаний лейблов. Возьмём 20 маршрутов, пять статусов и десять инстансов: до 1000 комбинаций для одной метрики. Добавим user ID и получим рост числа рядов вместе с аудиторией. Гистограмма создаёт несколько рядов на набор лейблов, поэтому цена ошибки окажется ещё выше.
В метриках маршрута обычно оставляем шаблон, например /orders/:id. Конкретный ID и контекст запроса ищем в логах или трейсах. Собираем только то, что помогает разбору: полное тело запроса и секреты не становятся полезнее оттого, что их легко записать. У мониторинга тоже есть бюджет на хранение и обработку.
Для пула полезны текущая занятость, ожидающие запросы и время ожидания. Для апстрима нужны задержка, исход и доля таймаутов. Для памяти различаем рост полезного состояния, кэш и утечку. Эти сигналы помогают выбрать следующую проверку, но не являются готовым диагнозом сами по себе.
Лейблы проектируем как часть контракта. Набор допустимых значений должен быть ограничен и понятен. Полный URL, текст ошибки или произвольное название клиента опасны тем, что меняются без контроля. Даже низкий текущий трафик не гарантирует, что такая метрика останется дешёвой после роста.
С логами и трейсами тоже выбираем бюджет. Записывать каждое тело запроса дорого и рискованно для данных. Сэмплинг экономит ресурс, но может пропустить редкую проблему. Для важных ошибок и корреляции операций нужны правила, которые сохраняют полезный контекст без копирования всего подряд.
Корреляционный ID помогает связать шаги запроса, но не заменяет метрики. По нему ищем конкретную историю, по метрике видим масштаб. Если алерт сообщает рост ошибок, рядом должен быть путь к примерам, по которым можно проверить причину. Дашборд и расследование должны соединяться.
После добавления измерения проверяем его собственное влияние. Высокочастотные метрики, синхронная отправка логов и дорогие вычисления в обработчике могут ухудшить путь, который измеряют. Наблюдаемость должна переживать перегрузку предсказуемо, иначе во время сбоя она станет ещё одной зависимостью, требующей спасения.
SLO и error budget: когда пора реагировать
SLO 99,9% оставляет 0,1% плохих операций за окно. На миллионе запросов это 1000 ошибок. Если текущая доля ошибок поднялась до 1%, бюджет расходуется в десять раз быстрее допустимого темпа. Такой burn rate равен 10.
При равномерном потоке и окне 30 дней этот темп потратил бы полный бюджет примерно за три дня. В жизни трафик меняется и часть бюджета уже израсходована. Поэтому это ориентир для выбора реакции, который нужно сопоставить с текущим остатком, масштабом сбоя и временем на исправление.
Полезно сочетать длинное и короткое окна. Первое показывает существенный расход, второе подтверждает, что проблема всё ещё идёт. На малом трафике нужны другие условия: один отказ из десяти запросов уже даёт 10%. Здесь учитываем размер выборки, важность операции и дополнительные проверки, иначе каждый случайный сбой станет вызовом.
Burn rate связывает долю плохих событий с допустимой долей. Это полезно, потому что одинаковый процент ошибок по-разному относится к разным целям. Для SLO 99% один процент соответствует допустимому темпу, для 99,9% он в десять раз выше. Срочность всё равно зависит от длительности и масштаба.
Окно бюджета и окна алерта решают разные задачи. За месяц оцениваем обещание, за короткие периоды обнаруживаем продолжающийся сбой. Условие должно требовать достаточно существенного расхода и подтверждения, что проблема ещё есть. Иначе короткий всплеск сможет вызвать дежурного уже после самостоятельного восстановления.
Для маленького потока полезно дополнить наблюдение синтетической проверкой сценария. Она не заменяет реальные пользовательские события, но помогает заметить полностью сломанный путь, когда запросов мало. Проверка должна использовать безопасные данные и не создавать реальные списания или нежелательные операции.
Бюджет ошибок помогает обсуждать изменения, а не только алерты. Если качество стабильно хуже цели, постоянное добавление рискованных фич может усугубить положение. Можно направить время на причины отказов и пересмотреть выпуск. Такая договорённость должна быть известна бизнесу заранее, иначе метрика не будет влиять на решения.
Важно не превращать бюджет в разрешение терять любой результат. Финансовая ошибка, утечка или повреждение данных могут требовать немедленной реакции независимо от общего процента. SLO описывает выбранный аспект качества. Другие критические гарантии продукта остаются отдельными условиями.
Алерт должен помогать действовать
Пейджим дежурного, когда ожидание увеличивает ущерб и человек может что-то сделать. Медленный рост занятого диска можно сначала разобрать как задачу. Если до заполнения осталось меньше времени, чем требуется на расширение или очистку, реакция уже срочная. Одного процента заполнения для такого решения мало.
В алерте нужны затронутый сценарий, масштаб, начало проблемы, владелец и ссылка на runbook. В runbook пишем, как проверить причину, ограничить ущерб и подтвердить восстановление. Совет "перезапусти сервис" без последствий опасен: рестарт может оборвать работу, очистить локальную очередь или усилить нагрузку на зависимости.
Связанные симптомы группируем. Если апстрим упал, сообщение от каждого инстанса не добавит информации. Но подавление алертов надо проверять: отдельная проблема в нашем сервисе не должна исчезнуть за общим инцидентом. Повторы и эскалация нужны на случай, если первый вызов остался без реакции.
Разделяем вызов дежурного, рабочее уведомление и плановую задачу. Один канал для всего быстро перестаёт привлекать внимание. У каждого уровня должны быть ожидаемое время реакции и человек, который действительно способен выполнить действие. Отправить сообщение в общий чат не означает назначить ответственность.
Runbook начинается с проверки, что именно случилось. Какие графики открыть, как понять масштаб, что изменилось недавно? Затем идут безопасные способы снизить ущерб и ограничения этих способов. Если инструкция требует недоступного ночью разрешения, это операционный риск, который нужно решить заранее.
Указание сервиса и среды помогает не перепутать проблему. Алерт с названием хоста, непонятным кодом и ссылкой на общий дашборд заставляет дежурного строить контекст с нуля. Вызов должен объяснять пользовательский эффект и давать вход в диагностику, а не просто пересылать внутреннее условие.
Эскалация должна учитывать отсутствие реакции и отсутствие результата. Человек мог подтвердить вызов, но не иметь доступа или застрять в неверной гипотезе. Нужны понятные правила привлечения следующего специалиста и передачи контекста. Иначе подтверждённый алерт создаст ложное ощущение, что проблема уже решается.
Для повторов и группировки проверяем реальные примеры. Два симптома одного отказа удобно объединить, две независимые аварии нельзя скрыть общей тишиной. Завершение инцидента тоже должно быть подтверждено нужным сигналом. Просто закрытое уведомление не доказывает, что пользователи снова получают правильный результат.
Тестируем мониторинг как отдельный путь
В тестовой среде создаём известный сбой и проходим цепочку целиком: метрика изменилась, правило сработало, вызов дошёл, runbook помог, восстановление замечено. Отдельно проверяем пропавшие данные и отказ самого мониторинга. Иначе сломанный сборщик способен сделать дашборд спокойнее именно во время аварии.
После инцидента разбираем пропущенные сигналы, шум и время до полезного действия. Если алерт постоянно мешает, выясняем почему: неверный порог, плохое измерение или уже ненужное условие. Просто поднять порог означает рискнуть пропустить следующий сбой. Хороший мониторинг оцениваем по тому, помог ли он понять проблему и восстановить продукт.
Тест алерта делаем с известным ожидаемым временем. Создаём неисправность, отмечаем начало и смотрим, когда изменилось измерение, сработало условие и дошёл вызов. Так можно отделить задержку метрики от задержки доставки. Общее "алерт пришёл" не показывает, где теряется время.
Проверяем доставку вне рабочего контекста. Дежурный может быть без открытого ноутбука, приложение уведомлений без доступа, телефон без звука. Нужен реалистичный канал и резервный путь. Это не повод тревожить людей бессмысленным шумом, а часть проверки заранее согласованного дежурства.
На разборе инцидента сравниваем полезные сигналы с тем, что реально использовали. Десятки графиков могут существовать, но не отвечать на главный вопрос. Удаляем ненужное и добавляем недостающий контекст. Дашборд развивается вокруг диагностических задач, а не вокруг количества доступных метрик.
Изменение порога проверяем на истории и тестовом сценарии. Уменьшение шума не должно убрать обнаружение того сбоя, ради которого правило появилось. Если характер работы изменился, переписываем условие и объяснение. Старые алерты без владельца постепенно становятся частью фонового шума.
В итоге у мониторинга есть собственный цикл обслуживания: владелец, проверка, разбор полезности и обновление после изменений системы. Продукт растёт, появляются новые пути и другие пределы. Хорошая настройка в день запуска не гарантирует, что через год команда увидит тот же класс проблем вовремя.
Собираем мониторинг оформления заказа
Возьмём оформление заказа как один законченный путь. Успех означает корректный заказ в пределах согласованного времени, а не только быстрый ответ входного сервиса. Разделим ошибочный ввод и нашу ошибку, выберем источник измерения и отдельно проверим, какие отказы до него не доходят. Оплата остаётся видимой даже при большом количестве быстрых чтений.
Для диагноза добавим очередь, пул, апстрим и время завершения. В метриках оставим ограниченные шаблоны маршрутов, для конкретной истории используем ID в логах и трейсах. Проверим бакеты рядом с целевым временем и отсутствие данных. Дашборд соединит масштаб проблемы с примерами для расследования.
Правило вызова использует значимый расход бюджета и подтверждение продолжающегося сбоя. Малый поток дополним безопасной синтетической проверкой, а нарушения критичных инвариантов оставим отдельными сигналами. В уведомлении есть пользовательский эффект, владелец и runbook с доступными действиями. Его доставка и эскалация проверены.
Затем создадим тестовый отказ апстрима. Отметим начало, изменение показателя, срабатывание, доставку и время полезного действия. После восстановления проверим корректные заказы, а не только исчезновение уведомления. Результат упражнения покажет, где теряется время и какой контекст отсутствует. Мониторинг становится рабочим инструментом через такие проверки, а не через количество добавленных графиков.