MAATRIX / Блог / Смена стека без остановки бизнеса: стратегия параллельной инфраструктуры

Смена стека без остановки бизнеса: стратегия параллельной инфраструктуры

MAATRIX

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

Почему «большой взрыв» — это лотерея с высокой ставкой

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

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

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

Параллельная инфраструктура: главный принцип

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

Практически это означает три вещи одновременно:

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

Каждый из этих трёх пунктов — отдельный практический паттерн со своими граблями. Разберём их по очереди.

Нужен сервер под эту задачу?

Разверните VPS MAATRIX за пару минут: NVMe, AMD EPYC, root-доступ, локации UK, США, Франция и РФ. Оплата картой РФ и по СБП.

Арендовать сервер

Strangler fig: замена по кускам, а не целиком

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

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

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

На уровне nginx это может быть простой location-based роутинг:

location /api/v2/catalog/ {
    proxy_pass http://new_stack_upstream;
}

location /api/v2/ {
    proxy_pass http://legacy_upstream;
}

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

Двойная запись данных: страховка на время миграции

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

Двойная запись (dual write) означает, что операция записи выполняется и в старую, и в новую базу данных параллельно, пока миграция не завершена и не доказана полностью. Подробно паттерн, его схема и типичные ловушки разобраны в статье про двойную запись в старую и новую базу при переезде — здесь коротко о том, зачем это в контексте смены стека целиком.

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

На практике двойная запись при смене стека целиком (не только базы, но и языка/сервера) реализуется одним из двух способов: синхронно — новый бэкенд при записи в свою базу дополнительно шлёт запрос на запись в API старой системы (просто в реализации, но добавляет задержку и точку отказа), или асинхронно через очередь событий (Kafka, RabbitMQ, Redis Streams) — оба потребителя читают из неё независимо, что устойчивее к временной недоступности одной из сторон, но требует продумать порядок событий и идемпотентность обработки.

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

Канареечный перевод трафика: от малого процента к полному

Когда strangler fig разбил переезд на куски, а двойная запись гарантирует согласованность данных, остаётся вопрос — как физически переводить пользователей на новую систему. Ответ — постепенно, с постоянным контролем состояния, а не переключателем «всё или ничего».

Принцип канареечного перевода трафика (canary release) подробно разобран в статье про canary deploy: основы применительно к обычным деплоям одной версии приложения; при смене всего стека логика та же, только временные рамки шире — счёт идёт не на минуты, а на дни и недели.

Практический план выглядит примерно так:

  1. Небольшой процент реального трафика на новую систему. Начинают с малой доли — достаточно, чтобы увидеть проблему на реальных данных, но не настолько много, чтобы ошибка задела значительную часть клиентов. Конкретная стартовая цифра зависит от масштаба бизнеса — для одних это единицы процентов, для других счёт может идти на конкретных клиентах поимённо.
  2. Мониторинг ключевых метрик на новой системе в сравнении со старой. Ошибки 5xx, время ответа, бизнес-метрики (успешные оплаты, завершённые заказы), логи на предмет исключений, которых не было в старой системе — сравнение важно делать именно относительно старой системы на том же классе трафика.
  3. Постепенное увеличение доли при подтверждённой стабильности. Если метрики новой системы держатся на уровне старой (или лучше) в течение согласованного заранее периода, доля трафика увеличивается поэтапно. Каждый шаг — это снова период наблюдения, а не автоматический безусловный рост.
  4. Готовность откатить долю обратно в любой момент. Механизм перевода трафика должен быть двусторонним: увеличить долю новой системы так же просто, как и уменьшить обратно, без экстренного релиза кода — конфигурационный переключатель, а не хирургическая операция.

Технически распределение трафика реализуется по-разному в зависимости от того, что мигрирует. Для веб-приложения за балансировщиком — веса upstream в nginx или HAProxy, либо feature-флаг по хешу идентификатора пользователя (важно, чтобы один и тот же пользователь стабильно попадал в одну и ту же систему, а не прыгал между ними от запроса к запросу). Для фоновых обработчиков — процент задач, забираемых новым воркер-пулом из общей очереди.

Что мониторить и когда откатываться

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

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

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

Честная цена параллельного пути

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

Что именно стоит дороже на период миграции:

Статья расходовРезкий переездПараллельная инфраструктура
ИнфраструктураОдин комплект серверовДва комплекта одновременно (старый + новый)
КодТолько новая системаПлюс прокси-роутинг, двойная запись, feature-флаги — временный, но реальный объём
КомандаОдин интенсивный рывокРастянутое во времени внимание: мониторинг, сверка данных, поэтапные решения
Срок проектаКороче, если получилось сразуДлиннее, но предсказуемее

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

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

Нужен сервер под эту задачу?

Разверните VPS MAATRIX за пару минут: NVMe, AMD EPYC, root-доступ, локации UK, США, Франция и РФ. Оплата картой РФ и по СБП.

Арендовать сервер

Нужны сами нейросети для контента?

Генерируйте изображения, видео и озвучку нейросетями на falapi.io — десятки моделей в одном окне. Оплата картой РФ и по СБП.

Частые вопросы

Сколько по времени обычно занимает переезд с параллельной инфраструктурой?

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

Обязательно ли использовать все три паттерна сразу — strangler fig, двойную запись и канареечный трафик?

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

Что делать, если старая система физически не может отдавать API для сверки данных с новой?

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

Как понять, что новая система готова к полному переключению, а не просто продержалась пару дней без ошибок?

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

Можно ли сократить срок параллельной работы, если бюджет ограничен?

Можно снизить издержки, сократив количество кусков в strangler fig (крупнее шаги — короче срок, но выше риск на каждом) или сжав период наблюдения на канареечных этапах. Это осознанный компромисс: суженное окно наблюдения означает, что вы увидите меньше реальных сценариев нагрузки до того, как отрежете путь назад.

Обсудить статью, задать вопрос или начать новую тему

Есть вопрос по этой статье, идея для обсуждения или просто хотите поделиться опытом? Сообщество MAATRIX ждёт. Для общения, пожалуйста, зарегистрируйтесь в нашем личном кабинете.

Перейти в сообщество →