Рано или поздно в любом проекте настает время работать над стабильность/доступностью вашего сервиса. Для каких-то сервисов на начальном этапе важнее скорость разработки фич, в этот момент и команда не сформирована полностью, и технологии выбираются не особо тщательно. Для других сервисов (чаще технологические b2b) для завоевания доверия клиентов необходимость обеспечения высокого uptime возникает с первым публичным релизом. Но допустим, что момент X все-таки настал и вас начало волновать, сколько времени в отчетный период "лежит" ваш сервис. Под катом я предлагаю посмотреть, из чего складывается время простоя, и как эффективнее всего работать над его уменьшением.
Показатели
Очевидно, что прежде чем что-то улучшать, нужно понять текущее состояние. Следовательно, если мы начали уменьшать downtime, его в первую очередь и нужно начать измерять.
Мы не будем здесь подробно говорить о том, как конкретно это делать, плюсы и минусы разных подходов, но тезисно процесс выглядит как-то так:
- опираемся на около-бизнесовые метрики (ошибки в работе сервиса, время отклика сервиса, $/second, signups/second итп)
- определяем, что такое хорошо, а что такое плохо
- переход хорошо->плохо является началом инцидента
- переход плохо->хорошо — конец инцидента
- время от начало до конца — длительность инцидента (кэп с нами)
- сумма длительностей инцидентов за период (месяц/квартал/год) — время простоя (downtime)
- <время простоя>/<длительность периода> * 100 = процент доступности за период
Когда говорят об uptime/downtime, часто упоминают еще один показатель:
MTTR (mean time to repair) — среднее время от начала инцидента до его окончания.
Проблемы с ним начинаются прямо с первого слова в аббревиатуре. Учитывая, что все инциденты разные, усреднение длительности ни о чем в системном плане нам сказать не может.
В этот раз мы не будем ничего усреднять, а просто посмотрим, что происходит в ходе инцидента.
Анатомия инцидента
Давайте посмотрим, какие значимые этапы можно выделить в ходе инцидента:
- detection — интервал между первой ошибкой, которую мы отдали пользователю, до того, как дежурному пришло SMS
- reaction — от получения уведомления о проблеме до момента, когда человек приступил к решению данной проблемы (обычно в этот момент событие в мониторинге переводится в состояние Acknowledged)
- investigation — от начала работы над проблемой до момента, когда понятна причина инцидента и мы знаем, что нужно сделать, чтобы восстановить работу.
- elimination — время восстановления, например, откатываем релиз, промоутим новый
masterprimary сервер БД
Возможно наша модель неполная и есть какие-то еще стадии, но предлагаю их вводить только после осознания, как это поможет нам на практике. А пока рассмотрим подробнее каждую стадию.
Detection
Почему вообще мы тратим время на обнаружение внештатной ситуации? Почему не отправлять уведомление при первой же ошибке, которую получил пользователь? На самом деле я знаю многие компании, которые пытались так делать, но от этой идеи отказывались буквально через несколько часов, за которые получили несколько десятков SMS. Я думаю, что не существует ни одного более-менее крупного сервиса, у которого бы не было постоянного "фонового" потока ошибок. Не все из них признак того, что что-то сломалось, бывают еще и баги в софте, невалидные данные полученные из формы и недостаточная валидация, итд.
В итоге в качестве критерия для открытия инцидента используется уровень ошибок (или других метрик), которые превосходит ежедневные колебания. Именно это и приводит к тому, что уведомление ответственных сотрудников происходит позже фактического начала проблемы.
Но вернемся к нашей изначальной задаче — снижению длительности инцидентов. Как мы можем сократить время обнаружения? Быстрее уведомлять? Придумывать супер-логику обнаружения аномалий?
Я предлагаю пока ничего не делать, а посмотреть на следующие стадии, так как на самом деле они взаимосвязаны.
Reaction
Здесь у нас чисто человеческий фактор. Мы предполагаем, что мониторинг справился с обнаружением проблемы и мы успешно разбудили дежурного инженера (вся эскалация тоже отработала на предыдущем этапе).
Рассмотрим "худший" случай, выделенной дежурной службы у нас нет, и алерт настиг мирно спящего админа. Его действия:
- среагировать на SMS: тут очень помогает жена с чутким слухом, различные приложения для телефона, усиливающие эффект от получения SMS (1-5 минут)
- принять решение о том, что из кровати он все-таки будет вылезать: если алерты настроены неправильно, человек может 2 минуты ждать "а вдруг придет resolve?" и уснуть (1-15 минут)
- добраться до ноута, открыть глаза, проснуться, добраться до мониторинга, нажать Ack: (1-15 минут)
В итоге в худшем случае получаем 35 минут реакции. По моим наблюдениям такое время реакции похоже на правду.
Так как в на этом этапе мы имеем дело с людьми, нужно действовать крайне осторожно и продумано. Ни в коем случае не нужно писать регламент, согласно которому только что проснувшийся человек должен пошевеливаться! Попробуем просто создать условия.
Давайте для начала уберем сомнения инженера в том, что проблема закончится сама. Это делается очень просто: сделать критерий алерта нечувствительным к мелким проблемам и уведомлять, если инцидент длится какое-то значимое время. Да, мы только что увеличили длительность стадии "detection", но давайте рассмотрим на примере:
- увеличиваем время обнаружения на 5 минут
- количество инцидентов снижается: все короткие всплески ошибок как правило укладываются в 1 минуту. Эти короткие инциденты нужно обязательно фиксировать, но без уведомления людей. Часто суммарно они дают очень большое время простоя, но разбираться с ними можно в рабочее время. Для этой задачи вам потребуется высокая детализация в мониторинге, так как проблема уже закончилась, а диагностические тулзы в большинстве своем не хранят истории.
- если человек вынужден реагировать на алерты раз в месяц или реже, а не через день, он будет реагировать на это более адекватно и не относиться к этому как к рутине
- отложенная нотификация позволяет человеку не думать: если SMS пришло, значит всё серьезно и само не исправится
Потенциально такой подход позволит сократить суммарное время реакции, на 15+ минут. Если вас и такое время реакции не устраивает, стоит подумать о дежурной службе.
Investigation
Пожалуй, эта самая сложная стадия аварии, когда вам нужно понять, что происходит и что делать. В реальности эта стадия очень часто совмещена со стадией принятия мер, так как обычно процесс идет так:
- смотрим в мониторинг, логи (если мониторинга недостаточно), запускаем еще какие-то диагностические тулзы
- выдвигаем гипотезы
- проверяем гипотезы, либо по метрикам, либо выполняя какие-то действия (рестартим все подряд:)
- оцениваем результаты изменений
- коммуницируем с коллегами, если ваших знаний о конкретной подсистеме недостаточно
и так до просветления или окончания инцидента.
Эта стадия обычно самая значимая в суммарной длительности инцидента. Как же ее уменьшать?
Здесь все не очень однозначно, есть несколько векторов:
- упрощать инфраструктуру: представьте, как быстро траблшутят люди, у которых одна база данных и один сервис
- распространение знаний в команде: идеально, если коммуникация людей будет идти не в процессе инцидента, а во время ежедневной работы (коммуникация людей вообще очень долгий процесс)
- мониторинг: многие думают, что мониторинг работает только на стадии "detection", но на самом деле он может выступать оптимизацией процесса проверки гипотез ("штатно ли работает БД?", "не уперся ли мой сервис в ресурсы?") и еще как транспорт распространения знаний в команде. "Серега, проверь, есть ли в логе X ошибки про дедлоки?" можно превратить в триггер, в описание которого будет ссылка на wiki с инструкцией.
Elimination
Как я говорил выше, эта стадия часто сливается с предыдущей. Но бывает так, что сразу понятна причина, но восстановление будет очень долгим. Например, у вас умер сервер с master primary (еще долго не смогу к этому привыкнуть:) базой данных, а реплику вы ни разу не промоутили, то есть вы будете читать документацию, раскатывать новый конфиг приложений итд.
Естественно после каждого значимого инцидента нужно разбираться, как не допустить такое снова или сильно ускорить восстановление. Но давайте посмотрим, какие направления нам можно попробовать проработать проактивно:
- инструментарий управления инфраструктурой: если для того, чтобы все починить вам нужно раскатить новый конфиг, но это делается минимум за 20 минут — это ваше ограничение. Попробуйте придумать сценарии, что может произойти и способ экстренного ускорения каких-то процессов. Например, в ansible у вас настроен serial (параллельность выполнения задач) = 3, но если все равно лежим, можно катиться с serial=30, нужно всех научить это переопределять (аналогично про rolling update strategy в kubernetes).
- учения: если вы знаете вероятные сценарии отказа и восстановление у вас не автоматизировано, у вас должны быть инструкция, которая обязательно должна быть протестирована. Запланируйте downtime (если нужно), проведите учения. Часто на этом этапе такие кейсы автоматизируются, так как в процессе учений выясняется большинство подводных камней даже самых сложных на первый взгляд процедур.
- взаимодействие с подрядчиками: вы должны заранее знать, что будете делать, если вашему хостеру станет плохо. Часто осознание вероятности проблемы и затрат на закрытие рисков приводит к выводу — "просто будем ждать восстановления". Но с другой стороны к такому сценарию будут готовы и инженеры и бизнес. Например, можно проработать вопрос с переключением вашего трафика на заранее заготовленную заглушку, уведомить пользователей заранее заготовленным письмом итд. Или наоборот, вы делаете инструкцию, по которой мы даем хостеру 30 минут на восстановление, а дальше начинаем переезд в другой ДЦ, где уже есть реплика БД, но нужно развернуть все остальное. И здесь опять же учения, засекаем время на переезд итд.
MTBF (Mean Time Between Failures)
Еще один распространенный показатель, который упоминают при обсуждении uptime. Я предлагаю опять ничего не усреднять, а просто поговорить о количестве инцидентов, которые случаются за интервал времени.
Здесь на первый план выходит вопрос, насколько вы позаботились об отказоустойчивости вашего сервиса:
- есть ли единые точки отказа (SPOF) в инфраструктуре, какова вероятность отказа?
- насколько вы уверены, что нет SPOF, о которых вы не знаете? (это ровно та проблема, которую решают с помощью chaos monkey)
- хорошо ли балансировщики нагрузки отрабатывают отказы? (мой доклад про балансировку)
- насколько отказоустойчива сеть?
- насколько надежен датацентр?
Иногда, чтобы все это просчитать/спрогнозировать делают "карту рисков", где у каждого сценария (который смогли предположить, естественно всегда остаются те, которых мы пока не знаем) есть вероятность + эффект воздействия (даунтайм короткий/длинный, потеря данных, репутационные потери, итп). Потом по такой карте планомерно работают, закрывая в первую очередь высоковероятные и серьезные по воздействию сценарии.
Другой прием, который можно использовать — классификация прошедших инцидентов. Сейчас много говорят о том, что очень полезно писать "разборы" (post mortem) инцидентов, где анализируются причины проблемы, действия людей, прорабатываются возможные будущие действия. Но чтобы быстро взглянуть на причины всех аварий за прошлый период удобно просуммировать их длительность с группировкой по "классам проблем" и там где больше всего downtime принимать меры:
- человеческие ошибки: снижать количество ручных действия в production, разные защиты от ошибки операторов
- неудачные релизы: стоит улучшать тестирование (в том числе нагрузочное)
- ошибки в приложениях: чинить утечки, крэши и другие "зависания"
- сеть: купить оборудование, настроить, нанять сетевиков, сменить подрядчика
- базы данных: нанять DBA, позаботиться про отказоустойчивость, купить железо получше
- ДЦ: думать про резервный или переезд
- внешние воздействия (ddos, блокировки, отзывы сертификатов, домены): купить antiddos, запастись проксями, замониторить срок действия доменов/сертификатов, иметь несколько сертификатов от разных CA.
То есть, если даже не пытаться предугадать возможные сценарии проблем, то работать с уже случившимися инцидентами определенно стоит.
Итого
Все инциденты разные:
Алгоритм работы над увеличением uptime очень похож на любую другую оптимизацию:
измеряй -> анализируй -> пробуй улучшить -> оценивай результат
По своему опыту могу сказать, что для существенного улучшения аптайма достаточно просто начать за ним следить и анализировать причины инцидентов. Обычно бывает, что самые простые изменения приносят самый значимый эффект.
Наш сервис мониторинга помогает не только со стадией "detection", но и сильно сокращает " investigation" (клиенты подтвердят)
Автор: Николай Сивко