К основному содержимому
к странице архива
#Research

[2/2] DistServe: параллелизм, очереди и баланс GPU (Рубрика #Research)

В первой части поста мы остановились на разделения prefill и decode. И после этого у нас появляется свобода: каждой стадии можно выделить свои GPU и по-своему распределить модель. Теперь эту свободу надо превратить в работающую конфигурацию.

Есть два подхода к параллелизму: - Intra-op делит одну операцию, например умножение матриц, между GPU. В этом контексте — tensor parallelism. Отдельный шаг выполняется быстрее, но GPU часто обмениваются данными. Ускорение зависит от того, сколько съедает коммуникация. - Inter-op делит слои модели на стадии конвейера — pipeline parallelism. Пока одна GPU обрабатывает следующий запрос, другая заканчивает предыдущий. Запрос всё ещё проходит все стадии; зато конвейер пропускает больше запросов. Расплата — простои, если стадии загружены неравномерно.

То есть можно ускорять прохождение одного запроса, а можно увеличивать частоту, с которой конвейер принимает следующие. Под нагрузкой второй вариант тоже сокращает задержку: меньше времени уходит на ожидание входа.

Здесь авторы достают из чулана теорию очередей. Для начала они упрощают prefill: одинаковые промпты, постоянное время обработки D, пуассоновский поток R запросов/с, одна обслуживающая очередь без батчинга. Получается модель M/D/1:

TTFT = D + R·D² / [2·(1 − R·D)]

Это среднее время: вычисление плюс ожидание. Формула работает при R·D < 1. Если D = 100 мс, при 5 запросах/с среднее TTFT составит 150 мс, а при 9 запросах/с — 550 мс. Само вычисление осталось тем же. Выросла очередь.

Для двух GPU авторы сравнивают: - intra-op: D/K + R·D² / [2K·(K − R·D)] - inter-op: D + R·D² / [4·(2 − R·D)]

K — ускорение intra-op, здесь между 1 и 2. Во втором случае предполагаются две равные стадии и пренебрежимо малый обмен между ними. Каждая формула применима, пока соответствующая очередь устойчива.

При редких запросах intra-op выигрывает за счёт быстрого вычисления. По мере роста потока inter-op может выиграть за счёт очереди. Очень строгий TTFT снова делает скорость отдельного запроса критичной. У decode свой баланс: размер батча, память под кэш и требование к TPOT. Правила «prefill всегда так, decode всегда иначе» здесь нет.

Но реальные промпты и ответы разной длины, а сервису нужна заданная доля запросов в SLO. Одной формулы среднего недостаточно.

Поэтому дальше ребята переходят к симуляции нагрузки. DistServe использует модель времени вычислений и профиль запросов: интенсивность поступления, распределения длин входа и выхода. Перебирает допустимые конфигурации параллелизма и размещения, а бинарным поиском находит поток, при котором ещё соблюдается целевой SLO attainment. Затем подбирает число экземпляров стадий под требуемую нагрузку. При медленной сети варианты prefill и decode приходится выбирать совместно.

Получается баланс для конкретной модели, железа, нагрузки и SLO. Когда профиль меняется, расчёт надо повторять. Формулы объясняют механизм, симулятор помогает выбрать конфигурацию; проверка на настоящем кластере остаётся необходимой.

В продолжении рассмотрении этой темы дальше я планирую прочитать несколько статей и потрогать llm-d. План примерно такой - Splitwise, ISCA 2024 — соседняя работа про выбор разного железа для фаз, стоимость и энергопотребление. - Sarathi-Serve, OSDI 2024 — другая ветка: дробить prefill на части и совмещать их с decode через планирование батчей. - Mooncake, FAST 2025 — другой масштаб: распределённый KV-кэш, его хранение и повторное использование становятся центром архитектуры.

А в мае 2025-го llm-d уже предложил объединять disaggregated serving и маршрутизацию с учётом кэша с Kubernetes-инфраструктурой. Так что через эти работы можно пройти путь от разделения двух стадий до управления вычислениями и состоянием всего кластера.

#Research #AI #Architecture #Engineering #DistributedSystems