К основному содержимому
ко всем лонгридам
Лонгрид#MLSystems#SRE

Эксплуатация инференса LLM: что обещать продукту и как обслуживать запросы при перегрузке

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

24 сентября 2026 · обновлено 31 октября≈ 33 минутыпервичные источники ↓

Обновлено 31 октября 2026 года: добавлены статьи и продакшн-отчёты о планировании, полезной пропускной способности, разделении стадий, миграции запросов и холодном старте, а также три учебных расчёта. Состояние инструментов проверено по первичным страницам на эту дату: vLLM 0.32, SGLang 0.5.22, llm-d 1.0, Gateway API Inference Extension 1.6, MLPerf Inference v6.1. Пороги бенчмарков относятся к указанным в них моделям и сценариям, а не к вашему трафику. Числа проектов о собственных решениях помечены как заявления поставщика, препринты — как сигнал направления; в учебных расчётах архитектура модели и поведение движка взяты из источников, а цены и доли нарушений условные.

01

График пропускной способности — это не обещание

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

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

Формат такого обещания придумывать не нужно — индустрия его уже записала. MLPerf Inference в версии 5.1 оценивает систему на модели Llama 3.1-8B не абстрактной скоростью, а максимальной устойчивой нагрузкой внутри двух границ. В сценарии Server это TTFT не выше 2 секунд и TPOT не выше 100 миллисекунд. В добавленном сценарии Interactive границы жёстче: 0,5 секунды и 30 миллисекунд.

MLCommons сама переводит эти пороги в человеческую величину: 100 миллисекунд на токен — это примерно 480 слов в минуту, заметно быстрее обычного чтения, а 30 миллисекунд — около 1600 слов в минуту. Второй сценарий появился ради случаев, где важна отзывчивость: помощники в коде и инструменты, работающие в реальном времени.

К октябрю 2026 года формат закрепился. В раунде MLPerf Inference v6.1 от 16 сентября 2026 года своя пара порогов задана для каждой языковой модели: у Llama 2 70B в интерактивном сценарии это 450 миллисекунд до первого токена и 40 миллисекунд на токен, у DeepSeek-R1 — 1,5 секунды и 15 миллисекунд. Рассуждающей модели разрешают дольше думать до начала ответа, но требуют быстрее печатать: пороги задаются под сценарий, а не под модель вообще. Там же MLCommons объявила, что для датацентров MLPerf Inference уступит место MLPerf Endpoints — бенчмарку, который нагружает систему через API, то есть так, как её видит клиент.

Исследователи дали такой мере собственное имя — . В DistServe (OSDI 2024) она определена как максимальная интенсивность запросов, при которой заданная доля запросов — например, 90 % — укладывается в SLO, в пересчёте на один ускоритель. В вводном примере статьи система, совмещающая обе стадии на одном ускорителе, держит внутри порогов около 1,6 запроса в секунду, а система с разделёнными стадиями — 3,3 запроса на ускоритель. Модель и железо те же; различается доля работы, которая уложилась в обещание.

Почему у темпа генерации вообще есть порог, объясняет простое наблюдение: текст быстрее чтения не делает ответ лучше. Авторы препринта Andes принимают скорость чтения за 4,8 токена в секунду, а прослушивания — за 3,3 и считают качество ответа по тому, насколько выдача отстаёт от этого темпа. Это препринт, а не стандарт, но логика полезна: обгонять читателя бессмысленно, отставать — заметно. Значит, после некоторой границы ускорение генерации ничего не даёт продукту, а время до первого токена даёт всегда.

обещание = порог на старте ответа + порог на темпе генерации + доля запросов, которая в них укладывается

Дальше вся статья — про то, откуда берётся нарушение этого обещания. Сначала разберём, почему одной кривой задержки недостаточно, затем — где на самом деле живёт хвост, чем измеряется ёмкость, как всё это ломается и что делать вместо отказа. Устройство самого сервера — как он собирает пакеты, где лежит KV-кеш и зачем разделять стадии — подробно разобрано в статье об инференсе как распределённой системе; здесь оно нужно только там, где влияет на обещание.

02

Одной кривой задержки не хватает: величин три

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

Величина
TTFT
Что измеряет
Сколько ждали до первого токена
От чего зависит
Очередь, планировщик, обработка входа
Как выглядит для пользователя
Пользователь думает, что кнопка не сработала
Величина
TPOT / межтокенная задержка
Что измеряет
Как быстро идёт текст после старта
От чего зависит
Размер батча, соседи по машине, длина контекста
Как выглядит для пользователя
Ответ печатается медленнее, чем читается
Величина
Сквозная задержка
Что измеряет
Сколько занял весь ответ
От чего зависит
Сумма первых двух и длина ответа
Как выглядит для пользователя
Сценарий не укладывается в таймаут вызывающего
Величина
Время в очереди
Что измеряет
Сколько запрос ждал до начала работы
От чего зависит
Загрузка, приоритеты, вытеснения
Как выглядит для пользователя
Ничего не видно на графиках модели — и это главный признак

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

vLLM уже разделяет задержки и состояние очереди. Имена ниже связывают метрику с вопросом, который нужно задать сервису.

Вопрос
Ожидание первого токена
Метрика
vllm:time_to_first_token_seconds
Вопрос
Задержка между токенами
Метрика
vllm:inter_token_latency_seconds
Вопрос
Время всего ответа
Метрика
vllm:e2e_request_latency_seconds
Вопрос
Время ожидания в очереди
Метрика
vllm:request_queue_time_seconds
Вопрос
Число выполняемых запросов
Метрика
vllm:num_requests_running
Вопрос
Число ожидающих запросов
Метрика
vllm:num_requests_waiting

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

03

Хвост живёт в очереди, а не в модели

Инженерная интуиция подсказывает, что задержка растёт, когда не хватает мощности. Это верно лишь наполовину, и вторая половина объясняет большинство неприятных инцидентов.

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

ожидание ≈ [ρ / (1 − ρ)] × [(c²прихода + c²обслуживания) / 2] × среднее время обслуживания

Управленческий смысл формулы в том, что ожидание растёт по трём независимым причинам: приход стал более рваным, обслуживание стало более разбросанным, загрузка приблизилась к единице. Докупка мощности работает только с третьим множителем.

У инференса первые два множителя экстремальны, и это его отличает от обычного сервиса. На одном и том же адресе живут запрос с контекстом в несколько сотен токенов и запрос с контекстом в сотни тысяч; ответ бывает в одну строку и на десять экранов. Разброс времени обслуживания измеряется не процентами, а порядками. Поэтому кластер, у которого «загрузка всего 60 процентов», уверенно выдаёт неприемлемый хвост — и добавленный ускоритель этот хвост почти не двигает.

Это видно и в реальных трейсах. Авторы Splitwise (ISCA 2024) опубликовали трейсы двух сервисов Azure: у помощника в коде медианный вход — 1500 токенов, а медианный ответ — 13; у диалогового сервиса — 1020 и 129 токенов, причём длина ответа распределена почти бимодально. Набор BurstGPT (KDD 2025) — 213 дней трейсов региональных сервисов Azure OpenAI — показывает второй множитель с другой стороны: всплески прихода резко меняют характер в рабочие часы, а доля отказов диалогового сервиса на модели ChatGPT в этих трейсах стабильно выше 5 %. Авторы связывают такие всплески отказов с нехваткой памяти, к которой мы вернёмся в следующем разделе.

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

Учебный расчёт: бюджет хвоста задержки

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

Этап
Шлюз, авторизация, маршрутизация
Бюджет
0,1 с
Откуда число
Замер на входе сервиса
Этап
Обработка входа типичной длины
Бюджет
0,4 с
Откуда число
95-й процентиль на вашей модели и железе
Этап
Запас на разброс и сеть до клиента
Бюджет
0,3 с
Откуда число
Решение команды
Этап
Ожидание в очереди
Бюджет
1,2 с
Откуда число
Остаток: 2,0 − 0,1 − 0,4 − 0,3

Чтобы перевести 1,2 секунды в число, которое видно на дашборде, нужен закон Литтла: среднее число ожидающих равно интенсивности прихода, умноженной на среднее время ожидания (L = λW). Если на реплику приходит 20 запросов в секунду, то при среднем ожидании 1,2 секунды в очереди в среднем стоят 24 запроса. Порог тревоги по vllm:num_requests_waiting должен быть заметно ниже 24: закон Литтла связывает средние, а обещание дано про 95-й процентиль, и при рваном приходе хвост ожидания намного длиннее среднего.

Тот же бюджет можно выразить в токенах. Если реплика обрабатывает, скажем, 20 тысяч входных токенов в секунду, то в 1,2 секунды очереди помещается не больше 24 тысяч необработанных входных токенов. В актуальных версиях vLLM есть настройка ровно для этого: max_num_queued_tokens ограничивает суммарный вход запросов, ещё ожидающих обработки, и отвечает 503 сверх лимита. Документация планировщика прямо называет её механизмом качества по TTFT и предлагает выставлять как целевое TTFT, умноженное на скорость обработки входа.

Хвост складывается по цепочке вызовов

Последний множитель хвоста появляется у агентов. В статье The Tail at Scale (Dean, Barroso, CACM 2013) показано, что если каждый сервер медленно отвечает в одном случае из ста, то запрос, ждущий ответа ста серверов, медленный в 63 % случаев. У агента та же арифметика растянута во времени: сессия из 10 последовательных вызовов модели, каждый из которых с вероятностью 1 % выходит за порог, хотя бы раз выйдет за него с вероятностью 1 − 0,99¹⁰ ≈ 9,6 %; при 20 вызовах — около 18 %. Обещание на уровне одного вызова не равно обещанию на уровне задачи, и для агентских сценариев его нужно пересчитывать.

04

Ёмкость измеряется памятью, а не числом запросов

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

Насколько дорога эта память, показала статья о PagedAttention (SOSP 2023): в системах того времени на реальные состояния токенов уходило лишь 20,4–38,2 % памяти KV-кеша, остальное съедали резерв под максимальную длину и фрагментация. Страничная раскладка памяти подняла пропускную способность в 2–4 раза при той же задержке и стала основой vLLM. Статью подробно разбирает выпуск Research Insights №32.

Учебный расчёт: сколько диалогов помещается в узел

Объём KV-кеша на токен считается по архитектуре модели: два тензора (ключи и значения) на каждый слой, на каждую KV-голову, по размеру головы, умноженные на байты на число.

байт на токен = 2 × слои × KV-головы × размер головы × байт на число

У Llama 3.1 70B, по описанию архитектуры в репозитории Meta, 80 слоёв, 8 KV-голов и размер головы 128 (8192 ÷ 64). В BF16 это 2 × 80 × 8 × 128 × 2 = 327 680 байт, то есть 320 КиБ на каждый токен контекста. Дальше — учебный узел из четырёх ускорителей H100 по 80 ГБ с тензорным параллелизмом:

  • движку по умолчанию отдают 92 % памяти — в актуальной документации vLLM это значение gpu-memory-utilization; от 320 ГБ остаётся около 294 ГБ;
  • веса в BF16 занимают около 140 ГБ: 70 млрд параметров по 2 байта;
  • на активации и графы вычислений заложим условные 10 ГБ;
  • на KV-кеш остаётся около 144 ГБ, то есть примерно 440 тысяч токенов.

Диалог с входом 2,5 тысячи токенов и ответом 0,5 тысячи занимает 3 тысячи токенов, и таких диалогов в узел одновременно помещается около 145. Одна агентская сессия с контекстом 128 тысяч токенов занимает 29 % пула — столько же, сколько 43 диалога. Перевод KV-кеша в FP8 вдвое уменьшает байты на токен и примерно удваивает этот запас. Расчёт приблизительный: движок выделяет память блоками, делит общие префиксы и резервирует место под генерацию. Сверять его стоит со строками, которые vLLM печатает при старте: GPU KV cache size: N tokens и Maximum concurrency for X tokens per request. Документация советует добавлять ускорители, если эти числа ниже требуемых.

Отсюда следствие, которое ломает интуицию: один запрос с очень длинным контекстом стоит дороже десятков коротких диалогов. И именно он вытесняет соседей. Когда памяти перестаёт хватать, vLLM пишет в лог честную фразу: Sequence group N is preempted by PreemptionMode.RECOMPUTE mode because there is not enough KV cache space.

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

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

Если ограничение здесь
Память под контекст
Что изменить
Увеличить долю памяти, доступную движку
Что проверить после изменения
Помещаются ли нужные контексты и хватает ли памяти остальным задачам
Если ограничение здесь
Одновременно выполняемые запросы
Что изменить
Уменьшить предельное число последовательностей
Что проверить после изменения
Очередь, время первого токена и число принятых запросов
Если ограничение здесь
Работа в одном пакете
Что изменить
Изменить предельное число токенов в пакете
Что проверить после изменения
Время первого токена и темп генерации: эффект различается
Если ограничение здесь
Модель на устройствах
Что изменить
Распределить модель между большим числом ускорителей: разделить вычисления или этапы обработки
Что проверить после изменения
Задержки, память и стоимость добавленных ускорителей

У SGLang те же ручки называются иначе: --max-running-requests, --chunked-prefill-size и --schedule-conservativeness — чем больше значение, тем осторожнее планировщик принимает новые запросы. Показательна страница тюнинга SGLang: хорошей загрузкой она называет занятость KV-кеша выше 0,9 и советует держать очередь в сотни запросов. Но это раздел о максимальной пропускной способности пакетной офлайн-обработки. Для интерактивного обещания такая очередь означает секунды до первого токена. Одна и та же метрика хороша или плоха в зависимости от того, что обещано.

Обе системы умеют приоритеты. В vLLM это --scheduling-policy priority: меньшее значение обслуживается раньше. В SGLang — --enable-priority-scheduling, где по умолчанию раньше идут большие значения, а направление переключается отдельным флагом. Шкалы противоположны, и это стоит записать в контракт с клиентами, иначе после смены движка пакетная задача окажется впереди интерактивной.

Ручка, которая явно переключает между двумя обещаниями

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

Откуда взялся этот компромисс, показывает Sarathi-Serve (OSDI 2024). Планировщики, которые ставят обработку входа вперёд, создают остановки генерации: в vLLM того времени такая остановка длилась до нескольких секунд. Нарезка входа на части позволяет добавлять новые запросы в пакет, не останавливая генерацию соседей, и при ограничении на 99-й процентиль межтокенной задержки дала до 2,6 раза больше ёмкости для Mistral-7B на одном A100.

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

Если одной ручки не хватает, следующий шаг — : обработку входа и генерацию ставят на разные пулы ускорителей и масштабируют по отдельности. В DistServe это дало до 7,4 раза больше запросов или в 12,6 раза более жёсткий SLO при доле запросов внутри порогов выше 90 %. В llm-d 1.0 от 20 октября 2026 года пулы двух стадий управляются как одна логическая единица — для согласованных выкаток и обновлений. Цена решения — передача KV-кеша между пулами и вторая модель ёмкости; где граница доказанного выигрыша, разбирает фронтир инференса LLM.

05

Четыре способа сломаться под нагрузкой

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

Отказ
Вытеснение по KV-памяти
Причина
Контексты не помещаются целиком
Что происходит
Пересчёт вытесненного запроса, скачок сквозной задержки
Ранний признак
`vllm:num_preemptions`, `vllm:kv_cache_usage_perc`
Отказ
Накопленная очередь
Причина
Приход выше устойчивой ёмкости
Что происходит
Память под ожидающие запросы, рост TTFT без роста нагрузки на GPU
Ранний признак
`vllm:num_requests_waiting`, `vllm:request_queue_time_seconds`
Отказ
Усиление ретраями
Причина
Клиент повторяет запрос по таймауту
Что происходит
Повторное занятие памяти под весь контекст, каскад
Ранний признак
Расхождение числа запросов клиента и сервера
Отказ
Холодный старт реплики
Причина
Автомасштабирование добавило под
Что происходит
Минуты до первой полезной работы новой реплики
Ранний признак
Время от решения масштабировать до готовности
Схема · где запрос ждёт и где можно вмешаться
Путь запроса через сервер инференса и точки управлениязапросВходприоритет · повторыОчередьвремя ожиданияKV-памятьзанятость · вытесненияГенерацияTTFT · TPOTвытеснениеОтветвнутри пороговесли не успеваем:Ранний отказ429 и паузаДешёвый ответкороче, меньше,позже

Про очередь стоит сказать отдельно, потому что здесь работает старое правило из инженерии надёжности. Очередь — это не бесплатное ожидание: она расходует память и добавляет задержку. В книге Google по эксплуатации приводится простой расчёт: если запрос обрабатывается 100 миллисекунд, а очередь вдесятеро длиннее пула обработчиков, то при полной очереди запрос занимает 1,1 секунды, и почти всё это время он ждёт. Рекомендация — держать очередь короткой относительно пула и отклонять запросы рано, а не копить их.

В vLLM этот совет стал настройкой. Кроме упомянутого лимита на необработанный вход, max_num_queued_reqs ограничивает число запросов в работе и в очереди; сверх лимита сервер отвечает 503, чтобы клиент повторил запрос на другом экземпляре. По умолчанию оба лимита выключены, и очередь vLLM без них не ограничена: короткую очередь нужно включить явно.

Ранний отказ — не только учебная рекомендация. Mooncake, платформа сервиса Kimi от Moonshot AI, описана в статье, получившей награду лучшей работы на FAST 2025. Планировщик заранее отклоняет запросы, которые по прогнозу не уложатся в SLO, чтобы разгрузить кластер. В целом архитектура позволила Kimi обслуживать на 115 % и 107 % больше запросов на кластерах A800 и H800. В расширенной версии статьи авторы прямо называют перегрузку частым состоянием в часы пик и приводят отдельный эксперимент: на записи из 23 тысяч реальных запросов, проигранной с удвоенной скоростью, базовая система отклонила 4183 запроса, ранний отказ — 3771, ранний отказ с прогнозом нагрузки — 3589. Отказов меньше, потому что кластер не тратит работу на запросы, которые всё равно не успеют.

Ретраи заслуживают отдельного абзаца, потому что в инференсе они дороже. В главе Handling Overload книги Google по эксплуатации даже лимит в три попытки на запрос при массовых отказах поднимает нагрузку почти втрое. Поэтому к нему добавляют второй бюджет: клиент повторяет запросы, только пока повторы составляют меньше 10 % его запросов, и тогда рост в общем случае ограничен примерно 1,1 раза. Там же описано адаптивное ограничение на клиенте: клиент сам отбрасывает часть запросов с вероятностью max(0, (запросы − K × принятые) / (запросы + 1)) за последние две минуты, а авторы предпочитают K = 2. Соседняя глава добавляет серверный бюджет — например, не более шестидесяти повторов в минуту на процесс.

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

06

Деградация вместо пятисотки

У обычного сервиса выбор под перегрузкой небогатый: обслужить или отказать. У генеративного сервиса есть третий путь, и он почти всегда лучше: отдать более дешёвый ответ. Между «как обычно» и «ошибка» лежит целая шкала.

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

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

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

Проект вводит понятие пула серверов модели, которым владеет платформа, и отдельный компонент, выбирающий эндпоинт под настроенные цели, — среди сигналов упоминаются состояние префиксного кеша и доступность адаптеров. Анонс опубликован 5 июня 2025 года, пул серверов модели стал стабильным API в версии 1.0 в сентябре 2025-го. За год граница сдвинулась: в версии 1.6 (август 2026) полноценный компонент выбора эндпоинта и объекты с приоритетами переехали в llm-d, а сам проект сосредоточился на стандарте, ресурсах Kubernetes и тестах совместимости.

В llm-d приоритеты и сброс нагрузки собраны в одном механизме. Цель запроса задаёт его приоритет; отрицательное значение помечает запрос как сбрасываемый. Управление потоком раскладывает запросы по очередям приоритетов, ограничивает ёмкость каждой и отвечает 429, когда лимит исчерпан; при необходимости оно может прервать уже отправленный низкоприоритетный запрос ради более важного. В llm-d 1.0 это заявлено как управление потоком с учётом приоритетов и справедливости, но в документации механизм пока включается отдельной настройкой.

Есть и третий путь между вытеснением и отказом — перенести запрос. Llumnix (OSDI 2024) из Alibaba переносит запрос вместе с KV-кешем на другой экземпляр почти без простоя и использует это для балансировки, приоритетов и освобождения узлов. В экспериментах авторов хвост задержки улучшился на порядок, высокоприоритетные запросы ускорились до 1,5 раза, а при сопоставимом хвосте расходы снизились до 36 %. Механизм разобран в разборе Llumnix из серии об инференсе на кластере.

Управление очередью как отдельная задача описано в QLM (SoCC 2024): система держит интерактивные и пакетные запросы с разными SLO в одной очереди и упорядочивает её по оценке времени ожидания каждого запроса; та же оценка управляет вытеснением, балансировкой и сменой моделей. Оценка опирается на требования облачного провайдера. Авторы сообщают о росте доли запросов внутри SLO на 40–90 % и пропускной способности на 20–400 %. Препринт SLOs-Serve идёт дальше и распределяет токены под ограничения нескольких SLO: заявлен рост ёмкости на ускоритель в среднем в 2,2 раза на шести сценариях — от суммаризации до вызова инструментов. На 31 октября 2026 года у препринта по-прежнему одна версия апреля 2025 года и нет подтверждённой площадки, поэтому это сигнал направления, а не ожидаемый выигрыш.

07

Платформа: чем масштабировать и почему это долго

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

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

Платформы сводят эти сигналы к целям SLO. Планировщик NVIDIA Dynamo в версии 1.6 меняет число реплик обработки входа и генерации, чтобы удержать цели по времени до первого токена и межтокенной задержке; в режиме по умолчанию он опирается на пороги глубины очереди и занятости KV-кеша. В руководстве llm-d по автомасштабированию один из вариантов пересчитывает накопленный необработанный вход в секунды ожидания и сравнивает их с долей бюджета на первый токен — тот же расчёт, что и в учебном примере выше. Там же отмечено, что при активном формировании пакетов загрузка ускорителя почти всегда близка к 100 %, поэтому как сигнал она бесполезна. Сигнал везде один и тот же: очередь и память.

Правило сработало — и ничего не произошло ещё несколько минут

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

Исследования атакуют этот интервал с двух сторон. ServerlessLLM (OSDI 2024) держит веса на локальных дисках и в памяти узлов, загружает их в 3,6–8,2 раза быстрее стандартных форматов и сокращает задержку на 10–200× в зависимости от нагрузки; подробности — в разборе холодного старта. BlitzScale (OSDI 2025) загружает веса по вычислительной сети между ускорителями и переносит вычисление отдельных слоёв на новые экземпляры, не дожидаясь полной загрузки: авторы сообщают о хвосте задержки до 94 % ниже, чем у ServerlessLLM, и о 49 % экономии времени ускорителей.

В открытых инструментах тот же интервал сокращают пробуждением вместо загрузки. Руководство llm-d по быстрому подъёму модели описывает подход, при котором тензоры остаются в оперативной памяти и возвращаются на ускоритель за секунды, а запуск нового экземпляра с уже загруженными модулями занимает десятки секунд. Проект честно оговаривает, что ускоряет подъём мощности, а не сам инференс, и оценивает накладные расходы резидентных серверов примерно в 2,5 процента памяти хоста.

Числа vLLM для этого режима: на A100 пробуждение занимает 0,26 секунды для Qwen3-0.6B и 0,82 секунды для Phi-3-vision против холодного старта в 37–58 секунд. На A100 переключение модели ускоряется в 18–20 раз, а верхняя граница заявленного диапазона — около 200 раз — получена на A4000. Это замеры проекта на своих моделях и своём железе, и относиться к ним стоит как к заявлению поставщика, а не как к ожидаемому результату на вашем контуре.

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

08

Цена запаса против цены нарушения

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

За один период: расходы на запас = цена часа запаса × часы; потери от нарушений = число запросов × доля нарушенных запросов × средняя цена одного нарушения

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

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

Учебный расчёт: точка безубыточности запаса

Назвать цену нарушения трудно, поэтому полезно перевернуть вопрос: посчитать, при какой цене запас окупается. Все числа ниже условные, цены — в условных единицах.

  • интерактивный сценарий: 1,2 млн запросов в сутки, всплески в рабочие часы;
  • без запаса автомасштабирование догоняет каждый всплеск через несколько минут холодного старта, и за сутки 25 000 запросов нарушают порог на первый токен;
  • одна дополнительная реплика, работающая круглосуточно, стоит 40 у. е. в час, то есть 960 у. е. в сутки, и снимает 90 % нарушений — 22 500 запросов.

цена нарушения, при которой запас окупается = 960 ÷ 22 500 ≈ 0,043 у. е.

Теперь разговор с продуктом сводится к одному вопросу: стоит ли одно нарушенное обещание больше четырёх сотых условной единицы. Для платного помощника в коде ответ почти наверняка «да», для внутреннего инструмента — возможно, «нет». У решения есть и промежуточные формы. Если всплески приходятся на восемь рабочих часов, запас по расписанию стоит 320 у. е. в сутки, и порог окупаемости падает до 0,014 у. е. на нарушение. Если пробуждение спящей реплики сокращает холодный старт до секунд, нужный запас уменьшается ещё сильнее: окно, которое он закрывает, становится короче.

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

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

09

Чеклист эксплуатации

Собранное в одном месте. Если из статьи нужно унести одну страницу — эту.

  • Записать обещание как пару порогов и долю запросов внутри них; отдельно для интерактивных сценариев и для пакетных. Для агентских сценариев пересчитать обещание на уровень задачи, а не одного вызова.
  • Развести три величины на дашборде: время до первого токена, темп генерации, сквозную задержку. Не усреднять их в одну кривую.
  • Вывести время в очереди отдельной метрикой: это граница между ответственностью модели и ответственностью ёмкости.
  • Разложить порог на первый токен в бюджет и получить из остатка на очередь порог тревоги по числу ожидающих запросов и лимит необработанного входа.
  • Посчитать ёмкость в токенах KV-кеша по архитектуре модели и сверить со строкой о размере кеша при старте движка; планировать по распределению длины контекста, а не по числу пользователей.
  • Смотреть на занятость KV-кеша и число вытеснений как на ранний признак: они меняются раньше, чем задержка.
  • Ограничить приём на входе: короткая очередь и ранний отказ лучше длинной очереди и позднего таймаута. В vLLM лимиты очереди по умолчанию выключены.
  • Разметить запросы приоритетами и проверить направление шкалы в своём движке и маршрутизаторе.
  • Определить деградацию заранее — длина, модель, режим, глубина поиска — и регулярно исполнять этот путь.
  • Ввести бюджет ретраев и экспоненциальную задержку: в инференсе повтор заново занимает память под весь контекст.
  • Масштабировать по очереди или по размеру пакета, а не по загрузке ускорителя.
  • Заложить в план холодный старт реплики: правило срабатывает мгновенно, мощность появляется через минуты.
  • Посчитать точку безубыточности запаса и пересчитывать её, когда меняется профиль трафика или скорость подъёма реплик.
Выводы

Что стоит унести с собой

  1. 01Обещание продукту — это пара порогов и доля запросов внутри них, а не число токенов в секунду. Индустрия записала такой формат раньше вас: MLPerf оценивает систему по устойчивой нагрузке внутри границ TTFT и TPOT, а исследователи называют эту меру полезной пропускной способностью.
  2. 02Три величины нельзя складывать в одну кривую: время до первого токена, темп генерации и сквозная задержка ломаются по разным причинам и лечатся разными ручками. Порог на первый токен раскладывается в бюджет, а остаток на очередь через закон Литтла превращается в порог тревоги.
  3. 03Ёмкость инференса измеряется памятью под контексты, а не числом запросов. В учебном узле из четырёх H100 с Llama 3.1 70B одна сессия на 128 тысяч токенов занимает место 43 обычных диалогов, и вытеснение видно отдельной метрикой раньше, чем жалобой.
  4. 04Ретрай в инференсе дороже, чем в обычном сервисе: он заново занимает память под весь контекст. Поэтому бюджет ретраев и заранее отрепетированная деградация здесь не гигиена, а несущая конструкция.
  5. 05Запас ёмкости — не расточительство, а плата за то, что реакция на рост измеряется минутами: новая реплика платит полный холодный старт до первой полезной работы. Вместо спора «дорого или медленно» полезно посчитать цену нарушения, при которой запас окупается.
Источники

Документация, стандарты и исследования

Список сгруппирован по роли источника. Пороги бенчмарков, настройки и метрики движков проверены по первичным страницам на 31 октября 2026 года; заявления проектов о собственных решениях и статус препринтов помечены в примечаниях.

Пороги и бенчмарки

  1. MLCommons · Llama 3.1-8B в MLPerf Inference v5.1 — источник порогов: Server — TTFT ≤ 2 с и TPOT ≤ 100 мс, Interactive — 0,5 с и 30 мс; там же перевод в слова в минуту
  2. MLCommons · MLPerf Inference v6.1 — раунд 16 сентября 2026 года: 30 участников, новые тесты агентного инференса и RAG, объявленная замена MLPerf Inference на MLPerf Endpoints для датацентров
  3. MLCommons · loadgen/mlperf.conf — пороги TTFT и TPOT по моделям и сценариям: Llama 2 70B Interactive — 450 и 40 мс, DeepSeek-R1 Interactive — 1500 и 15 мс

Движки инференса

  1. vLLM · Prometheus-метрики — перечень метрик, на которые опирается статья: TTFT, межтокенная задержка, время в очереди, занятость KV-кеша, вытеснения
  2. vLLM · Optimization and Tuning — вытеснение при нехватке KV-кеша, режим RECOMPUTE по умолчанию в V1, ручки против вытеснения и компромисс при смешивании обработки входа с генерацией
  3. vLLM · SchedulerConfig — политики fcfs и priority, лимиты max_num_queued_reqs и max_num_queued_tokens с ответом 503; второй лимит предложено задавать как целевое TTFT × скорость обработки входа
  4. vLLM · Engine Arguments — доля памяти движка по умолчанию 0,92, варианты типа KV-кеша, включая FP8
  5. vLLM · Parallelism and Scaling — что означают строки о размере KV-кеша и предельной параллельности при старте и когда добавлять ускорители
  6. vLLM · релиз v0.32.0 — актуальная версия на 31 октября 2026 года (18 октября)
  7. SGLang · Server Arguments — политики планировщика, --schedule-conservativeness, --chunked-prefill-size, --max-running-requests и приоритеты, где по умолчанию раньше идут большие значения
  8. SGLang · Hyperparameter Tuning — советы для пропускной способности офлайн-обработки: занятость KV-кеша выше 0,9 и очередь в сотни запросов; статья показывает, почему для интерактивного обещания это не цель
  9. Meta · llama-models, параметры архитектуры — Llama 3.1 70B: 80 слоёв, 64 головы внимания, 8 KV-голов, размерность 8192 — основа учебного расчёта KV-кеша

Исследования: планирование и SLO

  1. Zhong et al. · DistServe (OSDI 2024) — определение полезной пропускной способности через долю запросов внутри SLO; 1,6 против 3,3 запроса в секунду на ускоритель во вводном примере; до 7,4× запросов или в 12,6 раза более жёсткий SLO
  2. Agrawal et al. · Sarathi-Serve (OSDI 2024) — остановки генерации длиной до нескольких секунд, нарезка обработки входа и до 2,6× ёмкости для Mistral-7B при ограничении на хвост межтокенной задержки
  3. Sun et al. · Llumnix (OSDI 2024) — живая миграция запросов вместе с KV-кешем: хвост задержки лучше на порядок, приоритетные запросы до 1,5× быстрее, до 36 % экономии
  4. Patke et al. · QLM (SoCC 2024) — управление очередью по оценке времени ожидания: доля запросов внутри SLO +40–90 %, пропускная способность +20–400 % на требованиях облачного провайдера
  5. Chen et al. · SLOs-Serve — препринт апреля 2025 года о распределении токенов под ограничения SLO; ×2,2 к ёмкости на ускоритель на шести сценариях; на 31 октября 2026 года площадка не подтверждена
  6. Liu et al. · Andes — препринт о качестве потоковой выдачи: скорость чтения 4,8 и прослушивания 3,3 токена в секунду, выдача быстрее чтения не улучшает опыт

Исследования: память, нагрузка и холодный старт

  1. Kwon et al. · PagedAttention и vLLM (SOSP 2023) — в прежних системах на реальные состояния токенов уходило 20,4–38,2 % памяти KV-кеша; страничная раскладка дала 2–4× пропускной способности
  2. Patel et al. · Splitwise (ISCA 2024) — трейсы Azure: у помощника в коде медианный вход 1500 и ответ 13 токенов, у диалогового сервиса — 1020 и 129
  3. Wang et al. · BurstGPT (KDD 2025) — 213 дней трейсов региональных сервисов Azure OpenAI: всплески меняются в рабочие часы, доля отказов диалогового сервиса ChatGPT выше 5 %
  4. Qin et al. · Mooncake (FAST 2025) — архитектура сервиса Kimi: упреждающий отказ запросам, которые не уложатся в SLO; на 115 % и 107 % больше запросов на A800 и H800
  5. Qin et al. · Mooncake, расширенная версия — перегрузка в часы пик и эксперимент с ранним отказом на записи из 23 тысяч запросов: 4183, 3771 и 3589 отклонённых запросов
  6. Fu et al. · ServerlessLLM (OSDI 2024) — загрузка весов в 3,6–8,2 раза быстрее и снижение задержки на 10–200× при холодном старте
  7. Zhang et al. · BlitzScale (OSDI 2025) — загрузка весов по сети ускорителей и послойное масштабирование: хвост задержки до 94 % ниже ServerlessLLM, 49 % экономии времени ускорителей

Эксплуатация и перегрузка

  1. Google SRE · Addressing Cascading Failures — очередь как расход памяти и задержки, пример с запросом в 1,1 секунды, сброс нагрузки, деградация и серверный бюджет повторов
  2. Google SRE · Handling Overload — адаптивное ограничение на клиенте с K = 2, три попытки на запрос и бюджет повторов в 10 %: рост нагрузки около 1,1× вместо почти 3×
  3. Dean, Barroso · The Tail at Scale (CACM 2013) — 1 % медленных ответов у каждого из ста серверов делает медленными 63 % запросов; основа расчёта для цепочек вызовов агента
  4. Little · A Proof for the Queuing Formula: L = λW (1961) — закон Литтла, по которому бюджет ожидания переводится в число запросов в очереди
  5. Kingman · The single server queue in heavy traffic (1961) — приближение среднего ожидания в очереди G/G/1 произведением загрузки, вариабельности и времени обслуживания

Платформа и маршрутизация

  1. Google Cloud · автомасштабирование инференса на GKE — почему загрузка GPU — плохая метрика, как подбирать порог по очереди и по размеру пакета; страница обновлена 30 октября 2026 года
  2. Kubernetes · Introducing Gateway API Inference Extension — почему обычная балансировка не подходит длинным сессиям с частичным состоянием; что описывает InferencePool
  3. Gateway API Inference Extension · релиз v1.6.0 — август 2026 года: компонент выбора эндпоинта и InferenceObjective переехали в llm-d, проект сосредоточен на стандарте и тестах совместимости
  4. llm-d · релиз v1.0.0 — 20 октября 2026 года: управление потоком с приоритетами и сбросом нагрузки, DisaggregatedSet для пулов двух стадий
  5. llm-d · Flow Control — очереди по приоритетам, отрицательный приоритет как признак сбрасываемого запроса, ответ 429 при исчерпании лимита; механизм включается отдельной настройкой
  6. llm-d · Workload Autoscaling — масштабирование по очереди, запросам в работе и накопленным токенам; пересчёт необработанного входа в секунды ожидания против бюджета TTFT
  7. llm-d · Fast Model Actuation — пробуждение спящего экземпляра за секунды и запуск через подготовленный загрузчик за десятки секунд; заявление проекта о собственном решении
  8. vLLM · Zero-Reload Model Switching with Sleep Mode — числа пробуждения против холодного старта на A100 и два уровня сна; 18–20× на A100, около 200× на A4000; заявление проекта
  9. NVIDIA Dynamo · Planner Guide — версия 1.6: число реплик двух стадий подстраивается под цели TTFT и межтокенной задержки; по умолчанию — пороги очереди и занятости KV-кеша
Дальше

Связанные материалы

Это третья часть разговора об инференсе. Первая разбирает устройство, вторая — железо, эта — день после запуска.