Содержание

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

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

Почему релизы вызывают простой?

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

Типичные источники простоя:

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

Чем отличаются blue-green, canary и feature flags?

Blue-green, canary и feature flags по-разному снижают риск: первый позволяет мгновенно переключиться и откатиться, второй ограничивает число пользователей, которых затронет ошибка, третий отделяет выкладку кода от включения функции.

Подход Как работает Плюсы Что требует
Последовательная замена Экземпляры обновляются по одному Просто, встроено в оркестраторы Несколько экземпляров, совместимость версий
Blue-green Два окружения, трафик переключается целиком Мгновенный откат Двойные ресурсы на время релиза
Canary Новая версия сначала на небольшой доле трафика Ошибка затрагивает немногих Маршрутизация трафика и метрики
Feature flags Код выкладывается выключенным, функция включается отдельно Включение и отключение без релиза Дисциплина удаления старых флагов

Серый монитор на рабочем столе Фото: Unsplash

Как менять базу данных без простоя?

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

Пример: переименование столбца phone в phone_number.

Релиз 1 — расширение
  добавить столбец phone_number (nullable)
  код пишет в оба столбца, читает из phone
  фоновая задача копирует старые значения

Релиз 2 — переключение
  код читает и пишет phone_number

Релиз 3 — сужение
  удалить столбец phone

Правила безопасных миграций

  1. Не удалять и не переименовывать столбцы в том же релизе, где меняется код.
  2. Новые столбцы добавлять допускающими пустые значения или со значением по умолчанию.
  3. Индексы на больших таблицах создавать без блокировки записи — о том, как, в статье индексы в PostgreSQL.
  4. Большие переносы данных выполнять фоновыми задачами частями.
  5. Проверять миграции на копии продакшен-объёма данных.

Как использовать feature flags?

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

if (Feature::active('new-checkout', $user)) {
    return $this->newCheckout($cart);
}

return $this->legacyCheckout($cart);

Что важно:

  • включать функцию постепенно и следить за метриками и ошибками;
  • удалять флаг и старую ветку кода после полного включения — иначе код обрастает условиями;
  • не использовать флаги как замену правам доступа и настройкам.

С чего начать небольшой команде?

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

План:

  • автоматизировать выкладку в конвейере — подробнее в статье CI/CD на GitHub Actions;
  • запускать не меньше двух экземпляров приложения и заменять их по одному;
  • добавить эндпоинт проверки готовности — балансировщик не шлёт трафик на неготовый экземпляр;
  • писать миграции по схеме «расширить — перенести — сузить»;
  • подготовить быстрый откат и проверять его.

Коротко

  • Простой при релизе вызывают остановка приложения, несовместимые миграции и ошибки на всех пользователях.
  • Последовательная замена — база; blue-green даёт мгновенный откат, canary ограничивает охват ошибки.
  • Feature flags отделяют выкладку кода от включения функции.
  • Меняйте базу по схеме «расширить — перенести — сузить», а не одним шагом.
  • Начните с автоматической выкладки, двух экземпляров, проверки готовности и совместимых миграций.

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

  • Нужен ли Kubernetes для релизов без простоя?

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

  • Как откатить релиз с миграцией базы?

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

  • Сколько feature flags можно держать одновременно?

    Столько, сколько команда успевает отслеживать. Каждый флаг должен иметь владельца и срок удаления, иначе код обрастает условиями, которые никто не решается убрать.