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 типовых форм |