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

D-09 · Обратимость выката#

  • Версия: 3.2 · 2026-09-22 · по мастер-шаблону v6.0
  • Известно также как: откат, rollback, «можно ли вернуться», совместимость версий при выкате, две версии одновременно
  • Этап: W9 · Observability и эксплуатация · окно сосуществования проверяется на W10
  • Стадия: гринфилд · работающая — у первого выката нет предыдущей версии, и часть дисквалификаторов на нём не срабатывает
  • Профиль: дорого изменить · высокое влияние → полная форма
  • Не решает: какой стратегией выкатывать — rolling, blue-green, канареечный: это OPS-02, и там же четыре правила безопасного выката; как перевезти данные — D-08; что показывать пользователю при отказе — D-06; что обещано внешним потребителям контракта — D-11
  • Не путать с: D-08 — там переезжают данные, здесь выкатывают код и схему. У них общее окно и общая дата; точка невозврата и откат совпадают только пока приёмник данных наш — при чужом приёмнике у переезда точка на первой переданной порции (D-08, раздел 2), у кода на переключении. Дисквалификаторы разные
  • Карточки: OPS-02 стратегии выкатки · DATA-17 миграции схемы без простоя · NET-17 версионирование API и совместимость · NET-18 контракты и схемы · REL-04 фича-флаги и kill switch · REL-05 health checks

Предмет уже, чем кажется по названию. Карточка OPS-02 сравнивает пять стратегий выката и называет четыре правила, делающие выкат безопасным. Пересказывать их здесь незачем.

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

Область решения — одно изменение, а не система. Стратегия выката выбирается однажды; обратимость — свойство каждого изменения в отдельности.


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

Откат существует не тогда, когда в панели есть кнопка, а тогда, когда предыдущая версия кода способна работать с состоянием мира, каким оно станет после выката.

Что входит в «состояние мира»#

Не только схема данных. Всё, что переживает выкат и что предыдущая версия обязана уметь прочитать:

Что Чем опасно Кто замечает
Схема данных Колонка удалена или сужена — старый код падает на записи Сразу
Сообщения, уже лежащие в очередях Написаны новой версией, читать будет старая Через минуты после отката
Содержимое кэшей Формат значения изменился, ключ тот же Через секунды, случайно
Внешние контракты Партнёр уже получил новое поле и на него опирается Через дни, чужой командой (D-11)
Конфигурация и состояние флагов Новая версия записала значение, которого старая не понимает При перезапуске

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

Семь вопросов#

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

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

Оси сравнения. Степень обратимости · цена обеспечения · длительность отката · окно сосуществования · что остаётся необратимым в любом случае · наблюдаемость отличия новой версии от старой.

Шкала главной оси: три степени обратимости#

Не «есть откат» или «нет отката». Три состояния, и только первое даёт то, что обычно имеют в виду.

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

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

Степень Что значит Чем откатываются Цена
Полная Предыдущая версия работает с новым состоянием мира как есть Переключение Платится заранее: изменение делается совместимым, то есть в два шага вместо одного
Условная Предыдущая версия работает, только если откатить и состояние мира Процедура со своим риском и своей длительностью Платится в момент отката, когда времени меньше всего
Отсутствует Предыдущая версия работать не может Ничем Платится выбором другого способа жить с ошибкой

Третья степень — не провал, а законный исход. Иногда сделать изменение обратимым дороже, чем обойтись без отката: тогда нужен не откат, а способ жить с ошибкой — фича-флаг, отключающий поведение без выката; спроектированная деградация (D-06); готовность чинить вперёд с известным временем реакции.

Чего делать нельзя — это иметь третью степень и записанный план отката. Тогда в инциденте команда пробует то, чего не существует, и теряет на этом самые дорогие минуты.

Дисквалификаторы.

  • Состояние мира несовместимо с предыдущей версией, а план отката записан. Отката нет, регламент утверждает обратное. Либо изменение делается двухшаговым, либо обратимость объявляется отсутствующей — но врать себе в регламенте нельзя.
  • Критерий отката не выражен числом [стадия: гринфилд]. «Если станет плохо» означает спор в чате во время инцидента. Нужны величина и базовая линия (OPS-02). На гринфилде базовой линии нет и взять её неоткуда — правило не отсекает вариант, а назначает работу: линия собирается репетицией под нагрузкой, и до неё критерий остаётся прогнозом.
  • Откат ни разу не исполнялся [стадия: гринфилд]. Возможность, которой не пользовались, — предположение. То же правило, что для пути деградации в D-06: механизм, который не исполняется, не работает. У первого выката не исполнялось ничего, и правило срабатывает на все варианты сразу — различать оно перестаёт. Вместо отказа оно требует исполнить откат на репетиции, а не предположить его; отсюда и берётся пометка [проба] в матрице.
  • Необратимое действие выполняется раньше, чем выкат признан удачным. Письмо отправлено, деньги списаны, колонка удалена — откат кода этого не вернёт. Необратимое отодвигается за точку подтверждения или выносится под флаг.
  • Сообщения, написанные новой версией, будут прочитаны старой. Очередь переживает откат. Либо формат сообщения совместим в обе стороны, либо очередь входит в процедуру отката, либо обратимость условная — но не полная.

Первые два отсекают готовность выкатывать, остальные три превращаются в работу до выката.

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

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

Строки — шесть осей раздела 2, колонки — применимые к этому изменению формы раздела 4 плюс нулевой вариант. Отдельная колонка — что записывать в ячейку. Заполняется в проекте; ниже форма и условный пример, числа в нём выдуманы.

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

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

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

Ось Что записывать в ячейку Двухшаговое изменение Фича-флаг Отказаться от отката Нулевой: не обеспечивать
Степень обратимости Степень по строкам состояния мира; итог — худшая Полная по коду, условная по схеме [диф] Полная по поведению, код не откатывается [диф] Отсутствует — по определению формы Неизвестна до инцидента [нет данных]
Цена обеспечения Чем платим заранее и сколько Два выката вместо одного плюс срок между ними [расчёт] Флаг, его снятие и риск, что он останется навсегда [замер] Цена способа жить с ошибкой: сверка, ручной разбор [расчёт] Ноль — до инцидента
Длительность отката От решения откатиться до прежнего состояния Минуты, пока сужающий шаг не сделан [проба] Секунды — снять флаг [проба] Отката нет; меряется длительность способа жить с ошибкой [нет данных]
Окно сосуществования Сколько времени две версии работают одновременно Задано сроком между шагами [расчёт] Задано стратегией выката Не возникает Задано стратегией выката
Что остаётся необратимым Действия, которые не отменяет ничто Сужающий шаг после его выполнения [диф] Ничего, пока флаг не снят Всё, что названо в способе жить с ошибкой Неизвестно [нет данных]
Наблюдаемость отличия версий Чем отличить, какая версия обслужила запрос Версия схемы в записи [диф] Значение флага в журнале [замер] Не помогает: возвращать нечего Нечем [нет данных]

Ось, по которой формы не различаются, вычёркивается — как в любой матрице набора, и только показав это на своём изменении, а не по умолчанию.

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

4. Типовые формы обеспечения обратимости#

Рынка здесь нет; формы не устаревают.

Форма Как устроена Когда верна Чем оборачивается при ошибке Статус у нас
Ничего не делать Изменение совместимо само по себе Добавление поля, нового обработчика, новой очереди Совместимость показалась, а не проверялась заполняется в проекте
Двухшаговое изменение Сначала расширяющее, потом сужающее — разными выкатами и не подряд Схема, формат сообщения, контракт Второй шаг делают в тот же день — тогда это один шаг с лишними хлопотами
Фича-флаг Код выкатан, поведение включается отдельно Поведение можно выключить, не откатывая код Флаги копятся и становятся постоянной конфигурацией (REL-04)
Тёмный запуск Новый код исполняется, результат не показывается Только чтение; нужна уверенность до включения Двойная нагрузка; для записи не годится
Версия в сообщении Потребитель умеет оба формата Очереди глубокие, откат вероятен Потребитель «умеет оба» только на словах, пока не проверено
Отложить необратимое Удаление, отправка, списание — после подтверждения Необратимое отделимо от основного изменения Отложили и забыли: сужающий шаг не делается никогда
Отказаться от отката Обратимость объявляется отсутствующей, строится способ жить с ошибкой Обеспечить откат дороже, чем починить вперёд Объявили молча — команда в инциденте ищет кнопку, которой нет

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

Источники раздела: OPS-02 и DATA-17 · Yan, Chen, Ma и др., arXiv:2504.08865 — конфигурация и операции дают больше инцидентов, чем ошибки в коде · реестр исследования, запись P-OPS-02

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

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

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

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

Необратимое — после подтверждения. Разделить «выкатили» и «подтвердили» стоит одного флага, а сохраняет возможность вернуться.

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

«Нет данных» здесь означает «не посмотрели диф». Всё, что нужно, видно в изменении и в предыдущей версии кода за минуты. Пустая ячейка тут — не нехватка измерений, а несделанная проверка.

6. Запись в ADR#

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

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

Одна степень на всё изменение допустима ровно тогда, когда степени у всех строк совпали, и это надо было проверить, а не предположить.

Связанное решение. Выкат кода почти всегда идёт вместе с миграцией данных: общее окно и общая дата, а точка невозврата и откат общие только пока приёмник данных наш. Записываются они одним ADR — общий контекст, отдельные короткие записи, общие последствия (мастер-шаблон, раздел о связанных решениях).

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

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

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

Источники: Yan, Chen, Ma и др. — An Empirical Study of Production Incidents, arXiv:2504.08865 · DORA — метрики поставки, доля неудачных изменений и время восстановления · 00-workflow.md, шаг W9

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

Версия Дата Изменение
3.2 2026-09-22 MINOR, правка Р9.3·A плана ревизии. Два дисквалификатора получили пометку [стадия: гринфилд], а не один, как значилось в плане: к «откат ни разу не исполнялся» добавился «критерий отката не выражен числом» — базовой линии на первом выкате тоже нет. Оба срабатывают на все варианты сразу, различать перестают и превращаются в работу до; закрываются они одним действием — нагрузочной репетицией с исполненным откатом, откуда и берётся пометка [проба]. Старым ADR перепроверять нечего: U-02 · ADR-0007 вывел оба вручную и пришёл к репетиции сам
3.1 2026-09-22 MINOR, по итогам прогона U-02, правка Р8 плана ревизии. Снят заранее названный кандидат на вычёркивание. Стояло «первый кандидат — окно сосуществования»; на первом применении матрицы вычеркнулась другая ось — наблюдаемость отличия версий, — а окно как раз различало формы. Правило «вычёркивать, только показав на своём изменении» осталось и сработало: оно и спасло матрицу от ошибочной подсказки. Записано, почему кандидата не называют вовсе. Старым ADR перепроверять нечего: единственный ADR по D-09 v3.0 — U-02 · ADR-0007 — вычеркнул верную ось, не послушав подсказки
3.0 2026-09-21 MAJOR, по итогам вычитки Ш1, развилка Ж4. Документ объявлял полную форму и не имел раздела «Матрица оценки»: шесть осей были объявлены, заполнена одна, нулевого варианта и словаря пометок не было вовсе. Прежний раздел 2 «Три степени обратимости» вернулся на своё место — он шкала главной оси, а не замена матрице, ровно как таблица видов обратимости у D-08; матрица добавлена разделом 3. Старым ADR: единственный — ADR-0002 прогона U-01, и перепроверить в нём есть что: поля «Рассмотренные варианты» в нём нет ни в одной из двух записей, а из пяти строк состояния мира до решения дошли три — «сообщения в очередях» и «внешние контракты» пропали между сработавшим дисквалификатором и решением. Принятый ADR не правится; при следующем применении матрица эти две строки закрыть заставит
2.1 2026-09-21 MINOR, по итогам вычитки Ш1. Шапка и раздел 6 больше не называют точку невозврата и откат безусловно общими с D-08: они общие, пока приёмник данных наш, и расходятся при чужом. Старым ADR: единственный — ADR-0002 прогона U-01, где приёмник чужой; его строка об общей точке невозврата опровергнута находкой 2 того же прогона. Принятый ADR не правится — читать его надо вместе с находками
2.0 2026-09-18 MAJOR, по итогам узкого прогона U-01 — первого применения этого документа. Степень обратимости назначается по строкам состояния мира, а не одна на изменение; итоговая равна худшей из них. Документ давал таблицу состояния мира и спрашивал степень в единственном числе — на первом же переходе их оказалось три сразу. Обязательная строка записи стала таблицей, когда степени расходятся. Старым ADR: он один — ADR-0002 того же прогона, написанный по v1.0. Переделывать его не нужно: степень он уже назначает по частям — раздел «Решение: степень обратимости назначается по частям», три строки, худшая «отсутствует», — и сам же отмечает, что v1.0 требовал одну. Перепроверить в нём одно: итоговая степень изменения отдельной строкой не названа, она читается из таблицы. ADR по прежним версиям намеренно не переписываются. (Строка переписана 2026-09-21 по развилке Ж3: прежняя редакция говорила «перепроверять нечего, документ не применялся ни разу» — буквально верно и на вопрос не отвечает.)
1.1 2026-09-18 MINOR: строка «внешние контракты» в состоянии мира получила ссылку на D-11 — обещание совместимости стало отдельным решением. Метод не изменился, перепроверять в принятых ADR нечего
1.0 2026-09-17 Первая версия, второй документ третьей стадии. Собран из записи P-OPS-02 реестра исследования. Предмет сужен против названия: стратегии выката остаются карточкой OPS-02, здесь решается существование отката. Введены понятие «состояние мира» с пятью его составляющими и три степени обратимости; 7 вопросов, 6 осей, 5 дисквалификаторов, 7 типовых форм