Graceful degradation: как интернет-магазину пережить отказ части системы
Отказоустойчивость интернет-магазина — это не только резервные серверы, но и то, что увидит покупатель, когда сломалась одна функция. Такой подход называют изящной деградацией: система не падает целиком, а находит обходной путь. Ниже — пример с такси при сбое сервисов Яндекса, цепочка покупательских функций от главной до подтверждения и пять вопросов, которые стоит задать каждой из них.
Это «контролируемое ухудшение», когда у вас система не перестаёт работать при отказе её части, а находит обходное решение.
Пример: такси при сбое сервисов Яндекса
Сегодня, к большому сожалению, приходится наблюдать это на сервисах Яндекса. Очень хочется их поддержать и пожелать скорейшего восстановления.
Тем неменее, такси я смог вызвать
— Отказала их платежная система ≈ предложила другие формы оплаты
— Перестал работать обработчик статуса заказа = у водителя продолжил и он позвонил
И вдохновляет меня этот подход, потому что, это гарантированная возможность увеличить лояльность клиентов и поднять выручку. У всех с этим не идеально.
Дизайн отказа: честное сообщение вместо спиннера
А еще нравится, что задача и дизайнерская в том числе. Пользователю лучше честно сказать «Мы не можем посчитать курьерскую доставку», вместо бесконечного спинера🔤
Что делать: пройти цепочку покупательских функций
Что делать? Пройтись по ключевым покупательским функциям.
главная → поиск → карточка → корзина → checkout → оплата → подтверждение
Graceful degradation: 5 вопросов к каждой функции магазина
И задать 5 вопросов
1. Какие компоненты есть внутри каждой функции
2. На что переключаемся, если основной компонент отказал, например вместо тяжелых ML-рекомендаций показать блок «вы смотрели»
3. Что увидит покупатель
4. Дойдут ли гарантировано данные, которые отправил покупатель
5. Допустимы ли устаревшие данные, например остатками лучше пренебречь, в случае чего колцентр предложит замену
Что такое изящная деградация системы
Идея в одном предложении: если зависимость недоступна, компонент продолжает выполнять главную функцию, пусть с устаревшими, запасными или урезанными данными. Так это описывает руководство AWS Well-Architected: отказ одного звена не должен превращаться в отказ всей системы.
Слово «изящная» не про красоту. Оно про управляемость: заранее известно, что именно отключится, что заменит отключённое и что при этом увидит человек.
Жёсткая и мягкая зависимость
Жёсткая зависимость ломает функцию целиком: без неё ничего не работает. Мягкая позволяет функции работать в упрощённом режиме. Тяжёлые ML-рекомендации на главной — типичная мягкая зависимость: блок «вы смотрели» справится без них. Единственный платёжный провайдер без запасного способа оплаты — жёсткая.
В руководстве AWS эта работа так и называется: превратить жёсткие зависимости в мягкие. Начинать стоит с тех, что стоят на пути к деньгам.
Изящная деградация и progressive enhancement: в чём разница
В веб-разработке эти понятия часто ставят рядом, и в выдаче по ним в основном разбирают браузеры и CSS. В истории про магазин речь о другом: о сбоях сервисов на бэкенде и в интеграциях. Различие подходов удобно держать в голове.
| Параметр | Изящная деградация | Progressive enhancement |
|---|---|---|
| Отправная точка | Полная версия, для которой заранее продумано запасное поведение | Базовая версия, работающая у всех |
| Что происходит дальше | При отказе часть возможностей отключается | Если среда позволяет, возможности добавляются |
| Где применяют | Фронтенд, бэкенд, интеграции, инфраструктура | Преимущественно веб-интерфейсы |
| Вопрос на старте | На что переключиться, если эта часть отказала | Что обязано работать у каждого |
Отказоустойчивость интернет-магазина по шагам покупки
Цепочка из поста — главная, поиск, карточка, корзина, checkout, оплата, подтверждение — это карта зависимостей. Для каждого шага стоит выписать внешние сервисы и решить, что происходит без них. Ниже варианты, которые подходят большинству магазинов.
| Шаг | Что может отказать | Запасной вариант | Что увидит покупатель |
|---|---|---|---|
| Главная | ML-рекомендации | Блок «вы смотрели» или популярные товары | Обычная главная, отличий почти нет |
| Поиск | Поисковый движок с ранжированием | Упрощённый поиск по названию и категориям | Менее точная выдача без сообщений об ошибке |
| Карточка | Остатки, отзывы, внешние данные | Карточка без блока отзывов, остатки не блокируют покупку | Товар и кнопка «В корзину» |
| Корзина | Расчёт скидок и бонусов | Сохранить корзину, пересчитать на следующем шаге | Корзина с пометкой, что цена уточнится |
| Checkout | Расчёт курьерской доставки | Самовывоз, курьер с ценой позже | Честное сообщение и другой способ получения |
| Оплата | Платёжная система | Другие способы оплаты | Список доступных способов |
| Подтверждение | Письмо, SMS, учётная система | Очередь и повторная отправка | Номер заказа на экране сразу |
Что показать покупателю при отказе
Хороший отказ состоит из трёх частей: что не работает, что можно сделать вместо этого и что будет дальше. «Мы не можем посчитать курьерскую доставку» плюс кнопка самовывоза понятнее и безопаснее, чем крутящийся индикатор.
Спиннеру нужен предел. Если зависимость не ответила за заданное время, интерфейс переходит к запасному сценарию сам, не дожидаясь, пока покупатель закроет вкладку.
Паттерны, на которых держится деградация
Продуманный дизайн отказа держится на нескольких инженерных приёмах. Они давно описаны и поддерживаются библиотеками для большинства языков.
- Таймауты: ожидание ответа зависимости ограничено, а не бесконечно.
- Circuit breaker, «предохранитель»: после заданного числа ошибок вызовы сервиса прекращаются, и сразу отдаётся запасной ответ.
- Кэш с устаревшими данными: показывается последнее удачное значение.
- Очереди и повторы: заказ принят, а передача в учётную систему выполнится позже.
- Отключение тяжёлых функций вручную, например рекомендаций под нагрузкой.
Circuit breaker и таймауты
Паттерн популяризировал Майкл Нигард в книге «Release It!». Предохранитель оборачивает вызов удалённого сервиса и считает ошибки. Пока всё в порядке, он закрыт. Когда ошибок слишком много, он размыкается и отклоняет вызовы, не обращаясь к сервису. Через заданное время пропускается пробный вызов: удачный закрывает предохранитель, неудачный размыкает снова.
Такая схема не даёт очереди запросов копиться на недоступном сервисе и тянуть за собой остальную систему.
Очереди, повторы и идемпотентность
Четвёртый вопрос из списка — дойдут ли данные покупателя — решается очередью: заказ сохраняется у вас, а интеграции получают его позже. Повторная отправка не должна создавать дубль. Для платёжных запросов это решает ключ идемпотентности: у ЮKassa заголовок Idempotence-Key принимает до 64 символов, а повтор с тем же ключом в течение 24 часов возвращает исходный результат.
Устаревшие данные: где это допустимо
Пятый вопрос требует решения от бизнеса, а не от разработчика. Остатки обычно можно показать неточно: если позиция закончилась, колл-центр предложит замену. Цена и статус оплаты — другое дело, ошибка там стоит дороже недоступности.
Пять вопросов на примере шага оплаты
Чтобы вопросы не остались абстракцией, пройдите их по порядку на одном шаге. Оплата подходит лучше всего: здесь отказ дороже всего.
- Компоненты: форма оплаты, платёжный провайдер, банк, подтверждение 3-D Secure, фискализация чека.
- Переключение: другой способ оплаты, например СБП или оплата при получении, если магазин её допускает.
- Что увидит покупатель: сообщение, что выбранный способ временно недоступен, и список остальных.
- Дойдут ли данные: заказ сохранён со статусом «ожидает оплаты», повторная попытка не создаёт второй заказ.
- Устаревшие данные: для статуса оплаты недопустимы, статус берут у провайдера, а не из кэша.
Как проверить, что запасной путь работает
Запасной путь, который ни разу не запускали, чаще всего не работает. В руководстве AWS отдельно сказано, что такие пути нужно тестировать и что они должны быть заметно проще основного.
- Составить карту зависимостей по шагам покупки.
- Для каждой зависимости записать поведение при отказе и ответственного.
- Искусственно отключить зависимость в тестовой среде и пройти покупку как клиент.
- Считать, сколько заказов прошло через запасной путь, и настроить оповещение при росте.
Типичные ошибки
Запасной путь сложнее основного и ломается чаще. Отказ не пишется в журнал, и команда узнаёт о нём от клиентов. Сообщение об ошибке технически точное, но не говорит покупателю, что делать дальше.
Вопросы и ответы
Что такое изящная деградация системы простыми словами?
Это контролируемое ухудшение: если часть системы отказала, остальное продолжает работать и находит обходное решение. Например, при сбое платёжной системы покупателю предлагают другие способы оплаты.
Как повысить отказоустойчивость интернет-магазина?
Пройдите цепочку главная → поиск → карточка → корзина → checkout → оплата → подтверждение и задайте каждой функции пять вопросов: из чего она состоит, на что переключаться при отказе, что увидит покупатель, дойдут ли его данные и допустимы ли устаревшие.
Что показать покупателю, если сервис не отвечает?
Честное сообщение о том, что именно не работает, например «Мы не можем посчитать курьерскую доставку», и доступную альтернативу. Бесконечный спиннер хуже любого честного текста.
Можно ли при сбое показывать устаревшие остатки товара?
В примере из поста остатками лучше пренебречь: если товара не окажется, колл-центр предложит замену. Устаревшие данные допустимы не везде, поэтому вопрос задают отдельно по каждой функции.