Не дайте системе упасть полностью: проектирование режима деградации для малых команд
Когда внешний сервис недоступен, как малой команде сохранить основной путь? Предлагаем подход от карты зависимостей до регулярных учений.
В прошлом году мы создали инструмент, который зависел от стороннего API. В пятницу после обеда API начал возвращать ошибки 5xx. В нашей маленькой команде не было выделенного администратора; мониторинг сработал трижды, прежде чем мы поняли, что проблема в сети провайдера. Нам потребовалось четыре часа, чтобы включить переключатель деградации — не потому, что мы не хотели, а потому, что мы никогда не проектировали, как система должна выглядеть после деградации.
Сегодня я хочу поговорить о том, почему малые команды обязаны заранее проектировать режим деградации и как это делать. Это не обширная тема «высокодоступной архитектуры», а конкретные инженерные решения: переключатели, страницы, таймауты.
Деградация — это не «замедление», а «более узкий путь, который всё ещё работает»
Многие команды понимают деградацию как «система становится медленной» или «запасной вариант при недоступности». Но суть деградации в том, чтобы при ограниченных ресурсах или сбоях зависимостей осознанно отказаться от части функций, сохранив основную ценность.
Вот пример (не из нашего опыта, но типичный): контентное сообщество зависит от сервиса рекомендаций. Если сервис падает, а вся лента выдаёт ошибку, пользователь не видит ничего. Режим деградации — это откат к простой ленте, отсортированной по времени. Качество рекомендаций падает, но пользователь всё ещё может просматривать контент. Это и есть «более узкий путь».
У малых команд нет ресурсов строить высокодоступные кластеры для каждой зависимости, но вполне реально превратить «полный отказ» в «частичную доступность» через проектирование режима деградации.
Шаг 1: Составьте карту зависимостей и выделите критические
Проектирование деградации начинается с понимания того, от чего вы зависите. Многие малые команды рисуют диаграммы только своих сервисов, но не внешних зависимостей. Я предлагаю создать карту зависимостей:
- Перечислите все внешние сервисы: API, базы данных, кэш, сторонний вход, оплата, SMS, объектное хранилище и т.д.
- Для каждой зависимости задайте два вопроса:
- Если она упадёт, сможет ли мой основной путь всё ещё работать?
- Если нет, есть ли альтернативный путь?
- Отметьте «критические зависимости» — те, без которых основная ценность недостижима.
Для критических зависимостей режим деградации обязателен. Для некритических — хотя бы корректное сообщение об ошибке.
Распространённое заблуждение — считать базу данных «всегда доступной». На самом деле медленные запросы или исчерпание пула соединений встречаются чаще, чем полный отказ. Режим деградации не обязательно означает переход на реплику; можно ограничить глубину запросов, вернуть кэш или отклонять некритичные запросы.
Шаг 2: Определите условия срабатывания и восстановления для каждого режима
Деградация — не спонтанное решение, а заранее определённые правила: когда включать, когда выключать.
Худший вариант деградации, который я видел: срабатывает оповещение, но никто не решается включить режим, потому что «подождём и посмотрим». В итоге пользователи уже возмущаются, пока вы ждёте.
Рекомендую для каждой критической зависимости задать три порога:
- Порог предупреждения: например, доля ошибок > 5% в течение 5 минут. Режим не включается, но уведомляется ответственный.
- Порог деградации: например, доля ошибок > 20% в течение 2 минут или P99 задержки > 3 секунд. Режим включается автоматически или вручную.
- Порог восстановления: например, доля ошибок < 2% в течение 10 минут — только тогда разрешён откат.
Пороги не должны браться с потолка. Используйте неделю нормального трафика для калибровки. Если нет исторических данных, начните с консервативных значений и скорректируйте после следующего инцидента.
Условия восстановления не менее важны. Многие команды включают деградацию, но боятся возвращаться, потому что «вдруг снова упадёт». Условия восстановления должны быть строже, чем условия деградации, чтобы избежать колебаний.
Шаг 3: Заранее спроектируйте пользовательский опыт в режиме деградации
Деградация — это не только бэкенд-переключатель, но и фронтенд-взаимодействие. Пользователь не должен видеть страницу 500; он должен видеть сообщение вроде «Мы временно упростили некоторые функции».
Конкретно:
- Если деградация невидима (например, лента переходит от рекомендаций к сортировке по времени), добавьте ненавязчивое уведомление, чтобы пользователь не гадал, почему изменился контент.
- Если деградация отключает некоторые функции (например, оплату), явно сообщите об этом и предложите альтернативу («попробуйте позже» или «свяжитесь с поддержкой»).
- В режиме деградации сохраняйте основные пользовательские пути. Например, для интернет-магазина, если поиск недоступен, но просмотр по категориям работает, убедитесь, что страница категорий остаётся доступной.
Легко упустить из виду аналитику во время деградации. Нужно различать «нормальный трафик» и «трафик в режиме деградации», чтобы оценить влияние после восстановления. Рекомендую добавить метку в переключатель деградации и писать её в логи.
Шаг 4: Превратите переключатель деградации в «материальный объект», а не просто булевую переменную в коде
Малые команды часто совершают ошибку, помещая переключатель в код, управляемый конфигурационным файлом. Изменение конфигурации требует релиза, а релиз — процесса; к моменту завершения процесса инцидент длится уже полчаса.
Рекомендую вынести переключатель в отдельный центр конфигурации или простой внутренний эндпоинт, который можно менять динамически без релиза. Даже простой JSON-конфиг с внутренней страницей администрирования подойдёт.
Если боитесь ошибочных действий, добавьте диалог подтверждения, но гарантируйте, что время от подтверждения до вступления в силу не превышает 1 минуты.
Также давайте переключателям понятные имена и документацию. Не ждите сбоя, когда несколько человек спорят в чате, что делает этот переключатель.
Шаг 5: Регулярно тренируйтесь — не давайте плану деградации существовать только в документах
Самый надёжный план деградации — тот, который кто-то реально выполнял хотя бы раз. Рекомендую ежеквартально проводить «учения по деградации»: выберите непиковое время, принудительно включите один переключатель, наблюдайте за системой, фиксируйте проблемы, затем восстановите.
Учения не должны быть сложными. Например:
- Вручную отключите сетевой доступ к одной зависимости (в тестовой среде).
- Проверьте, сработала ли деградация как ожидалось.
- Убедитесь, что пользовательский опыт соответствует задумке.
- Затем восстановите и проведите разбор.
Первые учения часто выявляют множество проблем: слишком короткий таймаут, вызывающий ложную деградацию, страница, ломающаяся в режиме деградации, API, который всё ещё вызывается, и т.д. Обнаружить эти проблемы на учениях в сто раз лучше, чем во время производственного инцидента.
В заключение: Деградация — это инженерное решение принять несовершенство
У малых команд нет ресурсов для безупречной высокой доступности, но через проектирование режима деградации мы можем превратить «полный отказ» в «частичную доступность». Это требует принятия того, что режим деградации снижает пользовательский опыт, но это лучше, чем ничего.
Каждый инцидент — это возможность для калибровки. После инцидента спросите себя: Сработал ли режим деградации как ожидалось? Были ли условия срабатывания разумными? Соответствовал ли пользовательский опыт задумке? Запишите ответы в журнал решений и улучшайте в следующий раз.
Суть инженерии не в погоне за совершенством, а в поиске наименее плохого пути среди несовершенства.
PaxLee