中文翻译暂不可用,显示俄语原文。
Как работает scheduler в vLLM? Какие алгоритмы выбора запросов?
Краткий тезис
vLLM — это высокопроизводительная библиотека для инференса LLM, ключевая особенность которой — эффективное управление памятью через PagedAttention. Scheduler в vLLM отвечает за то, какие запросы (промпты) попадают в батч на каждом шаге генерации, учитывая доступные блоки KV-кэша и приоритеты. По умолчанию используется First-Come-First-Serve (FCFS), но поддерживаются также priority-based и fairness-алгоритмы, а при нехватке памяти применяется preemption (вытеснение) с возможностью swapping или recomputation.
1. Термин: vLLM и его архитектура
vLLM — open-source библиотека для инференса больших языковых моделей, разработанная в UC Berkeley. Её главное нововведение — PagedAttention, которая разбивает KV-кэш на блоки фиксированного размера (обычно 16 токенов), что позволяет:
- Избежать фрагментации памяти (не нужно резервировать место под максимальную длину последовательности).
- Делить память между запросами в батче.
- Поддерживать continuous batching — добавлять новые запросы в батч по мере завершения старых, без ожидания полного завершения всех.
Scheduler — центральный компонент, который решает, какие запросы выполнять на каждом шаге декодирования, и управляет аллокацией/освобождением блоков.
2. Основные понятия: блоки, sequence, батч
- Block — единица KV-кэша (фиксированное число токенов, например 16). Каждый блок имеет уникальный идентификатор и состояние (free / allocated / swapped).
- Sequence — один запрос (промпт + генерируемые токены). Каждая sequence хранит логическую таблицу отображения токенов на физические блоки (page table).
- Batching — группировка нескольких sequences для параллельного выполнения на GPU. vLLM использует continuous batching: батч динамически меняется между шагами.
Scheduler оперирует этими сущностями: он решает, какие sequences добавить в батч (на основе доступных блоков и политики), а какие приостановить (preempt).
3. Задачи scheduler'а
Основные функции:
- Выбор запросов для включения в текущий батч (scheduling policy).
- Управление памятью: проверка, хватит ли свободных блоков для нового запроса или для продолжения существующего.
- Preemption — вытеснение части sequences при нехватке памяти.
- Обработка завершённых запросов — освобождение блоков и удаление из очереди.
Scheduler работает на каждом шаге генерации (после выдачи очередного токена для всех sequences в батче). Он получает информацию о текущем состоянии памяти (сколько блоков свободно) и решает, можно ли добавить новые запросы из очереди ожидания.
4. Алгоритмы выбора запросов
4.1 First-Come-First-Serve (FCFS) — по умолчанию
Запросы обрабатываются в порядке поступления. Очередь — FIFO. Если для нового запроса не хватает блоков, он ждёт, пока освободятся блоки от завершённых sequences.
Плюсы: простота, предсказуемость, отсутствие голодания (starvation). Минусы: нет приоритетов; длинные запросы могут блокировать короткие, если память ограничена.
4.2 Priority-based
Каждому запросу присваивается приоритет (например, от 0 до 10). Scheduler выбирает запросы с наивысшим приоритетом, которые могут быть обслужены с учётом доступных блоков. При равных приоритетах — FCFS.
Плюсы: гибкость для SLA (например, платные пользователи выше). Минусы: возможное голодание низкоприоритетных запросов; требуется механизм назначения приоритетов.
4.3 Fairness (справедливость)
Scheduler стремится равномерно распределять ресурсы (блоки) между запросами или между группами (например, по пользователям). Реализуется через weighted fair queuing или round-robin с учётом потребления блоков.
Плюсы: предотвращает монополизацию одним запросом. Минусы: сложнее в реализации; может увеличить latency для отдельных запросов.
4.4 Комбинированные стратегии
На практике часто используют гибриды: например, приоритет + fairness внутри одного приоритета. vLLM позволяет задавать политику через конфигурацию (параметр --scheduling-policy).
5. Учёт available blocks
Scheduler перед добавлением запроса проверяет:
- Сколько блоков нужно для префилла (промпта) — вычисляется как ceil(len(prompt) / block_size).
- Сколько блоков нужно для декодирования (обычно 1 блок на шаг, но может быть больше при использовании speculative decoding).
- Текущее количество свободных блоков в пуле.
Если блоков достаточно — запрос добавляется в батч. Если нет — scheduler либо ждёт, либо применяет preemption.
6. Preemption (вытеснение)
Когда свободных блоков не хватает для нового запроса, а очередь ожидания не пуста, scheduler может вытеснить одну или несколько уже выполняющихся sequences. Есть два режима:
6.1 Swapping (свопинг)
KV-кэш вытесняемой sequence выгружается из GPU в CPU (в специальный буфер). Когда блоки снова освобождаются, sequence может быть восстановлена (загружена обратно). Это дорого по latency, но позволяет не терять прогресс генерации.
6.2 Recomputation (перевычисление)
Sequence полностью удаляется из GPU, а её KV-кэш отбрасывается. Позже, когда ресурсы появятся, sequence начинается заново с префилла (промпт обрабатывается снова). Это дешевле по памяти, но требует повторного вычисления.
Выбор режима зависит от конфигурации: --preemption-mode (swap / recompute / hybrid). По умолчанию — recompute, так как он проще и не требует CPU-памяти.
7. Continuous batching и роль scheduler'а
Continuous batching — ключевая особенность vLLM. В традиционном статическом батчинге все запросы в батче начинаются и заканчиваются одновременно. В continuous batching:
- На каждом шаге scheduler может добавить новые запросы (после префилла) и удалить завершённые.
- Батч динамически меняется, что повышает утилизацию GPU.
Scheduler решает, когда добавить новый запрос: обычно после того, как хотя бы одна sequence завершилась (освободились блоки) или если есть свободные блоки, но нет активных sequences (начало работы).
8. Сравнение алгоритмов
| Алгоритм | Принцип | Плюсы | Минусы | Типичное использование |
|---|---|---|---|---|
| FCFS | Порядок поступления | Простота, предсказуемость | Нет приоритетов, длинные запросы блокируют короткие | По умолчанию, тестирование |
| Priority-based | Приоритет запроса | Гибкость SLA | Голодание низкоприоритетных | Продакшн с разными уровнями сервиса |
| Fairness | Равное распределение блоков | Справедливость, защита от монополизации | Сложность, возможен рост latency | Мультитенантные системы |
| Гибрид | Приоритет + fairness | Баланс | Требует тонкой настройки | Enterprise-решения |
9. Пример псевдокода scheduler'а (упрощённо)
class Scheduler:
def __init__(self, policy='fcfs', block_pool, max_blocks_per_seq):
self.policy = policy
self.waiting_queue = deque()
self.running = set()
self.block_pool = block_pool # manages free/used blocks
def schedule_step(self):
# 1. Remove finished sequences, free their blocks
for seq in list(self.running):
if seq.finished:
self.block_pool.free(seq.blocks)
self.running.remove(seq)
# 2. Try to add new sequences from waiting queue
while self.waiting_queue:
seq = self._select_next(self.waiting_queue)
needed = seq.num_blocks_needed()
if self.block_pool.available() >= needed:
self.block_pool.allocate(seq, needed)
self.running.add(seq)
self.waiting_queue.remove(seq)
else:
# 3. Preempt if needed
if self._should_preempt():
victim = self._select_victim()
self._preempt(victim)
continue
else:
break
def _select_next(self, queue):
if self.policy == 'fcfs':
return queue[0]
elif self.policy == 'priority':
return max(queue, key=lambda s: s.priority)
elif self.policy == 'fairness':
# Simplified: round-robin among groups
...
10. Пет-проект для закрепления
Задача: Реализовать симулятор scheduler'а vLLM на Python, который моделирует continuous batching с разными политиками.
Инструменты: Python, NumPy (для генерации запросов), Matplotlib (для визуализации).
Шаги:
- Создать класс
BlockPoolс фиксированным числом блоков (например, 1024). - Создать класс
Sequenceс полями:prompt_len,max_tokens,priority,group_id. - Реализовать
Schedulerс методамиadd_request,step,preempt. - Реализовать три политики: FCFS, priority, fairness (по группам).
- Сгенерировать случайные запросы (длины, приоритеты) и прогнать симуляцию.
- Измерить метрики: среднее время ответа, пропускная способность, количество preemption'ов.
- Построить графики зависимости latency от нагрузки для разных политик.
Ожидаемый результат: Вы увидите, что FCFS даёт наименьшую вариативность latency, priority — ускорение для высокоприоритетных запросов, fairness — равномерное распределение ресурсов между группами.
11. Связь с другими вопросами
| Вопрос | Тема |
|---|---|
| 206 | Как работает PagedAttention в vLLM? |
| 208 | Что такое continuous batching и как он реализован? |
| 209 | Как vLLM управляет KV-кэшем при длинных контекстах? |
| 210 | Какие есть альтернативы vLLM для инференса LLM? |
| 115 | Как вы оптимизируете latency инференса LLM? |
| 118 | Что такое speculative decoding и как он работает? |
12. Навигация
- Предыдущий: 206
- Следующий: 208
- Индекс: 00. Индекс разборов
Навигация
- Предыдущий: 206
- Следующий: 208
- Индекс: 00. Индекс разборов