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 типовых форм вместо рыночного слоя, местная пометка [продукт], шестой пункт проверки — имя со стороны продукта |