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

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

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

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

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

01

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

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

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

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

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

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

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

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 процентов», уверенно выдаёт неприемлемый хвост — и добавленный ускоритель этот хвост почти не двигает.

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

04

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

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

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

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

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

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

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

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

05

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

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

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

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

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

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

06

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

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

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

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

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

Проект вводит понятие пула серверов модели, которым владеет платформа, и отдельный компонент, выбирающий эндпоинт под настроенные цели, — среди сигналов упоминаются состояние префиксного кеша и доступность адаптеров. Анонс опубликован 5 июня 2025 года; на сентябрь 2026 у проекта есть версия API v1 рядом с альфой.

В исследованиях эта же идея идёт дальше: препринт SLOs-Serve распределяет токены под ограничения нескольких SLO и заявляет рост ёмкости на ускоритель в среднем в 2,2 раза на шести сценариях — от суммаризации до вызова инструментов. Это сигнал направления, а не ожидаемый выигрыш: результат получен авторами на собственном наборе сценариев и независимо не воспроизведён.

07

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

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

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

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

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

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

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

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

08

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

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

решение = (цена часа запаса × часы) против (доля нарушенных запросов × цена одного нарушения)

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

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

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

09

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

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

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

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

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

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

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

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

  1. MLCommons · Llama 3.1-8B в MLPerf Inference v5.1 — источник порогов: Server — TTFT ≤ 2 с и TPOT ≤ 100 мс, Interactive — 0,5 с и 30 мс; там же перевод в слова в минуту

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

  1. vLLM · Prometheus-метрики — перечень метрик, на которые опирается статья: TTFT, межтокенная задержка, время в очереди, занятость KV-кеша, вытеснения
  2. vLLM · Optimization and Tuning — вытеснение при нехватке KV-кеша, режим RECOMPUTE по умолчанию в V1, ручки против вытеснения и компромисс при смешивании обработки входа с генерацией

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

  1. Google SRE · Addressing Cascading Failures — очередь как расход памяти и задержки, сброс нагрузки и деградация, арифметика усиления ретраями и бюджет ретраев
  2. Kingman's formula (VUT) — приближение среднего ожидания в очереди G/G/1 произведением загрузки, вариабельности и времени обслуживания; Кингман, 1961

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

  1. Google Cloud · автомасштабирование инференса на GKE — почему загрузка GPU — плохая метрика, как подбирать порог по очереди и по размеру батча
  2. Kubernetes · Introducing Gateway API Inference Extension — почему обычная балансировка не подходит длинным частично stateful сессиям; что описывает InferencePool
  3. Gateway API Inference Extension · документация проекта — состояние на сентябрь 2026: v1 рядом с v1alpha1, сигналы для выбора эндпоинта
  4. llm-d · Fast Model Actuation — из чего состоит холодный старт реплики и что именно ускоряет FMA; заявление проекта о собственном решении
  5. vLLM · Zero-Reload Model Switching with Sleep Mode — числа пробуждения против холодного старта на A100 и два уровня сна; заявление проекта, замеры на его моделях

Исследования

  1. Chen et al. · SLOs-Serve — препринт апреля 2025 о распределении токенов под ограничения SLO; ×2,2 к ёмкости на GPU на собственном наборе сценариев
Дальше

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

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