Dev48
ЯЗЫК
  • О нас
  • Услуги
  • Индустрии
  • Технологии
  • Статьи
  • Контакты
Забронировать звонок
    Главная/Статьи/Kanarskie razvertyvaniya obnovlenie modeley v production bez prostoev
Dev48

© 2026 · All rights reserved.

Канарские развертывания: обновление моделей в production без простоев

Источник: Together AI

Канарские развертывания: обновление моделей в production без простоев

Источник: Together AI

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

29 сентября 2026 г.•Обновлено: 29 сентября 2026 г.

Замена моделей — обычная практика

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

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

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

Как работают развертывания

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

  • Канарская: трафик перемещается в соответствии с заданными вами процентными соотношениями (например, 10% → 50% → 100%; стандартная лестница — 5% → 25% → 50% → 100%), с периодом ожидания и опциональными проверками метрик между шагами.
  • Сине-зеленая: один контролируемый переход с 0% на 100%. Это можно рассматривать как одношаговое канарское развертывание.
  • Постепенная: замена «на месте» по принципу «реплика за репликой», сохраняющая общую емкость. Лучше всего подходит при ограниченных ресурсах, особенно для изменений конфигурации той же модели, не требующих плавного наращивания трафика.

Вот что происходит на каждом канарском шаге:

Мы выбрали этот порядок намеренно; каждый пункт предотвращает определенный класс инцидентов:

  • Целевой деплой масштабируется до того, как начнет перемещаться трафик. Отсутствие емкости для нового деплоя означает отсутствие перенаправленных запросов: сначала развертывание приостанавливается.
  • Проверка работоспособности запускается до переключения трафика. Трафик попадает только на те реплики, чей движок загружен и отвечает, а не просто запущен.
  • Ожидание распространения происходит между переключением и освобождением ресурсов. Кэши маршрутизации сходятся до того, как какая-либо часть емкости источника будет удалена.
  • Ресурсы источника освобождаются после перенаправления трафика. Емкость опережает трафик при росте; трафик опережает емкость при снижении.
  • Период ожидания и проверка метрик происходят до того, как шаг будет записан как завершенный. Шаг с регрессом никогда не отмечается как пройденный.

Через API или консоль развертывание создается в состоянии PENDING и ничего не делает до тех пор, пока вы явно его не запустите (команда rollout в CLI создает и запускает его за один шаг). Этот двухэтапный процесс создания и запуска сделан намеренно, чтобы вы могли создать развертывание, проверить его (или попросить коллегу проверить) и запустить тогда, когда вы действительно наблюдаете за процессом.

Два состояния на диаграмме выше заслуживают отдельного упоминания:

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

Здесь нет конечного состояния FAILED, оставляющего трафик в подвешенном состоянии: развертывание завершается либо как COMPLETED (целевой деплой обслуживает запросы), либо как CANCELED (распределение замораживается на текущем этапе, и вы запускаете развертывание в обратном порядке для возврата назад).

Анатомия шага

Ниже приводится подробный разбор того, что происходит на отдельном канарском шаге, измеренном во время запуска в конце этой статьи (Qwen2.5-7B → Qwen3.5-9B на одной карте H100 каждая).

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

Краткий обзор выбора стратегии

Все три стратегии используют один и тот же движок и те же проверки работоспособности; они различаются тем, как перемещается трафик, сколько дополнительной емкости требует наложение и есть ли окно ожидания для проверки метрик.

Создание развертывания

Вот трехшаговое канарское развертывание от деплоя, обслуживающего текущую модель, к деплою с моделью-кандидатом, с ограничением по регрессии задержки. CLI поставляется как tg в пакете Python together (версии 2.34.0 или новее). Вы передаете целевой деплой; источник определяется автоматически, если трафик получает ровно один деплой, в противном случае передайте параметр --source:

Источник сокращается до нуля реплик и останавливается по завершении развертывания (--final-source-replicas по умолчанию равен 0), а целевой деплой получает количество реплик источника в качестве минимального значения (--final-target-replicas). CLI привязывает одно ограничение по метрикам на развертывание; для нескольких правил используйте консоль или API.

То же самое через REST API, где создание и запуск являютсядельными вызовами, а развертывание может содержать несколько правил метрик:

Несколько важных требований API: percentile является целым числом (95, а не "p95"), значения перечислений содержат полный префикс (METRIC_STAT_TYPE_*, REGRESSION_DIRECTION_*, THRESHOLD_OPERATOR_*), продолжительность задается строками protobuf вроде "600s", а имя метрики вне каталога отклоняется с кодом 400, содержащим список поддерживаемых имен. Высвобождение источника является действием по умолчанию, поэтому передавать для него ничего не нужно.

Проверку на регрессию можно понимать следующим образом: на каждом этапе сравнить p95 задержки маршрутизатора цели (длительность каждого запроса, измеренная на маршрутизаторе в миллиметрах) за последние 5 минут с аналогичным показателем источника. Если показатели цели хуже более чем на 10%, процесс не продолжается.

Python SDK

То же самое развертывание из Python с использованием пакета together (2.34.0 или новее). Имена полей здесь записаны в формате snake_case, а на уровне сети — в camelCase; SDK выполняет трансляцию.

Управление развертыванием

Каждое развертывание поддерживает четыре команды управления. На эндпоинте может быть максимум одно активное развертывание, поэтому CLI принимает ID эндпоинта, и ID развертывания вам почти никогда не понадобится. Каждая команда возвращает результат сразу после принятия; опрашивайте tg beta endpoints get (или GET-эндпоинт), пока развертывание не достигнет ожидаемого состояния. Пока развертывание активно (включая состояние паузы), разделение трафика эндпоинта заблокировано, а его источник и цель не могут быть остановлены или удалены.

Пауза

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

CLI

REST

Возобновление

Продолжает работу с того же шага как для PAUSED, так и для SYSTEM_PAUSED. Если проверка выдала ошибку, она переоценивается на основе свежих данных; шаг не пропускается.

CLI

REST

Повышение (Promote)

Пропускает оставшиеся канарские шаги и полностью выполняет финальный 100-процентный шаг: цель масштабируется до своего окончательного размера, трафик переключается, выполняются ожидание распространения и прогрев (soak), после чего источник высвобождается. Пропущенные шаги записываются как SKIPPED. Процесс не мгновенный: в тестовом запуск с 10-минутным интервалом шагов принудительное повышение на шаге 0 все равно дожидалось полного прогрева финального шага.

CLI

REST

Отмена

Замораживает текущее распределение трафика в соответствии с фиксированными весами эндпоинта и завершает выкатку со статусом CANCELED (ОТМЕНЕНО). Никакие ресурсы не сокращаются; обе развертки продолжают обслуживать свои замороженные доли, пока вы не измените распределение трафика или не запустите обратную выкатку. Целевая развертка, отмененная на уровне 0%, продолжает работать без трафика; масштабируйте ее до нуля или удалите, если она вам больше не нужна.

CLI

REST

Обратная выкатка

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

CLI

REST

Управление завершенной выкаткой (COMPLETED или CANCELED) заблокировано. Удалите завершенную или так и не запущенную выкатку из истории с помощью команды tg beta endpoints rm $ROLLOUT_ID; удаление записи не изменяет оставленное ею распределение трафика.

Под капотом: настройка проверок

Метрические проверки

Метрические проверки — это функция канареечного развертывания: стратегии blue-green и rolling по-прежнему выполняют проверки работоспособности (health gates), но для того чтобы постадийное сравнение метрик имело смысл, требуется структура шагов канареечной стратегии. Проверки выполняются по закрытому каталогу из трех метрик на стороне роутера, которые измеряются одинаково для источника и цели (любое другое имя метрики отклоняется при создании):

  • router_error_rate: количество 5xx ответов роутера, деленное на все ответы инференса, в виде соотношения от 0 до 1 (0.02 означает 2%)
  • router_latency: длительность обработки одного запроса, измеренная на роутере в миллисекундах. Она имеет бимодальное распределение (медианная попытка часто представляет собой быстрый отказ), поэтому используйте в качестве проверки перцентиль p95 или выше, а не среднее значение
  • inflight_requests: количество одновременных запросов на одну готовую реплику, усредненное за временное окно (пороговые значения размера задаются для реплики, а не для всего пула в целом)

Каждое правило использует одну из двух проверок:

  • regressionCheck (относительная): «цель должна быть хуже источника не более чем на N%». Это правильный выбор по умолчанию для задержки, поскольку она самокалибруется: вам не нужно знать ваше абсолютное значение p95, достаточно лишь того, чтобы новая модель не ухудшала его. Укажите направление (direction), чтобы платформа знала, какое изменение является лучшим или худшим.
  • thresholdCheck (абсолютная): «цель должна удовлетворять условию оператора и значения» (например, уровень ошибок < 0.01). Используйте этот вариант, когда у вас есть жесткий SLO (целевой уровень обслуживания) или когда сам источник может быть нездоров, из-за чего относительное сравнение оценило бы результаты по завышенной шкале.

Два шаблона покрывают большинство сервисов:

Временные окна

Взаимодействуют три интервала времени, поэтому учитывайте их все:

  • window (по умолчанию 5 минут): период времени в прошлом, который анализирует проверка при сравнении метрик.
  • stepInterval (по умолчанию 3 минуты): сколько времени каждый шаг ожидает на своем уровне трафика перед запуском проверки.
  • Задержка поступления метрик (~90 секунд): время между обслуживанием запроса и появлением возможности запросить его точку данных.

Необходимо выждать период не менее чем window + задержка поступления, чтобы весь период ретроспективного анализа проверки приходился на стационарное состояние текущего шага. Если выждать период короче, чем ваше окно, проверка будет сравнивать метрики, которые лишь частично описывают предыдущее распределение трафика. Платформа принудительно контролирует это: если вы запрашиваете слишком короткий период ожидания для вашего окна, она автоматически увеличивает его. Тем не менее, лучше проектировать систему с учетом этого фактора: для 5-минутного окна требуется период ожидания 6,5 минут. При стандартном 5-минутном окне платформа увеличивает стандартный 3-минутный интервал до 390 секунд (6 минут 30 секунд); если вы задаете собственный stepInterval, сделайте его равным как минимум window + 90 секунд.

Что происходит при регрессии

По умолчанию сработавшая проверка переводит систему в состояние SYSTEM_PAUSED, что означает приостановку для проверки. Выкатка замирает на текущем распределении (радиус поражения остается на уровне вашего канареечного процента), и вы принимаете решение: возобновить (проверка запускается повторно), продвинуть дальше или отменить.

Автоматический прерванный откат отсутствует: подтвержденная регрессия всегда приостанавливает выкатку для вмешательства человека, поскольку возвращение трафика назад — это тоже изменение, за которым кто-то должен наблюдать. Устранимые причины, такие как нехватка емкости или задержка в конвейере метрик, работают иначе: платформа повторяет попытки каждые 15 минут в течение максимум 3 часов, прежде чем оставить выкатку приостановленной для вас. Платформа также защищает от ложных срабатываний: перед приостановкой из-за регрессии система делает несколько повторных запросов в течение примерно 90 секунд, чтобы убедиться, что проблема не связана с задержкой поступления данных или кратковременными сбоями; а проверка, которая не может получить достоверные данные, переходит в состояние METRICS_UNAVAILABLE, а не засчитывается как регрессия.

Что гарантирует платформа

Все три стратегии выполняются через один и тот же механизм шагов, поэтому эти правила одинаково применимы для канареечного развертывания, blue-green и rolling.

1. Емкость никогда не округляется в меньшую сторону. Целевые реплики округляются вверх, а высвобождение источника — вниз, поэтому при замене равного размера количество реплик никогда не оказывается меньше исходного. Стратегия rolling добавляет одну реплику посреди шага; blue-green на короткое время запускает обе развертки в полном размере. Реплики, добавленные вашим автоскейлером сверх плана, сохраняются.

2. Трафик никогда не направляется на неготовую емкость. Каждый шаг выполняется в строго определенном порядке: масштабирование цели, проверка работоспособности, перенаправление трафика, ожидание 30 секунд для схождения маршрутизации, высвобождение источника, ожидание, оценка проверки, запись шага. Шаг, на котором произошла регрессия во время ожидания, никогда не записывается как пройденный.

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

4. Выкатка повышает нижние пределы, но не конфликтует с вашим автоскейлером. Каждый шаг записывает минимальное количество реплик для каждой развертки и ничего более, за одним исключением: максимум цели поднимается один раз, чтобы она могла выдержать весь эндпоинт, и остается поднятым. Максимум источника уменьшается вместе с его долей в процессе высвобождения. Если вы установите максимум ниже того, что требуется для шага, выкатка остановится со статусом POLICY_INFEASIBLE вместо того, чтобы переопределять ваши настройки.

5. Проверка всегда выдает вердикт. Относительная проверка (regressionCheck) считается пройденной, если цель укладывается в ваш процентный бюджет относительно источника. Отсутствие данных источника приводит к провалу; нулевой источник при ненулевой цели для метрики «чем больше, тем хуже» приводит к провалу; любой другой нулевой источник считается пройденным. Абсолютная проверка (thresholdCheck) игнорирует источник и сравнивает цель с вашим значением.

6. Проверки считывают только трафик текущего шага и только в необходимом объеме. Период ожидания составляет как минимум оконный период метрики плюс около 90 секунд задержки поступления, поэтому 300-секундное окно означает 390 секунд ожидания. Для p95 требуется 20 запросов в окне, а для p99 — 100; при меньшем количестве выкатка приостанавливается со статусом METRICS_UNAVAILABLE. Для уровня ошибок и активных запросов требуется один запрос.

Краевые случаи

1. Что делать, если для цели нет емкости GPU?

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

2. Могу ли я приостановить процесс на неопределенный срок?

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

Когда платформа приостанавливает развертывание, поле status.condition содержит типизированную категорию сбоя и понятное человеку сообщение. К ним относятся:

В документации перечислены остальные категории и действия для каждой из них: Устранение неполадок при развертывании.

Демонстрация реального развертывания

Все описанное выше проще принять на веру после единократного просмотра в действии, поэтому вот запуск на текущей платформе (сентябрь 2026 г.). Мы обновили работающую эндпоинт-точку с Qwen2.5-7B-Instruct до Qwen3.5-9B, каждую на отдельном H100, в то время как стабильный поток из 5 запросов чата в секунду проходил через эндпоинт все это время, и каждый код ответа регистрировался в логах. Новая модель — это то, что нам было нужно; вопрос, на который отвечает развертывание, заключается в том, укладывается ли она в бюджет задержки, установленный старой моделью. Мы выделили ей 25% бюджета p95.

Настройка. Модель 7B уже обслуживала запросы. Мы добавили 9B в качестве второго развертывания на ту же эндпоинт-точку без трафика и без реплик; развертывание запускает ее при необходимости.

Старт. Одна команда создает и запускает канареечное развертывание: 10% → 50% → 100%, с контрольной точкой (гейтом), которая сравнивает p95 задержку маршрутизатора целевой модели с исходной в течение 5-минутного окна после каждого шага.

Что произошло по часам (время с момента запуска развертывания):

  • +3:57 модель 9B завершила холодный старт, прошла проверки работоспособности, и на нее начали поступать 10% запросов. Развертывание подождало 30 секунд для стабилизации маршрутизации, высвободило соответствующую долю модели 7B, а затем стабилизировалось (soak phase). Мы оставили интервал шага по умолчанию, поэтому платформа увеличила его до 390 секунд, чтобы покрыть 300-секундное окно плюс задержку поступления данных.
  • +11:00 контрольная точка выполнила оценку и сработала. Задержка маршрутизатора p95 для модели 9B составила 1 740 мс против 734 мс у 7B, что означает ухудшение на 137% при бюджете в 25%. Развертывание перешло в состояние SYSTEM_PAUSED, при этом 10% трафика все еще оставалось на целевой модели, и ничего не было удалено. Вот что возвращает команда tg beta endpoints get $ROLLOUT_ID --json (значения в миллисекундах):

Принятие решения. Ухудшение реально, а не является случайным всплеском: 9B — это модель рассуждений (reasoning model) и при том же max_tokens генерирует больше данных на один запрос. Это продуктовое решение, а не то, что можно просто продолжить, поэтому мы отменили процесс и откатились назад.

  • +11:09 CANCELED (ОТМЕНЕНО). Распределение зафиксировалось на отметке 90/10 в течение 0,2 с после выполнения команды.
  • +17:00 обратное развертывание завершилось через 5 минут 49 секунд после старта: 100% трафика вернулось на 7B, модель 9B была полностью разгружена до нуля и остановлена. Большая часть этого времени ушла на холодный старт второй реплики 7B, поскольку после отмены стандартное финальное количество реплик равно их суммарному количеству для пары.

Вердикт зонда за весь прогон, включая переключение, паузу, отмену и возврат: 6800 запросов, 0 ответов, отличных от 200.

Журнал аудита. Каждый шаг, описанный выше, содержится в ленте событий эндпоинта с возможностью фильтрации по идентификатору развертывания (rollout ID):

Более ранний запуск в июле с намеренно невыполнимым пороговым гейтом дал тот же результат: срабатывание на 10% трафика и 1198 запросов зонда без единой ошибки за время восстановления.

Попробуйте сами!

1. Два развертывания на одной эндпоинт-точке. Оставьте текущее развертывание в качестве исходного и добавьте кандидата в качестве цели с нулевым трафиком. Команда pip install -U together (версии 2.34.0 или новее) предоставляет CLI-утилиту tg:

2. Создайте и запустите канареечное развертывание со стандартной лестницей (5% → 25% → 50% → 100%) и одним гейтом регрессии router_latency:

3. Наблюдайте за процессом с помощью команды tg beta endpoints get $ENDPOINT_ID (или на вкладке Rollouts эндпоинт-точки в консоли) по мере продвижения по шагам. Приостанавливайте, продвигайте или отменяйте его с помощью tg beta endpoints rollout $ENDPOINT_ID --pause | --promote | --cancel.

В течение всего процесса URL эндпоинта и ваши клиенты остаются неизменными; меняется только скрывающаяся за ними модель.

📚 Документация: Запуск развертывания · Управление развертываниями с помощью метрик · Справочник CLI · Справочник API: Создание развертывания

← Все статьи

Ещё в разделе «AI и машинное обучение»

Все →
OpenAI, по сообщениям, отказывается от модели из-за проблем с безопасностьюПресса
OpenAI

OpenAI, по сообщениям, отказывается от модели из-за проблем с безопасностью

OpenAI отказывается от плана выпустить новую модель из-за растущих опасений по поводу безопасностиПресса
OpenAI

OpenAI отказывается от плана выпустить новую модель из-за растущих опасений по поводу безопасности

Источник: Инфраструктурный провайдер AI-инференции Modal Labs приближается к раунду финансирования на $750 млн по оценке $15,75 млрд
Пресса
Modal

Источник: Инфраструктурный провайдер AI-инференции Modal Labs приближается к раунду финансирования на $750 млн по оценке $15,75 млрд

Tesla снова отложила событие Roadster 2 из‑за плохой погодыПресса
Tesla

Tesla снова отложила событие Roadster 2 из‑за плохой погоды

OpenAI спровоцировала борьбу за Hugging Face ранним предложением об инвестициях в преддверии сделки Nvidia на 13 млрд долларовПресса
OpenAI

OpenAI спровоцировала борьбу за Hugging Face ранним предложением об инвестициях в преддверии сделки Nvidia на 13 млрд долларов

OpenAI по-прежнему не до конца контролирует всю активность своих ИИ-агентов с непредсказуемым поведениемПресса
OpenAI

OpenAI по-прежнему не до конца контролирует всю активность своих ИИ-агентов с непредсказуемым поведением

Ещё от Together AI

Как обучить собственный Jev за $17
Together AI

Как обучить собственный Jev за $17

Как глобальный финтех-гигант масштабировал трафик агентов кодинга с помощью Dedicated Model Inference
Together AI

Как глобальный финтех-гигант масштабировал трафик агентов кодинга с помощью Dedicated Model Inference

Переход от закрытых моделей к моделям с открытым исходным кодом, Together
Together AI

Переход от закрытых моделей к моделям с открытым исходным кодом, Together