← Все постыНаписать

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 → оплата → подтверждение и задайте каждой функции пять вопросов: из чего она состоит, на что переключаться при отказе, что увидит покупатель, дойдут ли его данные и допустимы ли устаревшие.

Что показать покупателю, если сервис не отвечает?

Честное сообщение о том, что именно не работает, например «Мы не можем посчитать курьерскую доставку», и доступную альтернативу. Бесконечный спиннер хуже любого честного текста.

Можно ли при сбое показывать устаревшие остатки товара?

В примере из поста остатками лучше пренебречь: если товара не окажется, колл-центр предложит замену. Устаревшие данные допустимы не везде, поэтому вопрос задают отдельно по каждой функции.

Обсудить в Telegram Подписаться на @altocodes