Две машини от клас DGX Spark, един модел: копие на всяка, вместо разделяне

Операции

Семем седмици локалният ни езиков модел работеше разделен между две машини NVIDIA GB10 с тензорен паралелизъм. На 22 октомври заменихме това с пълно копие на модела на всяка машина и прокси с най-малко връзки отпред. Пропускателната способност се увеличи от около 180 на 210 токена в секунда и сега всяка машина може да се рестартира, без да премахва модела.

Защо го бяхме разделили

Всяка машина има 128 GB памет, която CPU и GPU споделят. През септември моделът се побираше на една машина, но кешът му едва ли: използваната ни версия на vLLM не можеше да съхранява KV кеша на този модел във FP8, затова кешът беше в BF16 и на една машина имаше място за 499 110 токена от него. Това е по-малко от две заявки при пълния контекст на модела от 262 144 токена. Разделен между двете машини с тензорен паралелизъм през директната им мрежова връзка, кешът нарасна до над три милиона токена. Бяхме разделили модела за място, а не за скорост.

Какво се промени

По-нова 4-битова версия на същия модел (NVFP4, направена с квантизиращо-осмислено дистилиране) заема около 71 GiB памет, а общностна версия на vLLM за GB10 (eugr/spark-vllm-b12x) изпълнява кеша ѝ във FP8. Сега една машина побира целия модел и кеш от 0,76 до 1,08 милиона токена, място за 2,9 до 4,1 заявки при пълен контекст, в зависимост от това колко памет ѝ отделя машината. И двете копия използват собственото спекулативно декодиране на модела (MTP, четири черновикови токена). Превключването предходихме с нашия тест за извикване на инструменти върху новата версия: тя постигна 86, а заменената версия – 75.

Какво измерихме

Разделен между две машиниКопие на всяка машина
KV кешнад 3 милиона токена0,76 и 1,08 милиона токена
Заявки при пълен контекстоколо 122,9 и 4,1
Пропускателна способност при нашето натоварванеоколо 180 токена/с210 токена/с (111 + 99)
Стартиранеоколо 20 минути5 до 13 минути на копие
Рестартиране на една машинамоделът е недостъпендругото копие обслужва

Едно копие само по себе си, според броя на едновременните заявки: с кратки промпти 1 заявка дава 36 токена в секунда, 4 – 82, 8 – 109 и 16 – 150. С по-дългите промпти на нашия имейл агент 4 даваха 81, 8 – 113, а 16 – само 87: след осем такива заявки, повече заявки забавят работата.

За един следобед едното копие поемаше най-много 12 едновременни заявки, а другото – 8. Първото произвеждаше 91 до 93 токена в секунда и обработваше 26 до 27 заявки в минута; второто – 81 до 83 токена в секунда и 22 заявки в минута. И двете сега поемат по 12.

От какво се отказахме

От мястото. Разделеният модел имаше един кеш с повече от три милиона токена; копията имат два по-малки, а заявката може да използва само кеша на копието, което я обслужва. Нашите агенти изпращат много кратки и средни заявки и за тях пропускливостта беше по-важна. Ако обслужвате няколко много дълги контекста едновременно, разделянето може пак да е по-добрият избор. Запазихме разделената конфигурация и връщането назад става с един скрипт.

Какво се обърка при прехода

  1. Единадесет минути без модел, после 30 секунди с грешки 502. Разделеният модел трябваше да спре, преди копие да се зареди на същите машини, затова нашите агенти чакаха около единадесет минути. Когато първото копие стартира, прокси сървърът продължи да отговаря с „502 no live upstreams“ още около 30 секунди: той беше маркирал бекендите като неуспешни, докато бяха спрени (max_fails=3, fail_timeout=30s), и не ги опитваше отново, докато времето не изтече.
  2. Клиент, който заобикаляше прокси сървъра. Една от нашите пакетни задачи имаше адреса на първата машина в конфигурацията си, затова целият ѝ товар отиваше към едно копие, докато другото имаше свободен капацитет. Сега всеки клиент минава през прокси сървъра; адресите на самите машини са само за проверки на състоянието.
  3. Метрики, които подскачаха. Нашият монитор за пропускливост четеше /metrics на vLLM през прокси сървъра. С два бекенда последователните четения идваха от различни копия, броячите подскачаха нагоре-надолу и мониторът докладваше, че моделът е в застой. Сега той чете всяко копие директно и сумира данните.
  4. Стар watchdog, който би спрял новото копие. При разделената конфигурация имаше watchdog, който рестартираше услугата, когато моделът спреше да отговаря. Новата услуга декларира Conflicts= със старата, така че това рестартиране би спряло новото копие. Трябваше да бъде изключен с systemctl disable --now, а не просто спрян, защото нашият слой за експлоатация рестартира активираните, но неизпълняващи се единици.
  5. Паметта на машината, която върши и друга работа. Една машина изпълнява и нашите бази данни, и изграждането на сайтове. При gpu-memory-utilization 0.78 за vLLM оставаше само 5 GiB за всичко останало, затова го намалихме на 0.74 и рестартирахме само това копие, докато другото поемаше натоварването. На тези машини дялът, който давате на vLLM, се взема от същата памет като за всичко останало.

Ако имате две от тези машини

Factory Floor включва проксито и конфигурациите за стартиране за една или две машини, проверката за здраве и теста за използване на инструменти, който изпълняваме преди смяна на моделите, с watchdogs и защитни механизми за паметта за останалата част от машината.

Обновено: