Налаштування балансування навантаження між GPU-інстансами

Обчислювачі простоюють, а черга запитів усе зростає — знайома картина? Ми налаштовуємо балансування навантаження між GPU-інстансами під ключ: запити розподіляються так, що простій скорочується втричі, а відмови не доходять до користувачів. Обговоримо ваше завдання і повернемося з оцінкою та планом.
Часті запитання

Чому балансування GPU ламається під навантаженням

Черга завдань на кілька обчислювачів виглядає рівною лише на папері. У реальному потоці короткі запити до моделі перемішані з тривалими завданнями навчання, а частина з них надходить пачками від одного сервісу.

Поки балансування GPU орієнтується на кількість з’єднань, а не на фактичну зайнятість обчислювача, розподіл розходиться з реальним навантаженням.

Далі спрацьовує лавина: вузол, що отримав кілька важких завдань, тримає їх десятки хвилин, нові запити накопичуються в черзі, і час відгуку зростає нелінійно.

Сусідні обчислювачі в цей час простоюють — нерівномірне завантаження перетворюється на простій обчислювача, який оплачує замовник.

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

Перевантаження вузла виникає не від напливу трафіку, а від того, що диспетчер не знає, скільки роботи вже прийнято кожним обчислювачем.

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

Ефект від розподілу навантаження: черга, простій, відмови

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

Черга зростає на перевантаженому вузлі й порожніє на вільному, а хвіст очікування задає найдовший запит попереду — короткі завдання стоять за довгими.

Керований розподіл знімає це на рівні планування.

Планувальник дивиться на вільну пам’ять обчислювача, тип профілю, пріоритет завдання й історію відмов вузла; ізоляція NVIDIA дозволяє нарізати один прискорювач на незалежні профілі, тому велика модель і потік дрібних інференсів не конкурують за той самий ресурс.

Вузол, що видає помилки або втратив зв’язок із сховищем моделей, виводиться з ротації до усунення причини, а не після падіння завдань.

Метрики змінюються передбачувано. Завантаження обчислювачів вирівнюється: замість розкиду 40–90% тримається 80–85% на всьому парку.

Час очікування в черзі скорочується в рази завдяки тому, що медіана перестає залежати від хвоста, а пропускна здатність зростає в 1,8–2 раза за тієї ж кількості прискорювачів.

Клас відмов теж зсувається: зникають помилки «завдання не запустилося через брак пам’яті» й таймаути через перевантаження вузла, залишаються поодинокі збої конкретного обчислювача, які гасяться повтором на сусідньому профілі.

Під піком система деградує м’яко — зростає час очікування низькопріоритетних завдань, але термінові продовжують проходити, замість того щоб валити весь вузол разом із чужими завданнями.

Режими балансування GPU: порівняння підходів

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

Ми підбираємо режим під профіль навантаження: довжину контексту, частку критичних викликів, допустимий час очікування для фонових завдань. Нижче — підходи, які трапляються на практиці, та їхні обмеження.

Режим Коли підходить Обмеження
Циклічний перебір Однотипні короткі запити, вузли однакової потужності Не враховує фактичну довжину завдань: один вузол накопичує повільні виклики, решта простоюють
За поточним навантаженням Змішаний потік, різна довжина генерації Потрібен постійний збір метрик із вузлів; при рідкому опитуванні рішення запізнюються
Спільна черга з пріоритетами Критичні виклики поряд із фоновими пакетними завданнями Низькопріоритетні запити чекають довше — потрібен контроль, щоб вони не голодували
Резервування вузлів Сервіс із жорсткою вимогою до часу відповіді Виділена частина потужностей простоює в години низького навантаження
Прив’язка завдань до вузлів Великі моделі з довгим завантаженням ваг Знижується гнучкість: вузол не можна швидко віддати під іншу модель

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

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

Етапи налаштування розподілу запитів між вузлами

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

Без картини потоків будь-яке балансування перетворюється на підбір ваг навмання, і перший же сплеск показує, що черга зростала не там, де її чекали.

  1. Аудит потоків завдань. Знімаємо профіль звернень за кілька діб: які запити короткі й часті, які важкі та рідкісні, де піки, скільки займає очікування в черзі й на яку частку відмов припадає перевантаження. На виході — таблиця класів завдань з їхньою вагою та допустимим часом відповіді.
  2. Схема розподілу. Вибираємо, що кладемо в основу рішення: кількість активних запитів на вузлі, фактичне завантаження пам’яті прискорювача або черга очікування. Для коротких завдань ваги одні, для довгих — інші: змішувати їх в одному пулі майже завжди означає, що важкий запит тримає місце, поки легкі простоюють.
  3. Налаштування пріоритетів і черг. Розділяємо потоки за класами, задаємо граничний час очікування й правила повторних спроб, описуємо поведінку при виході вузла з ладу — запит має йти на живий вузол, а не чекати відмови. Тут же фіксуємо, які завдання допускають зниження точності розрахунку заради швидкості.
  4. Перевірка під навантаженням. Проганяємо профіль, знятий на аудиті, із запасом у кілька разів і зі штучними піками: дивимося, як змінюється час відповіді на 95-му процентилі запитів, як вирівнюється завантаження вузлів і що відбувається при вимкненні одного з них.
  5. Передача експлуатації. Віддаємо схему розподілу, налаштовані пороги, дашборди з ключовими метриками та інструкцію з додавання нових вузлів — щоб розширення не вимагало перезбирання логіки з нуля.

Опишіть ваш потік завдань — повернемося з планом робіт та оцінкою.

Комплект конфігурацій, схем і регламентів

Роботи закінчуються не демонстрацією, а передачею комплекту, з яким ваша команда експлуатує балансування прискорювачів і змінює його без нас. Усе оформлено так, щоб новий інженер розібрався за документами, а не за листуванням.

  • Конфігурація вузлів — значення параметрів розподілу запитів, лімітів пам’яті та пріоритетів черг, із позначкою, що можна змінювати вільно, а що пов’язано із сусідніми налаштуваннями.
  • Схеми потоків запитів — шлях від вхідної точки до конкретного прискорювача, точки відмови та поведінка системи, коли вузол випадає з ротації.
  • Регламент обслуговування — порядок планових робіт: виведення вузла, прогрів, повернення в роботу, оновлення профілів без зупинки сервісу.
  • Політики доступу — ролі та права: хто змінює параметри балансування, хто бачить лише метрики, як фіксується кожна зміна.
  • Документація по системі — архітектура, словник метрик, розбір типових відмов і послідовність дій при кожній.
  • Набір перевірок — панель спостереження, пороги спрацювання та маршрути сповіщень для чергової зміни.
  • Процедура відкату — як повернути попередній профіль конфігурації однією операцією і чим підтверджується, що повернення пройшло успішно.

Комплект живе разом із системою: зміни вносимо в ті самі документи й схеми, а не накопичуємо окремими листами.

Кейс: як скоротили простій обчислювачів утричі

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

Планувальник Kubernetes розподіляв контейнери за залишковим принципом, і на двох вузлах із восьми постійно висіла черга, поки сусідні простоювали. Короткі запити до моделей чекали по кілька хвилин, а навчання зривало терміни.

Ми розвели пул вузлів за класами завдань, вивели зайнятість прискорювача й відеопам’яті в окремий ресурс планування та додали перевірку живості перед постановкою в чергу — обробник, що впав, перестав тримати за собою місце. Окремо переписали пріоритети: короткий запит до моделі більше не стає за багатогодинним навчанням.

Метрики до й після: простій обчислювачів скоротився втричі, час очікування в черзі — з шести хвилин до сорока секунд. Розкид завантаження вузлів стиснувся з 35–95% до 70–85%, тобто вирівнювання навантаження перестало залежати від того, куди планувальник поставив перше завдання. Частка запитів, доведених до відповіді без перезапуску, зросла до 96%.

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

Чим розподіл запитів відрізняється від резервування вузлів?

Резервування вузлів — це про наявність запасного вузла поряд. Другий вузол тримають запущеним і синхронізованим з основним, але потік завдань усе одно йде в один — робочий. Резерв вмикається лише тоді, коли основний відвалився, і до цього моменту він не обробляє нічого.

Перемикання при збої закриває частину ризику: сервіс не падає цілком, а через паузу продовжує роботу. Але в цієї схеми є межа — на час перемикання запити чекають, частина довгих завдань обривається на середині, а подвоєння парку не дає приросту пропускної здатності.

Розподіл запитів працює на рівень вище. Потік завдань дробиться на порції та розкладається по всіх живих вузлах з урахуванням їхньої поточної зайнятості.

Відмова вузла не перериває потік: запити, які до нього не дійшли або не встигли завершитися, йдуть на сусідні, і відмовостійкість стає наслідком рівномірного завантаження, а не дублювання.

Щоб це працювало, потрібен облік зайнятості кожного вузла, довжина черги й час відповіді, перевірка живості та коректний повтор для перерваних завдань.

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

Межа проста. Резервування відповідає на питання «чи є куди переїхати», розподіл — «чи не простоює потужність і чи не накопичується черга». Простій резерву при нерівномірному навантаженні не лікується дублюванням: одна копія захлинається, друга нудьгує.

Часті технічні питання щодо розподілу навантаження

Балансувальник стає між сервісом і пулом прискорювачів: приймає запит, вибирає вузол за завантаженням пам’яті та довжиною черги, повертає результат коду, що викликав.

Тому перед впровадженням ми розбираємо чотири типових сумніви інженерів — сумісність із поточною схемою, метрики контролю, поведінку при відмові вузла та обсяг правок у застосунку.

Чи сумісно це з нашою поточною схемою?

Так, якщо застосунок звертається до моделі по мережі, а не тримає її всередині свого процесу. Ми описуємо точки підключення та зберігаємо попередні адреси: сервіс не знає, що вузлів стало більше, — маршрут змінюється на боці балансувальника.

Якими метриками контролюється розподіл?

Частка запитів на кожному вузлі, глибина черги очікування, час до першої відповіді та кількість повторів. Розкид завантаження між вузлами вище 10-15% — сигнал, що ваги або поріг перегріву виставлені неправильно.

Що відбувається при відмові вузла?

Перевірки живості виводять вузол із ротації за секунди, а запити, що вже пішли на нього, повторюються на живому вузлі. Код, що викликає, отримує відповідь, а не помилку — але лише якщо повторний виклик не створює дубля, тому обробку повторів ми перевіряємо окремо.

Чи потрібно змінювати застосунок і як проходить міграція?

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

Обговоримо вашу задачу: розподіл навантаження та відмовостійкість

Щоб повернутися з оцінкою та планом, а не із загальними словами, нам потрібен зріз вашої поточної схеми: як запити потрапляють на прискорювачі, де виникає черга — на вході балансувальника, у черзі завдань, через різне завантаження інстансів або через відмови окремих вузлів.

Далі разом фіксуємо постановку задачі та межі: що вважаємо успіхом — цільове завантаження прискорювачів, час відповіді під піком, поведінку системи при випадінні одного інстанса.

  • Постановка задачі — що саме балансуємо і за якою ознакою: довжина запиту, тип моделі, зайнятість пам’яті, пріоритет клієнта.
  • Вихідні дані — поточна схема розгортання, режим масштабування, логи й метрики за період роботи, відомі збої та їхні наслідки.
  • Оцінка та план робіт — які зміни зачіпають лише балансувальник, а де потрібне перезбирання черги або перерозподіл інстансів.
  • Терміни етапів — черговість: спочатку знімаємо метрики, потім вводимо правила розподілу, далі перевіряємо поведінку під навантаженням.
  • Формат співпраці — хто на вашому боці дає доступи до середовища й метрик, як узгоджуємо вікна змін.
  • Критерії приймання — числові пороги завантаження й часу відповіді, за яких роботу вважаємо завершеною.

Опишіть задачу у вільній формі та додайте те, що є з метрик, — повернемося з оцінкою, планом робіт і термінами етапів.

Напрямки AI-розробки

Останні роботи

  • Розробка сайту компанії B2B ADVANCE
    Розробка сайту компанії B2B ADVANCE
    1542
  • Розробка веб-додатків для компанії FEEDME
    Розробка веб-додатків для компанії FEEDME
    1393
  • Розробка веб-сайту для компанії БЕЛФІНГРУП
    Розробка веб-сайту для компанії БЕЛФІНГРУП
    1081
  • Розробка інтернет магазину для компанії FURNORO
    Розробка інтернет магазину для компанії FURNORO
    1368
  • Розробка логотипу компанії B2B Advance
    Розробка логотипу компанії B2B Advance
    815
  • Розробка веб-додатків для компанії Enviok
    Розробка веб-додатків для компанії Enviok
    1139