Перейти к содержанию

D-06 · Деградация при отказе и перегрузке#

  • Версия: 3.2 · 2026-09-22 · по мастер-шаблону v6.3
  • Известно также как: graceful degradation, поведение при отказе зависимости, «что показывать, когда данных нет», деградация функциональности
  • Этап: W7 · Надёжность и деградация · класс важности приходит из W0, запас мощности — из W5
  • Стадия: гринфилд · работающая — на гринфилде свой замер недоступен, работает [замер сторонний]
  • Профиль: дорого изменить · высокое влияние → полная форма
  • Не решает: как устроены механизмы — таймауты, автоматический выключатель, сброс нагрузки, фича-флаги: это карточки блока REL; сколько мощности резервировать — W5; где взять суррогат — D-01, а нужно ли под него отдельное хранилище — D-07; что обещано пользователю и чем это измеряется — D-10; можно ли вместо деградации откатиться — D-09
  • Не путать с: D-03 — там решают, чем снять нагрузку, здесь — что отдать, когда снять не удалось
  • Карточки: REL-01 таймауты и повторы · REL-02 circuit breaker и bulkhead · REL-03 load shedding · REL-04 graceful degradation · REL-05 health checks · REL-10 chaos engineering · REL-11 метастабильные отказы · REL-12 серый отказ

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

Область решения — одна функция, а не система. «Деградация в системе» — не решение. Решение принимается для функции, у которой есть зависимость, способная отказать отдельно от неё. Функции одного класса важности решаются вместе, одним применением.

Документ собран из реестра пилота И0 — восьми проблем, собранных из внешних источников. Семь из них вошли сюда вопросами и дисквалификаторами; предметом стала восьмая.


1. Что выяснить#

Семь вопросов. Первые четыре — о функции, последние три — о том, сработает ли деградация вообще.

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

Третий вопрос решает больше остальных вместе взятых#

Деградация возможна ровно там, где инвариант закрывается не этой функцией. На прогоне E-01 схему зала разрешили отдавать грубо — «в этом секторе есть места» вместо поимённой занятости, — потому что точность всё равно проверяется транзакцией резерва на следующем шаге. Инвариант «нельзя продать одно место дважды» держит не экран, а резерв.

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

Что считать одной функцией#

Признак Одно применение Разные применения
Класс важности Совпадает Различается
Инвариант Один и тот же Разные
Зависимость Одна и та же Разные — отказывают независимо

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

2. Оси и дисквалификаторы#

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

Ось стоимости владения здесь не факультативна. У пути деградации есть постоянная цена — его надо регулярно исполнять, иначе он перестаёт работать (см. дисквалификатор ниже). Вариант, у которого цена построения низкая, а цена владения высокая, — самый частый способ получить механизм, существующий только на бумаге.

Дисквалификаторы — проверяются до сравнения. Четыре из пяти пришли прямо из реестра пилота.

  • Деградация нарушает инвариант. Отдать устаревший остаток в момент списания — не деградация, а ошибка с отложенным проявлением. Сюда же относится молчаливая подмена там, где пользователь принимает решение по этим данным: молчание превращает деградацию в обман.
  • Путь деградации не исполняется регулярно [стадия: гринфилд]. Механизм, срабатывающий раз в год, не работает, когда понадобится: неиспользуемая ветка отказывает сама (Google SRE, гл. 22). Либо регулярное исполнение — на части трафика, по расписанию, в учениях (REL-10), — либо вариант отвергнут. На гринфилде исполнять ещё нечего, и правило срабатывает на любой вариант, то есть перестаёт различать. Читать его там надо как обязательство, а не как наблюдение: вопрос звучит «какая доля трафика пойдёт этим путём после запуска», и ответ становится строкой решения, а не причиной отказа. На прогоне U-02 так и вышло — 2 % подач идут отложенным путём даже при исправном сервисе.
  • Суррогат добывается через отказавшую зависимость. Пересборка, обходной путь, ретраи «на всякий случай» — если деградация увеличивает нагрузку на то, что уже не справляется, это не деградация, а усиление. Самый распространённый поддерживающий эффект: усиление ретраями встречается более чем в половине изученных метастабильных отказов (Huang et al., OSDI '22).
  • Система не умеет заметить отказ. Если сигнал о здоровье приходит от самой зависимости о себе, при сером отказе деградация просто не включится: процесс исправен, отвечает на проверку и не обслуживает потребителя (Huang et al., HotOS '17). Дисквалифицирован здесь не вариант, а способ обнаружения: пока здоровье меряется не со стороны потребителя, любой вариант из матрицы останется невключённым.
  • У режима нет выхода. Не назначены условие снятия и владелец — режим станет постоянным, и через месяц никто не вспомнит, что было иначе.
  • Режим случается регулярно, и это известно замером — нашим или владельца зависимости. Тогда он не деградация, а нормальный режим работы, и описывать его надо как норму: в требованиях W0 и в контракте, а не формой деградации. Дисквалифицирован не вариант, а применение документа: отвод обязателен и делается на входе.

Чей это замер — решает не наша система, а та, что отказывает. Регулярность режима принадлежит тому, чей отказ мы обходим. Когда зависимость чужая — удостоверяющий центр, поставщик, орган с расписанием, — своего замера у нас не будет никогда: точка измерения не наша. Зато у владельца он есть и часто опубликован: объявленные обязательства, разборы инцидентов, регламент работ. Такой факт помечается [замер сторонний] (мастер-шаблон) и включает дисквалификатор наравне со своим. Мастер-шаблон требует, чтобы документ сказал об этом словами: молчание читается как «не принимает», и до этой версии D-06 молчал.

Отсюда три состояния, а не два:

Что есть Дисквалификатор Что записывается
Наш замер регулярности Срабатывает Отвод на входе, режим описывается как норма
Замер владельца зависимости Срабатывает так же То же, плюс дата публикации и кто её объявил
Замера нет ни у кого Не срабатывает — но проверка не пройдена Строка в ADR: регулярность не установлена ничем; единственная защита — условие пересмотра из раздела 7

Третье состояние — не формальность. Ячейка «нет замера» блокирует проверку, а не только остаётся пустой: условие пересмотра срабатывает после первого неожиданно частого включения, то есть ценой инцидента, тогда как отвод стоил бы одной строки на входе. Отдельно стоит назвать ошибку, ради которой эта версия и написана: «нашей системы ещё нет» не означает «замера нет». Чужая система существует и тогда, когда нашей ещё нет, и на гринфилде её публикация — единственный твёрдый факт, доступный этому дисквалификатору.

Последний дисквалификатор парен условию пересмотра из раздела 7 — «режим включался чаще, чем ожидалось». То срабатывает после наблюдения, этот — до, когда частота известна заранее. Нужны оба: на прогоне E-03 частота была замерена на входе, отвода не нашлось, и верный ответ получен пройденными семью разделами вместо одного.

Отвод не означает бесполезности. В том же прогоне документ, отведя себя, дал разделение на два применения с разными инвариантами, асимметрию двух операций, отсечение сегодняшнего поведения системы и владельца разбора. Правильный порядок — сначала отвести, потом воспользоваться разделами 1 и 2 как опросником для нормы.

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

Что нашёл дисквалификатор Что с вариантом Что обязано стоять в записи
Несовместимость предмета — обещанного этим вариантом не дать никакой работой Отвергнут Причина отказа
Дефект исполнения — вариант годится, но в нынешнем виде не работает Остаётся, с работой до Что построить прежде, чем режим включат
Неприменимость документа Отвод на входе Куда ушло решение

Один и тот же дисквалификатор попадает в разные роды на разных кейсах — и первый чаще остальных. Инвариант бывает нарушен существом ответа: отдать устаревший остаток в момент списания работой не лечится, вариант отвергнут. А бывает нарушен формулировкой: квитанция говорит «принято» там, где подпись ещё не проверена. Тогда отвергается текст, а не режим, и деградация остаётся — с другой квитанцией. Так и вышло на прогоне U-02.

Почему это правило, а не список. До v3.1 здесь стояло: «два последних дисквалификатора обычно не отвергают вариант, а добавляют работу» — обобщение одного прогона (E-03) и соседнего документа (D-03). На U-02 работу добавили четыре из шести, включая первый. Список из двух был обобщением одного кейса, список из четырёх стал бы обобщением двух; род переживёт оба. Само правило документ уже говорил дважды и порознь — у четвёртого дисквалификатора («дисквалифицирован не вариант, а способ обнаружения») и у шестого («не вариант, а применение документа»). Оно было в тексте и не было названо.

Следствие для записи. У каждого сработавшего дисквалификатора в ADR стоит не только «сработал», но и что из этого следует: отказ или работа до. Без этого ячейка не говорит главного — остался вариант в игре или выбыл. ADR-0006 прогона U-02 завёл пометку «Работа до:» сам, не имея её в документе: верный признак, что правила не хватало.

3. Матрица оценки#

Колонки — формы деградации из раздела 4, применимые к этой функции. В ячейках факты с пометкой источника, не баллы.

Словарь пометок. [требования] — из инвариантов и обещаний W0 · [продукт] — ответ владельца продукта, полученный явно · [замер] — измерено на работающей системе · [расчёт] · [нет данных]. Пометка [продукт] здесь заменяет рыночную: главный источник фактов — не рынок и не история, а человек, отвечающий за обещание.

Пример условный. Числа и функция выдуманы, форма настоящая.

Ось Что записывать в ячейку Полный ответ (нулевой) Устаревшее с пометкой Грубый ответ Явный отказ
Сохранность инварианта Какой инвариант и чем он закрыт при этой форме Держится функцией [требования] Нарушается: решение принимается по старым данным [требования] Держится следующим шагом — транзакцией резерва [требования] Держится: ответа нет [требования]
Что видит пользователь Дословно то, что появится на экране Норму Данные плюс отметку «на 14:32» «В секторе есть места» без поимённой схемы Сообщение с объяснением и сроком
Понимает ли он, что это деградация Да / нет — и как именно узнаёт Неприменимо Да, по отметке [продукт] Нет — выглядит как другой режим отображения [продукт] Да
Нагрузка на зависимость Вырастет, упадёт или не изменится Растёт: ретраи [расчёт] Падает до нуля: копия своя [расчёт] Падает: агрегат дешевле [замер] Падает до нуля
Стоимость построения Что надо написать 0 Хранение копии и отметки времени Агрегат и второй путь чтения Текст и его показ
Стоимость владения Чем платим постоянно и как путь исполняется 0 Копия обязана обновляться и сверяться Путь обязан исполняться регулярно — иначе отказывает сам Низкая
Обратимость Условие снятия и владелец Неприменимо Зависимость отвечает N минут; снимает дежурный [продукт] То же То же

Нулевой вариант — обязательная колонка. «Деградации нет» означает не «мы не подумали», а «функция критична, и вместо суррогата покупается запас мощности». Это законный исход, и он дороже остальных — поэтому его считают явно, а не подразумевают.

Строка «понимает ли пользователь» — не вежливость, а граница дисквалификатора. Если он не понимает и при этом принимает решение по этим данным, вариант отсекается первым дисквалификатором. Если не понимает и никакого решения не принимает — вариант законен, и молчание правильно.

4. Типовые формы деградации#

Рынка здесь нет: деградацию не покупают. Место рыночного слоя занимают формы — они не устаревают, поэтому даты съёмки у раздела нет.

Форма Что отдаём Когда верна Чем оборачивается при ошибке Статус у нас
Деградации нет Правильный ответ всегда Функция критична, инвариант держит только она, запас мощности куплен Отказ всё равно случится, но без плана — по худшему сценарию заполняется в проекте
Устаревшее с пометкой Последнее известное плюс отметка времени Устарелость безвредна, и пользователь способен её учесть Отметку не замечают: она есть, а решение принимается как по свежим данным
Устаревшее молча Последнее известное Устарелость не влияет ни на одно решение пользователя Молчание превращает деградацию в обман; чинится дороже, чем создавалось
Грубый ответ Меньше точности или меньше объёма Точность нужна не здесь, а на следующем шаге, и там она проверяется Пользователь строит план на грубых данных и упирается шагом позже
Функция исчезает Ничего, но без ошибки Функция необязательна, её отсутствие не выглядит поломкой Пользователь ищет то, чего нет, и считает это багом
Явный отказ Ошибку с объяснением и сроком Суррогата нет, инвариант важнее доступности Видимые ошибки и обращения в поддержку — зато честно
Отложить Приём заявки и выполнение позже Немедленный ответ не требуется Обещание, которое надо выполнить: нужна очередь, её мониторинг и уведомление

Колонка «статус у нас» заполняется теми же тремя значениями, что рыночный слой: используем · не используем, потому что… · не рассматривали.

Формы не исключают друг друга. Обычная комбинация — грубый ответ для основной массы плюс явный отказ для операций, где инвариант держится этой же функцией. Разделяет их не форма, а класс важности (REL-03).

Источники раздела: Google SRE Book, гл. 22 «Addressing Cascading Failures» · Google SRE Book — Handling Overload · Michael Nygard, «Release It!» (Fail Fast, Circuit Breaker) · реестр пилота И0

5. Эвристики#

Начинать с инварианта, а не с механизма. Первый вопрос — что функция обязана гарантировать и держит ли она эту гарантию одна. Если гарантия закрывается на следующем шаге сценария, деградация почти всегда возможна и почти всегда дешева. Если только здесь — выбор сужается до «отказать честно» или «купить запас».

Молчаливая деградация — решение, а не умолчание. Прежде чем показывать старое без пометки, назовите решение, которое пользователь принимает по этим данным. Не назвали — молчать можно. Назвали — нельзя.

Деградация, которая не исполняется, не существует. Путь, включающийся раз в год, отказывает в тот самый раз. Регулярное исполнение — часть решения, а не улучшение к нему.

Суррогат не добывается через отказавшую зависимость. Проверка в одну строку: нарисуйте путь получения суррогата и найдите в нём отказавший узел. Нашли — это не деградация.

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

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

Не решать за всю систему. Функции одного класса важности и одного инварианта решаются вместе; разные — порознь. Одна форма деградации на всю систему — признак того, что её не выбирали.

6. Запись в ADR#

Поле ADR Чем заполняется
Контекст Функция, её зависимость, обещание, действующее сейчас, и инвариант — с указанием, чем он закрыт
Дисквалификаторы Какие формы отсечены и почему; отдельно — что из отсечённого превратилось в обязательную работу
Рассмотренные варианты Матрица раздела 3 снимком, включая нулевой вариант
Решение Форма деградации дословно тем, что увидит пользователь, плюс условие включения
Обоснование Почему инвариант выдерживает эту форму; кто со стороны продукта подтвердил обещание
Последствия Что придётся построить и как путь будет исполняться регулярно; кто снимает режим
Условия пересмотра Раздел 7
Метод D-06 v<версия> · шаблон ADR v<версия> — рыночного снимка нет, формы не устаревают

Обязательная строка записи — как этот путь будет исполняться. Не «планируем учения», а частота и способ. Без неё решение считается непринятым: дисквалификатор о неисполняемом пути срабатывает на само отсутствие этой строки.

7. Условия пересмотра#

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

Проверка перед тем, как считать решение принятым — пять пунктов в шаблоне. Шестой, местный: есть ли имя человека со стороны продукта, подтвердившего обещание. Решение без него принято не до конца — как бы аккуратно ни была заполнена матрица.

Источники: Google SRE Book, гл. 22 · Google SRE Book — Handling Overload · Bronson et al. — Metastable Failures in Distributed Systems, HotOS '21 · Huang et al. — Metastable Failures in the Wild, OSDI '22 · Huang et al. — Gray Failure, HotOS '17 · 00-workflow.md, шаг W7

История версий#

Версия Дата Изменение
3.2 2026-09-22 MINOR, правка Р9.3·A плана ревизии. Второй дисквалификатор получил пометку [стадия: гринфилд]: исполнять ещё нечего, правило срабатывает на любой вариант и перестаёт различать — читается как обязательство, а не наблюдение, и превращается в работу до. План указывал на другой дисквалификатор, шестой; он закрыт раньше — правкой Р4·B в v3.0, где замер стал считаться чужим. Проверено при внесении. Старым ADR перепроверять нечего
3.1 2026-09-22 MINOR, по итогам прогона U-02, правка Р6·A плана ревизии. «Добавляет работу» — свойство рода находки, а не позиции в списке. Роды названы: несовместимость предмета отвергает, дефект исполнения оставляет вариант с работой до, неприменимость документа даёт отвод. Один дисквалификатор попадает в разные роды на разных кейсах: первый отвергает при нарушении инварианта существом и добавляет работу при нарушении формулировкой. Снят прежний список из двух последних — обобщение одного прогона; на U-02 работу добавили четыре из шести. В запись добавлено требование: у сработавшего дисквалификатора указывается отказ или работа до. Класс — MINOR, и он держится на одном слове. Прежняя редакция говорила «два последних обычно не отвергают» — наблюдение о частом режиме, а не запрет остальным четырём вести себя так же. Поэтому ни один прежний исход не был предписан иначе, и ось с дисквалификаторами не изменились. Будь там «только два последних», правка была бы MAJOR. Старым ADR: перепроверять исходы нечего, но записи неполны — в E-03 · ADR-0004 и U-02 · ADR-0006 у сработавших дисквалификаторов род не назван; второй вывел пометку «работа до» вручную
3.0 2026-09-22 MAJOR, по итогам прогона U-02, правка Р4·B плана ревизии. Шестой дисквалификатор расширен: замер считается чужой. Прежняя формулировка читалась как «замер наш», а регулярность режима принадлежит владельцу отказывающей зависимости — у него замер есть и часто опубликован. Введены три состояния вместо двух: свой замер, замер владельца (срабатывает так же), замера нет ни у кого (проверка не пройдена, а не «не сработал»). Названа ошибка, породившая правку: «нашей системы ещё нет» не означает «замера нет». Пометка [замер сторонний] пришла из мастер-шаблона v6.3, и строка совместимости обновлена именно поэтому — документ опирается на словарь, которого в v6.0 не было. Старым ADR: перепроверить один. В U-02 · ADR-0006 шестой дисквалификатор помечен «не смог сработать: замера нет, системы нет» — при этой версии такая ячейка незаконна: на её месте обязан стоять либо сработавший дисквалификатор, либо строка о том, что владелец зависимости не публикует ничего. Исхода прогона это не отменяет — центр вымышлен и публикаций у него нет, — но проверка из непройденной стала возможной. E-03 · ADR-0004 не затронут: замер там был наш
2.0 2026-09-18 MAJOR, по итогам прогона E-03. Добавлен шестой дисквалификатор: режим, случающийся регулярно и замеренный, — норма, а не деградация, и отвод делается на входе. Он парен условию пересмотра, которое до сих пор срабатывало только после наблюдения. Старым ADR перепроверять нечего, и по неожиданной причине: их нет. Проверено при внесении — единственный ADR, написанный по D-06, это E-03 · ADR-0004, и он написан в тот же день, что эта правка. До него документ не применялся ни разу: деградация в E-01 · ADR-0004 была названа обязательной и не принята — документа тогда не существовало
1.0 2026-09-17 Первая версия. Собрана из реестра пилота И0, а не из пробелов набора: семь записей реестра вошли вопросами и дисквалификаторами, восьмая стала предметом. 7 вопросов, 6 осей, 5 дисквалификаторов, 7 типовых форм вместо рыночного слоя, местная пометка [продукт], шестой пункт проверки — имя со стороны продукта