Выгрузка KV-кэша — это процесс перемещения attention-данных (ключей и значений) из памяти GPU в более дешёвое хранилище, например, в оперативную память CPU или на диск. Это освобождает ресурсы GPU, но позволяет возобновлять инференс без пересчёта. Такой подход помогает масштабировать LLM-нагрузки, балансируя между производительностью и использованием памяти.
Почему KV-кэш становится узким местом в инференсе LLM?#
LLM сильно зависят от KV-кэша для ускорения инференса. Кэш хранит attention-ключи и значения для каждого токена входной последовательности, позволяя модели переиспользовать их на следующих шагах вместо пересчёта. Это экономит вычисления и ускоряет инференс, но требует много памяти.
С ростом окна контекста размер KV-кэша растёт линейно с длиной последовательности. Это быстро приводит к исчерпанию памяти GPU, особенно при длинных контекстах. Поскольку память GPU ограничена, KV-кэш часто становится узким местом для приложений, которым нужен расширенный контекст.
На самом деле, не все данные KV-кэша должны постоянно находиться в памяти GPU. Во многих реальных сценариях пользователи не взаимодействуют с LLM непрерывно: кто-то делает паузу при вводе или возвращается через часы. В таких случаях их KV-кэш остаётся в памяти GPU, хотя не используется. Аналогично, если несколько пользователей или агентов обращаются к одному диалогу/документу в разное время, один и тот же KV-кэш может простаивать на GPU между сессиями (и не хочется тратить ресурсы GPU только ради пересчёта одного и того же).
В итоге память GPU расходуется неэффективно: она занята неактивными сессиями вместо обслуживания новых запросов. Со временем это ограничивает число одновременных пользователей и снижает общий throughput.
Чтобы решить эти проблемы, KV cache offloading перемещает неактивные или редко используемые данные кэша из памяти GPU в более дешёвое и ёмкое хранилище: оперативную память CPU, локальные SSD или удалённое object storage. Когда пользователь возвращается или другой пользователь обращается к тому же контенту, кэш можно вернуть в память GPU по требованию. Это позволяет избежать дорогого пересчёта и освобождает ресурсы GPU для активных задач.
Как посчитать размер KV-кэша#
При организации offloading полезно понимать, сколько памяти реально занимает KV-кэш.
В трансформерах каждый attention-слой хранит два вектора (key и value) для каждого токена входа. В каждом слое несколько attention-head’ов, обычно одинаковой размерности.
Для оценки объёма памяти используйте калькулятор:
KV Cache Memory Calculator
Оценка памяти, требуемой для KV-кэша в трансформерных LLM
Формула и пояснения
KV Cache Size (GB) = 2 × B × S × L × H × D × (Q / 8) / (1024³)
• ×2 — потому что хранятся и Key, и Value
• (Q / 8) — перевод бит в байты
• / (1024³) — перевод байт в гигабайты
Размер растёт линейно с длиной последовательности. При длинных контекстах KV-cache может стать основным потребителем памяти.
Если вы уже знаете размерность модели, можно упростить формулу, подставив H × D (см. упрощённый расчёт выше).
Когда стоит выгружать KV-кэш для LLM#
KV cache offloading особенно полезен, если:
- Вы используете LLM с длинным окном контекста, и KV-кэш быстро превышает объём памяти GPU.
- Несколько пользователей или агентов работают с одним и тем же контентом/контекстом в разных сессиях (например, разработчики в IDE часто обращаются к одним и тем же фрагментам кода).
- Ваш деплой ограничен по памяти или вы хотите оптимизировать инфраструктурные расходы.
- Вы масштабируете инференс на много распределённых воркеров с ограниченными GPU-ресурсами.
- В нагрузке есть прерывистые или “спящие” сессии, и держать их KV-кэш в памяти GPU нерационально.
Преимущества выгрузки KV-кэша#
Offloading KV-кэша даёт несколько важных плюсов для масштабирования и оптимизации инференса LLM:
- Лучшее использование ресурсов. Перемещая неактивные или общие KV-данные из памяти GPU, вы освобождаете место для новых запросов. Это позволяет обслуживать больше пользователей или длиннее последовательности на том же GPU без переполнения памяти.
- Снижение стоимости вычислений. Память GPU дорогая и ограниченная. Offloading позволяет использовать более дешёвое хранилище (например, RAM CPU или диск), уменьшая потребность в дорогих GPU только ради кэша.
- Меньше задержка. Offloading позволяет модели пропускать повторные вычисления KV-кэша при инференсе, особенно при перекрывающемся контексте в многоходовых диалогах. Это значительно снижает TTFT и общую задержку. NVIDIA сообщает, что выгрузка KV-кэша может ускорить TTFT до 14 раз для длинных последовательностей по сравнению с пересчётом с нуля.
Компромиссы производительности при offloading KV-кэша#
Хотя offloading KV-кэша может сильно повысить эффективность памяти и throughput, критична скорость целевого хранилища. Если RAM CPU или диск слишком медленные, накладные расходы на возврат KV-данных в GPU могут свести на нет все плюсы, особенно в задачах с жёсткими требованиями к задержке.
В общем, выгружать кэш стоит только если стоимость передачи данных ниже, чем пересчёт с нуля. Это часто так в длинных диалогах, где важно переиспользовать контекст, а пересчёт был бы дорогим.
Выгрузка KV-кэша с помощью LMCache#
LMCache — расширение для движков инференса LLM, оптимизирующее инференс за счёт снижения TTFT и увеличения throughput, особенно для длинных контекстов. LMCache поддерживает переиспользование KV-кэшей для повторяющегося контента (не только префиксов) между разными инстансами движка.
LMCache хранит KV-кэши в нескольких уровнях памяти: GPU, DRAM CPU, локальный диск. Это резко снижает избыточные вычисления, ускоряет ответы и экономит GPU-циклы — идеально для задач вроде многоходовых QA, RAG, reasoning по документам.
В бенчмарках связка LMCache + vLLM давала 3–10-кратное снижение задержки в разных сценариях.
Ряд open-source проектов уже интегрировали LMCache для эффективного offloading и переиспользования KV-кэша:
- llm-d выгружает KV-кэш с помощью LMCache из памяти GPU в более дешёвое и ёмкое хранилище (CPU, сетевые диски).
- KServe интегрирует LMCache для снижения стоимости инференса и соблюдения SLO по задержке и throughput на масштабе.
- vLLM использует LMCache для offloading на CPU, шаринга кэша между запросами и дисагрегированного prefill — это улучшает управление памятью и эффективность ресурсов.
LMCache поддерживает offloading KV-кэша в разные типы хранилищ: от локальных (оперативная память CPU, файловая система) до распределённых систем вроде Mooncake и ValKey.
