Производственные системы не должны останавливаться. Финансовая платформа, обрабатывающая транзакции в 2 часа ночи, система медицинских записей, обслуживающая врачей в разных часовых поясах, логистическое приложение, отслеживающее отправления через континенты: ни одна из них не имеет временного окна для проведения рефакторинга. Тем не менее, все они накапливают технический долг, несут в себе архитектурные решения, принятые в условиях ранее существовавших ограничений, и в конечном итоге требуют структурных изменений для сохранения работоспособности, масштабируемости и безопасности. Рефакторинг без простоев — это дисциплина, которая разрешает это противоречие: развитие работающей системы без прерывания предоставляемых ею услуг.
Модернизация без простоев
Реорганизуйте ваши приложения в процессе производства с контролем и точностью корпоративного уровня
Подробнее SMART TS XLПроблема не только техническая. Она носит организационный и архитектурный характер. Рефакторинг системы, которую нельзя отключить, требует иной ментальной модели, чем рефакторинг системы в процессе разработки: каждое изменение должно быть обратно совместимым до тех пор, пока это не перестанет быть таковым, каждый структурный переход должен быть обратимым, каждая проверка должна проводиться на реальном трафике, а не на синтетических тестах. Методы, позволяющие это осуществить, включая сине-зеленое развертывание, переключение функций, паттерн «душитель-фига», миграции баз данных с расширением и сокращением, а также идемпотентные событийно-ориентированные архитектуры, хорошо описаны по отдельности. Менее часто рассматривается вопрос о том, как они работают вместе в качестве согласованной стратегии для устойчивых и безопасных структурных изменений в системах, которые должны обслуживать пользователей на протяжении всего процесса.
Как должна выглядеть ваша архитектура для внесения изменений, исключающих простои.
Наиболее распространенный вопрос, который задают команды при внедрении рефакторинга без простоев, касается архитектуры: что нужно изменить в структуре системы, прежде чем можно будет начать сам рефакторинг? Ответ кроется не в каком-то одном шаблоне, а в наборе структурных свойств, которыми должна обладать система, прежде чем рефакторинг в рабочем режиме станет безопасным. Понимание этих свойств является необходимым условием для всего остального, описанного в этом руководстве.
Первое свойство — это независимая развертываемость. Каждый компонент, подлежащий рефакторингу, должен быть развертываемым без необходимости одновременного развертывания его зависимостей. Если изменение сервиса A требует одновременного изменения сервисов B и C во избежание сбоев, то развертывание A без простоя структурно невозможно: три сервиса фактически представляют собой единую единицу развертывания независимо от того, в скольких репозиториях они находятся. Независимая развертываемость требует обратно совместимых интерфейсов, версионированных контрактов и устранения требований к скоординированному развертыванию между сервисами.
Второе свойство — обратимость. Любое развертывание, изменяющее поведение в реальном времени, должно быть обратимым в течение нескольких минут, а не часов. Обратимость — это не просто сохранение старого бинарного файла. Она требует, чтобы состояние базы данных, состояние кэша, состояние сессии и любое состояние внешней системы, измененное новой версией, были совместимы со старой версией. Если новая версия записывает данные в формате, который старая версия не может прочитать, то развертывание по определению необратимо, и отсутствие простоев невозможно, поскольку любой откат приведет к ошибкам.
Третье свойство — это наблюдаемые переходы состояний. Рефакторинг, в ходе которого поведение перемещается из одного пути кода в другой без наблюдаемых метрик на обоих путях, осуществляется вслепую. Команда не может знать, успешен переход или нет, не может выявлять регрессии на ранних стадиях и не может принимать решения на основе данных о том, когда ускорить или остановить миграцию. Наблюдаемость должна быть обеспечена до начала рефакторинга, а не добавлена после возникновения проблемы. Как показано в контексте поэтапная рефакторизация и технический долгСтруктурная прозрачность того, что делает код и от чего он зависит, является основой для планирования любых изменений, которые не могут потерпеть неудачу в производственной среде.
Сине-зеленое развертывание: базовая модель
Сине-зеленое развертывание — это основополагающий принцип релизов без простоев. Существуют две идентичные производственные среды: синяя среда, обслуживающая реальный трафик, и зеленая среда, получающая новую версию. Новая версия развертывается, тестируется и проверяется в зеленой среде, в то время как синяя среда продолжает обслуживать пользователей без перерыва. После проверки в зеленой среде трафик атомарно переключается на синюю среду. Откат — это обратный процесс: переключение трафика обратно на синюю среду, которая остается доступной на протяжении всего процесса.
Схема кажется простой. Сложность заключается в уровне базы данных. Когда обе среды должны читать и записывать данные в одну и ту же базу данных, схема базы данных должна быть совместима с обеими версиями одновременно. Миграция, которая удаляет столбец, переименовывает поле или изменяет тип данных, ломает старую среду в момент выполнения. Именно поэтому сине-зеленое развертывание неотделимо от схемы миграции с расширением и сокращением, описанной в разделе базы данных этого руководства.
Методы поэтапного внедрения и предварительного запуска новых продуктов
В рамках канареечного развертывания расширяется модель «сине-зеленого» подхода, при которой определенный процент трафика перенаправляется на новую версию, а не весь трафик сразу. Канареечное развертывание может начинаться с одного процента пользователей, затем отслеживаются показатели ошибок, задержки и бизнес-метрики для этой группы, после чего процент постепенно увеличивается: пять, двадцать, пятьдесят, сто. На каждом этапе автоматические контрольные точки проверяют, не ухудшились ли ключевые показатели сверх заданных пороговых значений. Если контрольная точка не проходит проверку, развертывание останавливается, и процент канареечного развертывания снижается до нуля.
Методы поэтапного развертывания добавляют логику таргетинга к этому процессу. Вместо маршрутизации только по процентному соотношению, трафик может быть сегментирован по группам пользователей, географическим регионам, уровням подписки или характеристикам сессий. Это позволяет проверить новую версию на конкретной группе пользователей, которая испытывает наибольшую нагрузку, прежде чем эта группа будет полностью переведена на новую версию. Ключевым требованием является то, что инфраструктура маршрутизации, будь то балансировщик нагрузки, API-шлюз или сервисная сеть, должна поддерживать необходимую для развертывания детализацию таргетинга.
Метрики, определяющие критерии проверки (canary gates), должны быть определены до начала развертывания. Допустимыми критериями проверки являются частота ошибок, задержка p99, время выполнения запросов к базе данных и специфические для бизнеса метрики, такие как коэффициент конверсии или процент успешных платежей. Пороговые значения должны быть откалиброваны относительно базового уровня, измеренного на существующей версии при сопоставимой нагрузке, а не относительно теоретических целевых показателей. Развертывание, которое проходит проверку при 2% трафика, но не проходит при 20%, не было проверено: канареечный образец был слишком мал, чтобы быть репрезентативным. Правильное поэтапное развертывание требует достаточного объема трафика на каждом этапе для получения статистически значимого сравнения.
Переключатели функций и аварийные выключатели
Функции переключения режимов работы позволяют отделить развертывание кода от активации поведения. Переработанный фрагмент кода развертывается в неактивном состоянии, управляемом переключателем, который определяет, какие пользователи или запросы будут выполнять новую логику. Переключатель можно включать постепенно, настраивать под конкретные группы пользователей или отменять мгновенно без повторного развертывания. Это делает функции переключения режимов работы основным механизмом для миграции бизнес-логики без простоев, в отличие от изменений инфраструктуры, где более уместны сине-зеленые или канареечные шаблоны.
«Аварийные выключатели» — это защитный аналог переключателей функций: переключатели, цель которых не в том, чтобы включить новое поведение, а в том, чтобы мгновенно отключить его в случае некорректной работы. Аварийный выключатель для переработанного расчета платежей, нового потока аутентификации или заменяющего уровня доступа к данным предоставляет дежурному инженеру путь восстановления одним действием, не требующий развертывания, отката базы данных или межкомандной координации. Аварийный выключатель должен быть настроен в системе, которая позволяет активировать его через вызов API, консоль управления флагами функций или автоматизированную интеграцию оповещений, чтобы задержка срабатывания составляла секунды, а не минуты.
Проблема поддержания работоспособности переключателей является реальной операционной проблемой. Переключатели, которые никогда не очищаются, накапливаются в коде, что затрудняет понимание потока управления и создает неявные зависимости между состоянием переключателя и состоянием данных. У каждого переключателя должен быть задокументированный владелец, запланированная дата истечения срока действия и задача по очистке. Технический долг, связанный с переключателями, так же реален, как и любой другой вид технического долга, и он накапливается быстрее, потому что переключатели, как правило, защищают наиболее активно изменяющиеся части системы.
Рефакторинг базы данных без простоя
Изменения в базе данных — самая сложная часть рефакторинга без простоев, поскольку базы данных являются состоятельными, общими и медленно модифицируются в больших масштабах. Приложение можно развернуть и откатить за считанные минуты. Миграция базы данных, изменяющая таблицу с сотнями миллионов строк, может занять часы, её трудно отменить после фиксации изменений, и она удерживает блокировки, которые блокируют чтение и запись на протяжении всего процесса. Правильный рефакторинг базы данных требует иного подхода, чем рефакторинг кода приложения, и большинство команд обнаруживают это при первой попытке изменить схему в работающей таблице с высокой нагрузкой.
Основной принцип заключается в том, что каждое изменение в базе данных должно быть обратно совместимо с предыдущей версией приложения до тех пор, пока предыдущая версия не будет больше использоваться. Это звучит очевидно, но имеет неочевидные последствия. Переименование столбца требует добавления нового имени в качестве псевдонима или дубликата, прежде чем можно будет удалить старое имя. Изменение типа столбца требует параллельного заполнения теневого столбца нового типа, прежде чем можно будет удалить старый столбец. Удаление таблицы требует подтверждения того, что ни одна развернутая версия приложения не считывает данные из нее. Каждая из этих операций представляет собой многоэтапный процесс, распределенный по нескольким развертываниям, а не единую миграцию, выполняемую один раз. Как обсуждалось в более широком контексте... Рефакторинг COBOL в контексте устаревших структур данныхЗадача развития структур данных, используемых совместно в нескольких программах и системах без скоординированного перехода, является одной из определяющих трудностей рефакторинга в масштабах предприятия.
Модель расширения-сокращения
Паттерн «расширение-контрактирование» формализует многоэтапный подход к изменению схемы. На этапе расширения новые элементы схемы добавляются аддитивно: новый столбец рядом со старым, новая таблица рядом со старой, новый индекс рядом со старым. Приложение обновляется для записи как в старую, так и в новую структуру, но продолжает читать из старой структуры. Данные не теряются, существующие запросы не ломаются, и старая версия приложения продолжает функционировать, поскольку старые элементы схемы по-прежнему присутствуют.
На этапе сокращения, который происходит в отдельном развертывании после полного развертывания и проверки новой версии, старые элементы схемы удаляются. К этому моменту ни одна работающая версия приложения от них не зависит. Удаление безопасно, поскольку оно было проверено путем наблюдения, а не предположено на этапе планирования.
Паттерн «расширение-сокращение» требует дисциплинированного подхода к последовательности развертывания. Миграция базы данных, добавляющая новый столбец, должна быть развернута до версии приложения, которая в него записывает данные. Миграция базы данных, удаляющая старый столбец, должна быть развернута после вывода из эксплуатации всех версий приложения, которые считывают из него данные. Эти требования к последовательности должны быть закодированы в конвейере развертывания, чтобы миграции не могли быть применены в неправильном порядке.
Инструменты для рефакторинга устаревших конвейеров обработки данных без переписывания кода.
Устаревшие конвейеры обработки данных, особенно те, которые построены на основе пакетной обработки, инструментов ETL или перемещения данных с использованием мэйнфреймов, представляют собой особую проблему: они непрерывно преобразуют и перемещают данные, их нельзя остановить на время миграции, и они часто настолько плохо документированы, что полный объем их работы становится известен только после возникновения ошибки. Рефакторинг этих конвейеров без полной переработки требует инструментов, которые могут отслеживать текущие действия конвейера, проверять, что переработанная версия выдает эквивалентный результат, и позволять осуществлять переход поэтапно, а не резко.
Инструмент отслеживания изменений данных (CDC) является наиболее широко применимым инструментом для рефакторинга конвейеров обработки данных в режиме реального времени. CDC фиксирует каждую операцию записи в исходную таблицу в виде потока событий, что позволяет передавать данные как старому, так и новому конвейеру-заменителю из одного и того же источника без внесения изменений ни в один из них. Старый конвейер продолжает работу, новый конвейер запускается параллельно с тем же потоком событий, и результаты сравниваются. Выявленные расхождения указывают на логику преобразования, которая не была корректно переработана. После подтверждения четности старый конвейер выводится из эксплуатации.
Инструменты миграции схем, такие как Liquibase и Flyway, предоставляют версионированные, последовательные миграции, которые можно применять инкрементально и откатывать при использовании принципа расширения-сокращения. Они отслеживают, какие миграции были применены к каждой среде, и предотвращают применение миграций в неправильном порядке. Для устаревших конвейеров, работающих на мэйнфреймах или хранилищах данных на основе VSAM, эквивалентное управление осуществляется через Расширение JCL и управление наборами данных Это позволяет контролировать доступ программ к данным во время перехода, гарантируя, что ни старая, ни новая программа не будут работать с несовместимой структурой набора данных.
Как модернизировать устаревшие базы данных без простоя
Специфические задачи модернизации устаревшей базы данных, перехода от схемы DB2 на мэйнфрейме к реляционной базе данных в облачной среде, миграции от файловой структуры VSAM к реляционной схеме или объединения нескольких устаревших баз данных в новое унифицированное хранилище, требуют последовательного применения всех вышеперечисленных методов в течение длительного периода времени.
Наиболее эффективный подход: сначала выполняется проверка четности при чтении, затем достигается проверка четности при записи, затем происходит миграция операций чтения, затем — миграции операций записи, после чего устаревшее хранилище данных выводится из эксплуатации. Проверка четности при чтении означает, что новое хранилище содержит все данные, которые содержало старое хранилище, и может обрабатывать все запросы приложения. Проверка четности при записи означает, что каждая операция записи, выполняемая приложением в старом хранилище, также применяется к новому хранилищу, либо посредством двойной записи в приложении, либо посредством репликации CDC. После подтверждения обоих условий четности под производственной нагрузкой операции чтения могут быть перенесены в новое хранилище (с проверкой выходных данных), затем операции записи — в новое хранилище, после чего устаревшее хранилище данных может быть выведено из эксплуатации.
На каждом этапе этой последовательности работа сервиса не прерывается. На каждом этапе предыдущее состояние может быть восстановлено путем перемещения операций чтения или записи обратно в предыдущее хранилище. Длительность каждого этапа определяется степенью достоверности, полученной в результате проверки, а не фиксированной календарной датой.
Инструменты для рефакторинга устаревших систем без переписывания кода.
Переписывание устаревшей системы с нуля почти всегда обходится дороже и сопряжено с большими рисками, чем ее поэтапная рефакторизация. Полное переписывание требует одновременного поддержания старой системы в рабочем состоянии и создания замены с сопоставимой функциональностью, управления разрывом в функциональности между двумя системами и выполнения перехода, который по сути представляет собой развертывание совершенно другой системы без простоев. Большинство организаций, пытающихся осуществить полное переписывание, обнаруживают на полпути, что старая система содержала функции, которые они не документировали, которые замена пока не воспроизводит, и от которых зависят пользователи.
Поэтапная рефакторизация с использованием подходящих инструментов позволяет избежать этой ловушки, делая старую систему понятной до внесения изменений. Отправной точкой является структурный анализ: понимание того, что делает каждый компонент существующей системы, что от него зависит и от чего зависит он сам. Этот анализ невозможно провести, просто читая документацию (которая обычно отсутствует или неточна для устаревших систем) или вручную читая код в больших масштабах. Для этого требуются автоматизированные инструменты, которые анализируют существующий код, строят граф зависимостей и делают этот граф доступным для запросов. Как описано в контексте управление проблемами интеграции устаревших системПервым шагом в любой программе рефакторинга устаревших систем является обеспечение структурной прозрачности, которой нет ни в одном поддерживаемом человеком артефакте.
Узор «Душитель инжира» для монолитов
Паттерн «душитель-фига» — это доминирующая архитектурная стратегия для поэтапной замены монолита без полной переработки или перехода на новую архитектуру. Новая функциональность создается в виде независимых сервисов параллельно с монолитом. Уровень маршрутизации, обычно API-шлюз или обратный прокси, перехватывает входящие запросы и направляет их либо к монолиту, либо к новому сервису в соответствии с правилами маршрутизации. Монолит продолжает обслуживать весь трафик, который еще не был перенесен. Новый сервис обрабатывает только тот трафик, который явно направлен к нему.
Со временем добавляются новые правила маршрутизации. Все больше путей направляется к новым сервисам. Монолит обрабатывает все меньшую часть общего трафика. В конце концов, монолит ничего не обрабатывает и может быть выведен из эксплуатации. Ни одно отдельное развертывание в этом процессе не является достаточно масштабным, чтобы представлять существенный риск. Каждое изменение правила маршрутизации можно протестировать и отменить индивидуально. Метод «душителя» — это не метод быстрой трансформации: это метод безопасной трансформации в течение недель, месяцев или лет, в зависимости от сложности системы, подвергающейся «душению».
Критически важным требованием к реализации паттерна «дровосечка» является то, что уровень маршрутизации должен быть отделен как от монолита, так и от новых сервисов. Уровень маршрутизации, встроенный в монолит, не может перенаправлять трафик от монолита. Прокси-сервер должен располагаться перед обоими компонентами, способный направлять трафик к любому из них на основе конфигурации, которую можно изменять без модификации монолита или нового сервиса.
Преобразование устаревших API в облачные сервисы без простоев
Миграция устаревшего API на облачную альтернативу — это специфическое применение паттерна «душитель-фига» с дополнительными ограничениями: у устаревшего API могут быть потребители, которых нельзя обновлять одновременно, контракт API должен сохраняться на протяжении всего перехода, а облачная альтернатива может иметь другие характеристики производительности, которые неожиданным образом влияют на потребителей.
Стандартный подход заключается в развертывании облачной замены за тем же контрактом API, что и устаревший API, перенаправлении определенного процента трафика на замену с использованием канареечных методов, проверке соответствия выходных данных для этого процента трафика и постепенном увеличении перенаправляемого процента. Потребителям не нужно ничего менять во время этого перехода, поскольку контракт API сохраняется. Уровень маршрутизации обрабатывает переход прозрачно.
Переход от основных интеграций к промежуточным API без простоев, который отображается в данных Search Console для этой статьи как запрос с высокой интенсивностью намерений, — это именно такой сценарий: момент обновления маршрутизирующего уровня для направления 100% трафика в новую систему и вывода из эксплуатации устаревшего API. Этот переход никогда не должен быть единичным атомарным событием. Он должен быть заключительным этапом постепенного развертывания, в ходе которого новая система уже прошла проверку при постоянно растущих объемах трафика. К моменту окончательного перехода новая система уже обработала весь объем трафика; переход просто удаляет резервный путь, который больше не нужен.
Идемпотентность, повторные попытки и переключение на резервный сервер в рефакторизованных системах
Рефакторинг системы, использующей событийно-ориентированную архитектуру, очереди сообщений или распределенные вызовы сервисов, порождает класс проблем, которые не решаются шаблонами, ориентированными исключительно на развертывание: что происходит с выполняющимися операциями при переходе сервиса со старой версии на новую? События, опубликованные в старой версии, могут поступать в обработчик, работающий в новой версии. Запросы, инициированные через старый API, могут поступать в обработчик, который уже был рефакторизован в соответствии с новой внутренней структурой. Транзакции, частично завершенные в рамках старой логики, могут потребовать завершения или компенсации в рамках новой логики.
Решение всех этих проблем — идемпотентность: проектирование каждой операции таким образом, чтобы она давала один и тот же результат независимо от того, выполняется она один раз или несколько раз. Идемпотентный обработчик, получающий дублирующееся событие во время перехода развертывания, выдает тот же результат, что и обработчик, получающий событие ровно один раз. Идемпотентная операция записи, которая воспроизводится в рамках отката, приводит к тому же состоянию базы данных, что и исходная запись. Идемпотентность — это не просто вопрос рефакторинга: это общее свойство отказоустойчивых распределенных систем. Но именно во время переходов рефакторинга ее отсутствие приводит к наиболее заметным сбоям.
Добавление повторных попыток и переключения на резервный сервер без масштабной рефакторизации.
Один из наиболее часто задаваемых вопросов в Search Console для этой статьи — как добавить возможности повторной попытки и переключения на резервный сервер в существующее приложение, особенно в приложение на Rails или аналогичном фреймворке, без проведения масштабной рефакторизации. Ответ заключается в том, что повторную попытку и переключение на резервный сервер можно добавить на уровне инфраструктуры, не изменяя отдельные реализации сервисов.
На уровне инфраструктуры сервисная сеть, такая как Istio или Linkerd, может быть настроена на автоматическое повторение неудачных запросов до заданного количества попыток, с экспоненциальной задержкой и дрожанием для предотвращения эффекта «громоподобного потока». Это не требует изменений в коде приложения, поскольку механизм повторных попыток реализован в прокси-сервере sidecar, который перехватывает все входящие и исходящие запросы. Аналогичным образом может быть реализовано переключение провайдера на резервный: если основной провайдер возвращает ошибку выше порогового значения, сеть перенаправляет последующие запросы к резервному провайдеру до тех пор, пока основной не восстановится.
На уровне приложения, когда повторных попыток на уровне инфраструктуры недостаточно, поскольку логика повторных попыток должна учитывать состояние бизнес-процессов, можно внедрить легковесную библиотеку повторных попыток или очередь заданий на границе между приложением и внешними зависимостями без внутренней реструктуризации приложения. Ключевым моментом является изоляция логики повторных попыток и отказоустойчивости на уровне интеграции, а не распределение её по всему уровню бизнес-логики. Это делает поведение повторных попыток видимым, тестируемым и настраиваемым без изменения основной структуры приложения. Как обсуждалось в контексте Практики гибкого рефакторингаВнедрение шаблонов обеспечения надежности на уровне инфраструктуры до рефакторинга бизнес-логики уменьшает площадь, которую необходимо проверять после каждого изменения.
Идемпотентность в событийно-ориентированных архитектурах с использованием Redis Streams
В архитектурах с низкой задержкой, управляемых событиями и использующих Redis Streams или аналогичные технологии, при рефакторинге возникает специфическая проблема идемпотентности: группы потребителей могут обрабатывать события с разной скоростью, потребитель, считывающий события в новой версии, может уже обработать события, которые старая версия не обработала, а операции воспроизведения или восстановления могут доставлять одно и то же событие несколько раз обработчикам, которые не были предназначены для обработки дубликатов.
Стандартный подход заключается в присвоении уникального идентификатора каждому событию в момент публикации и отслеживании обработанных идентификаторов событий в постоянном хранилище. Перед обработкой события обработчик проверяет, был ли идентификатор уже обработан. Если да, событие подтверждается и отбрасывается без повторной обработки. Если нет, событие обрабатывается, и идентификатор записывается. Эта логика дедупликации должна быть атомарной: если обработчик обрабатывает событие, но терпит неудачу до записи идентификатора, событие будет повторно обработано при следующей доставке. Использование атомарных операций Redis или транзакционных операций записи для записи идентификатора в рамках операции обработки предотвращает это состояние гонки.
В процессе рефакторинга, при котором изменяется логика обработки событий, идентификаторы идемпотентности предоставляют дополнительное преимущество: они позволяют воспроизводить поток событий с использованием новой логики обработки событий и сравнивать выходные данные с записанными выходными данными старой логики обработки событий, что обеспечивает сравнительное тестирование без ознакомления пользователей с новой логикой.
Автоматизация рефакторинга в конвейерах CI/CD
Принципиальность рефакторинга без простоев не может быть обеспечена ручными процессами. Каждое развертывание в программе с нулевым временем простоя требует последовательности проверок: предварительные проверки совместимости новой версии с текущим состоянием базы данных, оценка «канареечного шлюза» при каждом увеличении процента трафика, автоматическое сравнение результатов работы старого и нового участков кода, а также проверка после развертывания на предмет ухудшения ключевых показателей. Выполнение этих шагов вручную для каждого изменения не является операционно устойчивым и приводит к человеческим ошибкам в наиболее критических точках процесса.
Конвейер CI/CD для рефакторинга без простоев — это не просто конвейер сборки и развертывания. Это конвейер валидации: последовательность автоматизированных этапов, которые должны быть пройдены до того, как изменение перейдет к следующему этапу развертывания. Каждый этап представляет собой конкретный, измеримый критерий. Непрохождение этапа останавливает конвейер и запускает оповещение. Прохождение всех этапов автоматически переводит развертывание на следующий этап. Как описано в более широком обсуждении... Практики CI/CD для мэйнфреймовых и корпоративных средОсновное требование заключается в том, что конвейер должен обеспечивать соблюдение одной и той же дисциплины развертывания для каждого изменения, независимо от его размера, и что это соблюдение должно быть автоматизировано, а не зависеть от внимательности отдельных инженеров.
Стадии конвейера для живого рефакторинга
Контрольные точки этапов — это точки проверки, которые развертывание должно пройти, прежде чем перейти к следующему этапу. Для конвейера рефакторинга с нулевым временем простоя минимальный набор контрольных точек выглядит следующим образом.
Перед развертыванием: проверка совместимости схемы подтверждает обратную совместимость миграции базы данных с текущей версией приложения, автоматизированные контрактные тесты проверяют совместимость ответов API новой версии с контрактом предыдущей версии, а статический анализ зависимостей подтверждает, что никакие зависимости, введенные новой версией, не будут конфликтовать с зависимостями, необходимыми в существующей среде.
После развертывания в тестовой среде: сравнение частоты ошибок между тестовым и базовым трафиком, сравнение задержки на уровнях p50, p95 и p99, сравнение бизнес-метрик для любых метрик, на которые влияет измененный путь выполнения кода, и минимальное окно наблюдения, в течение которого тестовая среда должна оставаться стабильной, прежде чем будет увеличен процент трафика.
После полного развертывания: набор регрессионных тестов на производственных конечных точках, проверки согласованности базы данных, подтверждающие сохранение согласованности при миграции с двойной записью или расширением контракта, а также подтверждение того, что предыдущий артефакт развертывания остается доступным для отката.
Рефакторинг и обеспечение соблюдения нормативных требований
Рефакторинг, обусловленный требованиями соответствия, вводит дополнительное ограничение, которое должны обеспечивать контрольные точки конвейера: каждое изменение должно быть явно согласовано с применимыми нормативными требованиями или требованиями организационной политики. В регулируемых отраслях это означает, что конвейер развертывания должен создавать журнал аудита, показывающий, что было изменено, когда было развернуто, какая проверка была выполнена и кто это утвердил. Автоматизированные контрольные точки конвейера, которые записывают собственное выполнение, включая состояние входных данных, критерии контрольной точки и результат «пройдено/не пройдено», предоставляют этот журнал аудита без необходимости ручной работы по документированию.
Интеллектуальные платформы рефакторинга с возможностями обеспечения контроля на уровне всей команды, которые отображаются в данных Search Console для этой статьи, — это инструменты, интегрирующие проверку соответствия в рабочий процесс рефакторинга: они гарантируют, что шаблоны рефакторинга применяются согласованно во всех командах, что устаревшие интерфейсы не будут повторно использоваться, и что структурные изменения соответствуют архитектурным стандартам, определенным на организационном уровне. Эти возможности выходят за рамки того, что предоставляет только конвейер CI/CD, поскольку они требуют понимания семантики изменяемого кода, а не только того, компилируется ли он и проходит ли тесты.
Рефакторинг мэйнфреймов и CICS без простоев
В средах мэйнфреймов рефакторинг с нулевым временем простоя представляет собой наиболее требовательный вариант, поскольку ограничения носят структурный, а не настраиваемый характер. Программу транзакции CICS нельзя заменить, развернув новый образ контейнера и переключив балансировщик нагрузки. Замена программы в CICS требует команды NEWCOPY или PHASEIN, которая загружает новую версию программы в память. NEWCOPY немедленно заменяет старую версию, затрагивая все транзакции, начавшиеся после выполнения команды. PHASEIN ожидает завершения всех активных транзакций, использующих старую версию, прежде чем заменить её, обеспечивая более плавный переход для длительных транзакций.
Ни один из этих механизмов не обеспечивает мгновенного отката. Если в новой версии программы обнаружен дефект, для возврата к старой версии требуется повторный запуск NEWCOPY или PHASEIN с предыдущим загрузочным модулем. Это требует сохранения предыдущего загрузочного модуля в библиотеке загрузок, а также документирования, отработки и выполнения процедуры отката дежурной группой без привлечения первоначального разработчика.
Использование общих файлов VSAM добавляет еще одно ограничение. Несколько транзакций CICS и пакетных программ могут одновременно обращаться к одному и тому же файлу VSAM. Структурное изменение структуры файла, например, добавление или расширение сегмента записи, требует, чтобы все программы, обращающиеся к файлу, были обновлены до или одновременно с изменением структуры, либо чтобы файл поддерживал несколько форматов записей в течение переходного периода. Это эквивалент схемы «расширение-сокращение» в мэйнфреймах: новая структура должна быть совместима со старыми программами во время перехода, а старые программы должны быть обновлены до того, как старая структура будет выведена из эксплуатации. Контролируемое расширение структур данных и параметров доступа программ — это механизм, который делает возможным такое совместимое сосуществование без замены файла.
Стратегии устранения пакетного окна
Традиционная пакетная обработка на мэйнфреймах предполагает наличие пакетного окна: периода, в течение которого обработка онлайн-транзакций приостанавливается, пакетные задания выполняются без конфликтов, а полученные данные готовы к следующему периоду онлайн-обработки. Устранение пакетного окна, необходимого для работы без простоев, означает перепроектирование модели пакетной обработки таким образом, чтобы пакетные задания могли выполняться одновременно с онлайн-транзакциями без повреждения общих данных.
Стандартные подходы включают блокировку ресурсов на уровне записей, а не файлов, обработку мини-пакетов на основе событий, которая обрабатывает небольшие рабочие нагрузки непрерывно, а не большие — периодически, и базы данных с репликами для чтения, которые обслуживают пакетные отчеты, не конкурируя с обработкой транзакций в режиме реального времени за доступ на запись. Каждый из этих подходов требует изменений как в программах, так и в шаблонах доступа к данным, но ни один из них не требует сохранения окна пакетной обработки во время перехода: сам переход может быть поэтапным с использованием того же подхода двойной проверки, который используется для любой другой рефакторизации работающей системы.
Рефакторинг программы на COBOL с использованием анализа влияния
Для безопасной рефакторизации программы на COBOL необходимо заранее знать, какие именно другие программы её вызывают, какие файлы копирования она использует совместно с другими программами, какие наборы данных она читает и записывает, и какие системы зависят от создаваемых ею данных. Без этих структурных знаний любое изменение программы несёт в себе неизвестный риск: рефакторизованная программа может нарушить работу вызывающей функции, которая не была идентифицирована, выдавать результаты в формате, который система, использующая её, не сможет обработать, или изменить общую структуру данных таким образом, что это повлияет на другие программы, использующие тот же файл копирования.
Автоматизированный анализ влияния решает эту проблему, создавая полный граф зависимостей программы COBOL до начала рефакторинга. Граф показывает каждый вызывающий код, каждую общую копибук-книгу, каждый доступ к набору данных и каждого нижестоящего потребителя, организованных по типу связи и конкретному местоположению ссылки. Затем план рефакторинга формируется на основе графа влияния: программы, вызывающие измененную программу, должны быть протестированы на новой версии, измененные копибук-книги должны быть проверены на всех программах, которые их включают, а измененные структуры наборов данных должны быть проверены на всех программах, которые обращаются к тем же наборам данных. Как описано в решения для анализа воздействия Благодаря возможностям, которые предоставляет IN-COM, эта функция отличает программу рефакторинга, которая обнаруживает свои последствия после развертывания, от той, которая количественно оценивает их до внедрения.
Проверка, откат и наблюдаемость
Рефакторинг без простоев обеспечивает непрерывный вывод результатов, который необходимо постоянно отслеживать. Мониторинг — это не проверка работоспособности задним числом: это активный контроль на каждом этапе процесса развертывания, и это основной механизм, с помощью которого проблемы выявляются достаточно рано, чтобы предотвратить негативное воздействие на пользователей.
Модель верификации для рефакторинга без простоев состоит из трех уровней. Первый — это синтетический мониторинг: скриптовые транзакции, имитирующие поведение пользователя и непрерывно запускающиеся в производственной среде, подтверждают успешное завершение ключевых потоков. Синтетические мониторы выявляют сбои, возникающие в определенных участках кода, которые реальные пользователи могут не использовать в периоды низкой нагрузки, и обеспечивают базовый уровень поведения, с которым можно сравнивать результаты канареечного тестирования.
Второй уровень — это дифференциальный мониторинг: сравнение метрик в реальном времени между тестовым развертыванием и базовым развертыванием, включая частоту ошибок, распределение задержек, бизнес-метрики и потребление ресурсов. Дифференциальный мониторинг не требует абсолютных пороговых значений: он требует относительного сравнения. Тестовое развертывание, демонстрирующее на два процента более высокую частоту ошибок по сравнению с базовым развертыванием, является проблемой независимо от того, превышает ли абсолютная частота ошибок какой-либо индивидуально определенный порог.
Третий уровень — это проверка согласованности данных. При любом рефакторинге, включающем двойную запись, миграцию схем или параллельное выполнение системы, необходимо постоянно проверять согласованность данных между старым и новым представлениями. Сравнение контрольных сумм, сравнение количества записей и выборочные запросы, проверяющие значения конкретных полей на соответствие ожидаемым преобразованиям, — все это способствует уверенности в корректной работе уровня данных во время перехода. Как было рассмотрено в контексте Что такое анализ воздействия и почему он важен?Способность проверять последствия изменений на соответствие определенному набору ожиданий отличает структурированный рефакторинг от спекулятивных изменений.
Механизмы мгновенного отката
План отката, выполнение которого занимает тридцать минут, не является планом отката для системы с нулевым временем простоя. К моменту его завершения пользователи уже получат тридцать минут работы в режиме пониженного качества. Для мгновенного отката необходимо, чтобы каждое развертывание изначально проектировалось с учетом возможности отмены, а не устанавливалось задним числом, когда возникает проблема.
При развертывании приложений мгновенный откат означает сохранение доступного, предварительно подготовленного и указывающего на то же состояние базы данных артефакта предыдущего развертывания. Для возврата к предыдущей версии достаточно переключения трафика через балансировщик нагрузки или изменение правил API-шлюза. Это достижимо, если состояние базы данных обратно совместимо с предыдущей версией, что гарантируется принципом расширения-контракта на уровне миграции базы данных.
При миграции баз данных мгновенный откат требует, чтобы каждая миграция, выполненная на этапе расширения, была обратимой без потери данных. Столбец, добавленный на этапе расширения, может быть удален при откате. Столбец, измененный необратимым образом, не может быть восстановлен без резервной копии. Именно поэтому необратимые изменения схемы, такие как удаление столбцов, изменение типов несовместимым образом или снижение точности, никогда не следует применять до тех пор, пока новая версия не будет полностью развернута и проверена, а старая версия не будет полностью выведена из эксплуатации.
Как SMART TS XL Поддерживает программы рефакторинга с нулевым временем простоя.
SMART TS XL Эта платформа решает проблему структурной прозрачности, лежащую в основе каждой неудачной попытки рефакторинга без простоев: команды пытаются рефакторить работающие системы, не имея полного представления о том, что эти системы содержат, от чего что зависит и каковы будут последствия каждого запланированного изменения. Платформа загружает исходный код со всех языков и платформ в среде, включая COBOL, JCL, Java, .NET, Python, JavaScript и SQL, и создает единую перекрестную модель, которая представляет структурные взаимосвязи всей системы.
Перед внесением изменений в процесс рефакторинга, SMART TS XLВозможности анализа влияния позволяют проследить граф зависимостей от изменяемого компонента наружу, через каждый вызывающий компонент, каждую общую структуру данных, каждого нижестоящего потребителя и каждую программу, которая будет затронута изменением. В результате получается конкретный, перечисленный список последствий, организованный по степени серьезности и компоненту, а не общая оценка риска. Именно этот список позволяет правильно спланировать последовательность рефакторинга без простоев: зная, какие потребители необходимо обновить до развертывания измененного компонента, какие миграции баз данных необходимо выполнить до развертывания каких приложений и какие нижестоящие системы необходимо проверить перед выводом из эксплуатации старой версии.
SMART TS XLВозможности визуализации кода позволяют командам, не имеющим глубоких знаний о каждом слое системы, подвергающейся рефакторингу, легко ориентироваться в графе зависимостей. Архитекторы могут увидеть, как компоненты связаны между собой, прежде чем перепроектировать структуру соединений. Разработчики могут увидеть, что вызывает функцию, прежде чем изменять её сигнатуру. Команды эксплуатации могут увидеть, чем используется набор данных, прежде чем изменять его структуру. Такая прозрачность является необходимым условием для структурированной, обратимой, поэтапной программы рефакторинга, необходимой для работы без простоев.
Рефакторинг без простоев как непрерывная практика
Описанные в этом руководстве методы не являются разовыми вмешательствами. Это оперативный словарь организации разработчиков, которая решила рассматривать производственные системы как постоянно развивающиеся, а не периодически заменяемые. Сине-зеленые развертывания, канареечные релизы, переключения функций, миграции с расширением и сокращением, извлечение «душителя», идемпотентная обработка событий и контролируемые конвейером этапы развертывания — это не аварийные процедуры: это стандартные операционные процедуры команды, которая безопасно и с высокой частотой внедряет структурные изменения.
Для достижения этого состояния необходимы инвестиции в инструменты, инфраструктуру и организационные процессы, выходящие за рамки любой отдельной инициативы по рефакторингу. Инструменты должны поддерживать независимое развертывание, наблюдаемые переходы состояний и мгновенный откат. Инфраструктура должна поддерживать разделение трафика, сине-зеленые среды и синхронизацию данных на основе CDC. Организационные процессы должны включать анализ влияния до развертывания, дифференциальный мониторинг после развертывания и регулярные репетиции отката, подтверждающие работоспособность пути отката в реалистичных условиях.
Организации, которые вкладывают средства в этот процесс, обнаруживают, что стоимость каждого изменения снижается по мере совершенствования практики: каждая последующая рефакторизация менее рискованна, чем предыдущая, поскольку уже существует необходимая инфраструктура, команда выработала знание того, какие пороговые значения подходят для каких изменений, и накопила структурные знания в таких инструментах, как [название инструмента]. SMART TS XL Это позволяет более точно определить область действия каждого запланированного изменения, чем предыдущего. Цель рефакторинга без простоев состоит не в безопасном внесении одного изменения, а в безопасном и непрерывном внесении каждого изменения без необходимости запрашивать у пользователей согласие на проведение технического обслуживания.