Слогер Создать блог
Разработка

Как проектировать отказы системы: доктрина радиуса поражения

Сеньор отличается от джуна не тем, что его код работает, а тем, что он заранее решил, как этот код будет ломаться. Разбираем подход, который называется доктриной радиуса поражения.

Провайдер платежей отдаёт таймаут. Что дальше? Таймаут выжирает пул соединений — а тот блокирует API оформления заказа? Блокировка валит каталог товаров, и каталог тянет за собой всё остальное?

Цепочка из пяти вопросов, и в ней уже вся суть senior-инженерии. Код, который работает на счастливом пути, пишется легко: тут справится и джун, и генератор кода за пять секунд. Локальные тесты зелёные, сервис поднимается, всё красиво. Интерес начинается ровно в тот момент, когда что-то отваливается.

У этого взгляда есть название — доктрина радиуса поражения (Blast Radius Doctrine). Идея простая: у каждой ошибки есть радиус, и этот радиус можно ограничить архитектурой, а не героизмом дежурного в три ночи.

Два типа систем

На практике встречаются две крайности. Первая — когда связи между сервисами настолько плотные, что одна необработанная ошибка запускает retry storm по зависимостям и укладывает весь кластер. Вторая — когда отказы предусмотрены и заперты в своих отсеках: упал движок рекомендаций — корзина работает, база подтормаживает — срабатывают circuit breakers, читающие реплики берут нагрузку на себя, а пользователь получает кэшированный ответ.

Хрупкий каскадСуверенный балкхед
Связи между сервисамиЖёсткие: сосед падает — падаешь тыРазделены явными стенами
Необработанное исключениеРетраи расходятся по зависимостям и валят кластерОстаётся внутри своего отсека
Внешний сервис тормозитПул соединений исчерпан, очередь запросов растётБрейкер размыкается, реплики забирают чтение
Что видит пользовательБелый экран целикомКэшированный фоллбэк: рекомендации не грузятся, корзина живёт
Кто решил, что будет такНикто. Так получилосьИнженер, который заранее выбрал режим отказа
Сеньор пишет код не для того, чтобы он работал. Сеньор проектирует архитектуру, чтобы решить, как он будет ломаться.

Модели, генерирующие код, не имеют понятия об организационном радиусе поражения. Они выдают изолированные функции, и в этом их предел: стены, которые удерживают взрыв, ставит человек. Функция может быть идеальной и при этом лежать в контуре, где один таймаут сносит витрину.

Что делать в понедельник утром

Ревью — самое дешёвое место, чтобы поймать эту проблему. Открывая пул-реквест — неважно, человеческий или сгенерированный, — добавьте к обычной проверке синтаксиса один вопрос: если конкретно эта строка бросит исключение таймаута, какой максимальный радиус ущерба?

  1. Если ответ «упадёт весь сервис» — до мержа нужен circuit breaker или балкхед.
  2. Если ответ «деградирует один блок страницы» — уже нормально, но проверьте, чем именно деградирует.
  3. Если ответ «не знаю» — считайте, что радиус неограничен, пока не доказано обратное.

Технический минимум на каждый внешний вызов

  • Явный таймаут. Не «по умолчанию из библиотеки», а выбранное число, которое меньше бюджета всей операции.
  • Ретраи с backoff и jitter и жёстким лимитом попыток. Без разброса они сами становятся источником шторма.
  • Отдельный пул соединений на каждую зависимость — чтобы медленная чужая база не съедала поток, который нужен остальным.
  • Circuit breaker с понятным порогом срабатывания и понятным поведением после размыкания.
  • Фоллбэк, который реально работает: кэш, урезанный ответ или честный отказ на одном блоке интерфейса. Ошибка здесь не должна ходить в ту же недоступную базу.

Когда это лишнее

Внутренняя админка на двадцать человек, которая ходит в одну базу и больше никуда, не нуждается в балкхедах и брейкерах. Стоимость поддержки такой обвязки выше риска: если инструмент встанет на десять минут, никто не заметит. А вот если через этот же контур идут деньги или он стоит между пользователем и каталогом — вопрос «как оно сломается» перестаёт быть теоретическим.

Типичные ошибки

  • Единый пул соединений на все зависимости сразу.
  • Отсутствие таймаута: «подождём, пока ответит».
  • Тесты только по счастливому пути — падение внешнего сервиса никто не воспроизводит.
  • Фоллбэк, который на поверку сам зависит от упавшего узла.
  • Ретраи без разброса: пять сервисов одновременно повторяют запрос, и добивают то, что почти поднялось.

Проверка на пальцах

Возьмите одну главную пользовательскую цепочку — оплата, заказ, каталог — и мысленно отключите каждое звено по очереди. Запишите, что именно упадёт и что останется жить. Это и есть карта радиуса поражения вашей системы, и она полезна куда больше, чем схема сервисов из вики. Если для какого-то звена ответ «упадёт всё», вы нашли следующий балкхед. Если для какого-то звена ответа нет вообще, значит, поведение системы при сбое никто не выбирал — оно получилось само.

Архитектура проявляется не на зелёных графиках, а на красных: в том, что осталось работать, пока соседняя часть уже сломалась. Спрашивать об этом дешевле всего на ревью.

По материалам: career. Текст переработан редакцией Слогера.

← На главную

Рекламное место — Конец поста
Реклама · Слогер

Комментарии (0)

Войдите, чтобы комментировать.

Пока нет комментариев. Будьте первым.