Маршрутизация с использованием политик LB
В этом руководстве на практике рассматриваются политики балансировки нагрузки на уровне маршрутов GPUStack: сохранение устойчивости сеансов при одновременном распределении нагрузки и предоставление службе принятия решений выбора между маленькой и большой моделью для каждого запроса. Справочную информацию по настройке см. в разделе Управление маршрутами модели.
Предварительные условия
- Запущенная установка GPUStack. Шлюз AI, применяющий эти политики, по умолчанию развертывается с помощью GPUStack, поэтому стандартная установка не требует дополнительной настройки.
- Две развернутые модели, служащие целями маршрута, например.
qwen3-0.6bиqwen3-32b(они используются в примерах ниже). - Для части службы принятия решений: служба принятия решений Jev, зарегистрированная на странице
Model-Providerв качестве поставщикаTypeSafe Decision Service (Jev)(см. Управление модельным поставщиком).
Шаг 1. Создайте маршрут.
- Перейдите на страницу
Routes. - Нажмите
Add Route, назовите его, например.qwen3. - Выберите
qwen3-0.6bиqwen3-32bкакRoute Targets, оставив все веса неустановленными. - Нажмите
Save.
Без весов и политики маршрут Route By является циклическим — простым циклическим перебором между двумя моделями.
Шаг 2. Взаимодействие Session Affinity и Least Inflight Request
Когда плагины политик включены, каждый из них оценивает каждую цель-кандидата. Итоговый механизм выбора выбирает цель с наибольшей взвешенной суммой баллов:
Session Affinity присваивает наивысший балл текущей цели сеанса, а Least Inflight Request — наименее загруженной цели. Сеанс переходит с текущей цели только тогда, когда разница баллов Least Inflight Request превышает разницу баллов Session Affinity.
Когда оба плагина имеют вес по умолчанию (1), следующая таблица показывает результат для случая, когда у текущей цели сеанса накопилось x обрабатываемых запросов, а остальные цели простаивают. Это наиболее благоприятное условие для перехода сеанса на другую цель:
| Цели (N) | x=0 | x=1 | x=2 | x=3 | x=4 | Возможен переход? |
|---|---|---|---|---|---|---|
| 2 | сохраняется | ничья ⚠️ | ПЕРЕХОД | ПЕРЕХОД | ПЕРЕХОД | да |
| 3 | сохраняется | сохраняется | ничья ⚠️ | ПЕРЕХОД | ПЕРЕХОД | да |
| 4 | сохраняется | сохраняется | сохраняется | сохраняется | сохраняется | только при x ≈ 5.3 |
| ≥5 | сохраняется | сохраняется | сохраняется | сохраняется | сохраняется | нет |
- ПЕРЕХОД: сеанс переходит к следующей цели-кандидату.
- ничья ⚠️: разницы баллов точно равны; итоговый выбор случаен, поэтому запрос может как перейти на другую цель, так и остаться на текущей.
- N ≥ 5: разница баллов Least Inflight Request ограничена значением
1/(N−1) ≤ 0.25, меньшим, чем разница Session Affinity. Поэтому один лишь дисбаланс нагрузки не может нарушить привязку сеанса.
Чтобы нагрузка имела значение на больших маршрутах, перебалансируйте веса — см. Как работают веса, чтобы узнать об изменении порогов при масштабированных соотношениях весов.
Шаг 3. Включение Session Affinity и Least Inflight Request
- Отредактируйте маршрут, начиная с шага 1.
- Включить
Session Affinity— принять цепочку сеансовых ключей по умолчанию (заголовокsession-id, заголовокx-client-request-id, затем поле телаprompt_cache_key) или указать свою собственную. - Включите
Least Inflight Requestс весом по умолчанию. - Сохраните и убедитесь, что
Route Byмаршрута равноPolicy.
Сеансы теперь привязаны: запросы, несущие один и тот же сеансовый ключ, остаются на одной и той же цели — кэши подсказок остаются теплыми — в то время как сильно загруженный владелец в конечном итоге сбрасывает сеансы на простаивающий целевой объект, как указано в таблице выше.
Обратите внимание, какие источники ключей на самом деле применяются на каждом пути: ключи заголовка (например, session-id) работают везде, но ключи тела, такие как prompt_cache_key, вступают в силу только для запросов /responses и /messages — для /chat/completions, у которого нет стандартного поля тела сеанса, учитываются только ключи заголовка цепочки. Предпочитайте ключ заголовка для трафика чата.
Шаг 4. Добавьте маршрутизацию службы принятия решений.
Теперь сделайте маршрут учитывающим модель: вместо того, чтобы всегда привязывать сеанс к той модели, на которой он начался, спросите механизм принятия решений, какой модели заслуживает каждый запрос.
-
Отредактируйте маршрут и включите
Decision Service Routing:Decision Service— выберите зарегистрированного провайдера.Decision Model— e.g.jev-latest.Instructions— «Выберите наименьшую модель, которая сможет хорошо обработать запрос. Простые, короткие или фактические запросы переходят к быстрой модели; сложные запросы рассуждений, математических вычислений или кода переходят к большой модели».Model Criteria— одна запись для каждой цели (или нажмитеGenerate from targetsи уточните):qwen3-0.6b— «Очень быстрая и недорогая модель 0.6B. Обрабатывает приветствия, простые вопросы по фактам, форматирование и короткую болтовню. Не справляется с многоэтапными рассуждениями, математикой и программированием».qwen3-32b— «Модель рассуждения 32B с высокими возможностями. Обрабатывает сложные рассуждения, математические вычисления, генерацию кода и длительный контекстный анализ. Медленнее и дороже за запрос».
-
Сохраните, затем отправьте два аутентифицированных запроса по имени маршрута
qwen3(замените$GPUSTACK_API_KEYключом API, созданным на страницеAPI Keys):
Первый запрос направляется на qwen3-0.6b, второй на qwen3-32b.
Как работают веса
Веса появляются в двух разных местах и имеют разное значение:
Целевой вес (доля трафика)
В режиме Target Weight вес цели равен общей доле трафика этой цели — независимо от того, сколько экземпляров она запускает. GPUStack масштабирует веса для каждого экземпляра, поэтому разделение всегда соответствует настроенным целевым весам:
- Цель A (вес 100, 1 экземпляр) и Цель B (вес 100, 2 экземпляра) делят трафик 50/50 между двумя целями, а не 1/3 на каждый экземпляр.
- Увеличение масштаба цели с 1 до 2 экземпляров не меняет ее долю; каждый экземпляр затем получает половину этого количества.
Пример с qwen3-0.6b и qwen3-32b: вес 100 на qwen3-0.6b и вес 300 на qwen3-32b отправляет 25 % запросов на маленькую модель и 75 % на большую, независимо от количества их реплик.
Вес политики (влияние в сумме)
Параметр Weight каждого плагина определяет его вклад во взвешенную сумму в режиме Policy. Это положительное число; дробные значения тоже допустимы. Если Weight не задан, используется встроенный вес плагина: 1 для Session Affinity и Least Inflight Request, 10 для Decision Service Routing.
Правила расчёта баланса Session Affinity × Least Inflight Request при x обрабатываемых запросах у текущей цели сеанса и простое всех остальных целей:
- разница баллов Session Affinity:
affDiff = 0.5 / (2·(1 − 2⁻ᴺ)) - разница баллов Least Inflight Request:
loadDiff = x / ((1+x)·(N−1) + 1) - сеанс переходит к другой цели, когда
w_leastInflight × loadDiff > w_affinity × affDiff
Изменение соотношения весов сдвигает порог перехода. В следующей таблице указано минимальное число x обрабатываемых запросов у текущей цели, при котором сеанс переходит на другую цель, для каждого соотношения весов (Least Inflight Request : Session Affinity) и числа целей N:
| N | 1:1 (по умолчанию) | 1.5:1 | 2:1 |
|---|---|---|---|
| 2 | 2 | 1 | 1 |
| 3 | 3 | 1 | 1 |
| 4 | 6 | 2 | 1 |
| 5 | никогда | 3 | 2 |
| 6 | никогда | 7 | 3 |
| 7 | никогда | никогда | 4 |
| 8 | никогда | никогда | 9 |
Читаем таблицу:
- При соотношении по умолчанию 1:1 на маршрутах с пятью и более целями сеанс никогда не переходит на другую цель: разница баллов Least Inflight Request ограничена значением ниже разницы Session Affinity.
- Уменьшение
WeightSession Affinity вдвое (соотношение 2:1) позволяет нагрузке влиять на выбор уже приx= 2–4 на маршрутах с количеством целей до 8. УдвоениеWeightLeast Inflight Request даёт тот же эффект: важно только соотношение весов. - Точные ничьи (например, 1:1 при N=2/x=1) определяются финишером случайным образом.
Как политика разделяет работу
Все включённые политики вносят вклад в одну общую взвешенную сумму, выполняя каждая свою задачу:
- Маршрутизация службы принятия решений решает, какая модель соответствует запросу (ее значение по умолчанию
Weight, равное 10, означает, что обычно это доминирующий голос); - Привязка сеанса сохраняет текущую модель сеанса, сохраняя локальность кэша подсказок;
- Least Inflight Request распределяет запросы между экземплярами выбранной модели.
Если модель развернута в нескольких экземплярах, Decision Service Routing сужает выбор до нужной модели, а Least Inflight Request выбирает экземпляр этой модели.