Политика Обновления Axelix

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

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

Начиная с Axelix 1.1

Данная политика обновления Axelix была введена, начиная с Axelix 1.1 и с тех пор применяется для всех minor релизов внутри одного major. Каждая миграция между major версиями Axelix-а покрыта собственным, отдельным гайдом.

Окно совместимости

Вся процедура опирается на одну гарантию:

Axelix Master поддерживает стартеры последних 4 минорных релизов, включая свой собственный.

Например, Master 1.4.x поддерживает сервисы на стартерах от 1.1.x до 1.4.x. Сервис на стартере 1.0.x находится вне окна Master 1.4.x, и его работоспособность с ним больше не гарантируется:

Окно совместимости Axelix Master 1.4 поддерживает сервисы, чей стартер попадает в окно 1.1–1.4. Сервис, оставшийся на стартере 1.0, находится вне окна и больше не поддерживается.

Это гарантированный минимум: на практике мы можем поддерживать и более широкий диапазон, но обещаем как минимум эти 4 минора и не будем сужать окно в пределах мажорной версии.

Из окна следуют два правила:

  • Master обновляется первым. Окно направлено назад: более новый Master поддерживает более старые стартеры, но не наоборот. Не запускайте стартер, версия которого новее вашего Master.
  • Стартер и плагин двигаются вместе. В пределах одного сервиса стартер и плагин сборки должны иметь одинаковую версию major.minor — бампайте их одним изменением. Окно действует между Master и вашими сервисами, а не внутри сервиса.

Частота релизов

Axelix ориентируется примерно на 7–9 минорных релизов в календарный год — новый минор примерно раз в 1.5 месяца — и один мажорный локстеп-релиз в год.

В сочетании с окном совместимости это превращает абстрактное окно в конкретный запас времени: поскольку Master поддерживает стартеры последних 4 миноров, сервис, остающийся внутри окна, достаточно обновлять примерно раз в полгода. А так как клиентские компоненты сознательно держатся "тупыми", такое обновление в большинстве случаев тривиально — бамп версии зависимости и передеплой.

Процедура обновления

1. Узнайте, до какой версии можно обновиться

Откройте Administration → Upgrading в UI Master. Там показана самая высокая версия Master, до которой можно обновиться, не вытолкнув ни один сервис за окно совместимости, — она вычисляется из самой старой версии стартера, которую Master наблюдал по вашему флоту.

Поскольку окно — чистая арифметика, Master вычисляет этот вердикт полностью локально: без обращений к каким-либо release page, без доступа в интернет. В закрытых контурах это работает точно так же.

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

2. Обновите Axelix Master

Обновите Master на каждом окружении — сначала dev, затем staging, затем production. Master — это standalone-развёртывание (JAR, Docker-образ или Helm-чарт), так что этот шаг целиком в руках платформенной команды и не затрагивает ни один сервис. Механика этого шага — остановка, бэкап, накат и откат — описана в секции «Обновление самого Axelix Master» ниже.

Ваши сервисы продолжают работать всё это время: они внутри окна — в этом и был смысл шага 1.

3. Дайте командам обновить свои сервисы

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

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

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

4. Наблюдайте, как флот догоняет

Страница Upgrading показывает распределение версий стартеров по флоту. После обновления Master наблюдайте, как оно смещается к новой версии, — и сразу видьте, какие сервисы отстают, включая сервисы, созданные из устаревших шаблонов со старой версией стартера.

Обновление самого Axelix Master

Обновления Master — forward-only: двигаться можно только к более новой версии, и процедуры даунгрейда сознательно не существует. Это стандартная модель для stateful control plane, и причина — база данных. У Master она есть, миграции схемы применяются к ней автоматически при старте, и мы проектируем эти миграции простыми, а не обратимыми — миграцию, перестраивающую таблицу, обычно можно отменить, только выбросив данные. Поэтому вместо того, чтобы делать вид, будто даунгрейд работает, мы вкладываемся в надёжный путь назад: бэкап базы данных, снятый по ходу обновления, который восстанавливается, если что-то пошло не так.

Forward-only не означает "по одному минору за раз". Обновление с любой более старой версии на любую более новую в пределах одного мажора поддерживается одним прыжком — перейти с 1.1 сразу на 1.4 это нормально. При старте новый Master находит все миграции, которых ваша база ещё не видела, и применяет всю цепочку по порядку; охватывает она один минор или три — разницы нет. Единственное исключение — переход через границу мажорной версии: каждый мажорный релиз выходит с собственным гайдом миграции — следуйте ему, а не этой процедуре.

И ещё одно, что нужно знать перед шагами: это процедура типа stop-the-world. Она начинается с остановки работающего Master, поэтому в ней есть короткое окно даунтайма — обычно несколько минут, — в течение которого UI и API Master недоступны. Ваши сервисы, впрочем, его даже не заметят.

Что происходит с вашими сервисами во время даунтайма

Ничего — так задумано. Стартер внутри каждого сервиса отчитывается перед Master периодически, heartbeat'ами, а не один раз при старте. Пока Master лежит, heartbeat'ы просто остаются без ответа: сервис продолжает обслуживать свой трафик, ничего не буферизирует и повторяет попытки по своему обычному расписанию. Как только новый Master поднялся, ближайший heartbeat каждого сервиса регистрирует его заново с нуля — и весь флот собирается сам в течение одного heartbeat-интервала. Поэтому шаги ниже ни разу не упоминают ваши сервисы: не нужны ни координация с командами, ни draining, ни перезапуски — с точки зрения сервиса обновление Master неотличимо от короткого сетевого сбоя.

По шагам

  1. Остановите работающий Master. Как бы он ни был развёрнут — Kubernetes Deployment, контейнер, обычный JAR — погасите его полностью. Здесь открывается окно даунтайма.

  2. Сделайте бэкап базы данных. Используйте штатные средства вашего движка: дамп для PostgreSQL или MySQL, копию файла базы для SQLite. Снимайте бэкап после остановки Master — в базу уже никто не пишет, и снапшот гарантированно консистентен. Не пропускайте этот шаг даже при рутинном на вид обновлении: этот бэкап и есть процедура отката.

  3. Запустите новую версию Master. При старте она автоматически применит все недостающие миграции базы и начнёт обслуживать трафик. Дайте ей закончить — не перезапускайте и не убивайте Master, пока применяются миграции.

  4. Проверьте. UI доступен и показывает новую версию, и в течение одного heartbeat-интервала ваши сервисы появляются сами. Если флот выглядит полным и сервисы успешно перерегистрировались — можно считать, что обновление Axelix Master завершено.

Откат

Если по какой-либо причине новая версия ведёт себя плохо, путь назад — бэкап из шага 2:

  1. Остановите новый Master.
  2. Восстановите базу из бэкапа.
  3. Запустите ту версию, с которой обновлялись.

Всё, что записалось в базу между бэкапом и откатом, теряется — и для Master эта потеря пренебрежимо мала, так задумано.

Реестр сервисов самовосстанавливается: он заново собирается из heartbeat'ов за один интервал. То, что само не восстанавливается — пользователи, роли, настройки, — редко меняется за такое короткое окно. И помните: откат — это передышка, а не пункт назначения; forward-only означает, что долгосрочный путь всегда ведёт вверх, так что если обновление у вас не удалось — пожалуйста, заведите issue: настоящий фикс приедет уже в более новой версии.

Инварианты

  • Никогда не запускайте две разные версии Master против одной базы данных одновременно. Новая версия перестраивает схему в момент старта, а старая не рассчитана на то, чтобы пережить эту перестройку — совместимость старого кода с будущими схемами это ровно та сложность, от которой forward-only нас избавляет. В Kubernetes это означает, что Deployment Master должен использовать стратегию Recreate: стратегия по умолчанию RollingUpdate ненадолго запускает старый и новый под бок о бок — даже при одной реплике — и этот перехлёст приходится ровно на момент применения миграций.

  • Короткий даунтайм Master ожидаем. Мы сознательно не обещаем zero-downtime обновлений Master: это потребовало бы обратимых, многофазных миграций и высокодоступного Master, а мы предпочитаем держать простыми и продукт, и эту процедуру. В окне даунтайма недоступны только UI и API самого Master; ваши сервисы продолжают работать как ни в чём не бывало.

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

Сервисы, которые отстали

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

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

Обновление мажорной версии

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

На этой странице