Твой DGX Spark греется как утюг во время тренировки? Это не фича, а баг
Запускаешь плотный тренировочный цикл на Llama 3 70B, а через час система начинает троттлить, потому что GPU упираются в 90°C. Встроенные кулеры DGX Spark Rack справляются в теории, но на практике, в реальной стойке с ограниченным воздухообменом, они просто не успевают выгонять горячий воздух. Ты платишь за каждую секунду работы железа, а оно простаивает из-за перегрева.
Внимание: Модификация системы охлаждения может нарушить гарантийные условия. Все действия выполняются на свой страх и риск. Эта статья — техническое руководство, а не официальная рекомендация NVIDIA.
Проблема в том, что стандартная конфигурация рассчитана на идеальные условия дата-центра. В домашней лаборатории или небольшом офисе ты сталкиваешься с обратным потоком горячего воздуха, пылью и ограниченным пространством. Решение — внешняя система принудительного обдува, управляемая не вслепую, а по реальным показаниям датчиков GPU.
1 Что тебе понадобится: железо, а не магия
Забудь про «купи любые вентиляторы». Неправильный подбор компонентов даст тебе только лишний шум и ноль эффекта. Вот точный список, проверенный на трёх разных стойках.
| Компонент | Модель / Характеристики | Зачем нужен |
|---|---|---|
| Вентиляторы стоечные | 3 x Noctua NF-A14 industrialPPC-2000 PWM, 140 мм | Высокий статический давление, чтобы протолкнуть воздух через плотно упакованные GPU. PWM для точного контроля скорости. |
| PWM-хаб/контроллер | Aquacomputer QUADRO | Мозги системы. Управляет 4 вентиляторами по показаниям датчиков температуры. Подключается по USB. |
| Кабели, переходники | PWM splitter cable, набор M3 винтов (25 мм) | Для подключения трёх вентиляторов к одному порту контроллера и крепления к стойке. |
| Источник питания вентиляторов | Блок питания Molex/SATA на 12V (или запитаться от самого DGX, если есть свободные разъёмы) | QUADRO управляет сигналом PWM, но питание вентиляторов лучше взять отдельно. |
2 Схема размещения: куда дуть, чтобы не было хуже
Самая частая ошибка — поставить вентиляторы куда попало и надеяться на лучшее. В стойке важен направленный поток.
- Место: Установи три 140-мм вентилятора на переднюю дверцу стойки (или в переднюю панель, если она перфорирована), напротив воздухозаборов DGX Spark.
- Направление: Вентиляторы должны нагнетать холодный воздух из комнаты в стойку, создавая положительное давление. Это предотвращает подсос пыли через щели.
- Альтернатива: Если стойка закрытая, можно разместить вентиляторы на верхней крышке на вытяжку, но эффективность будет ниже на 15-20%.
Крепи вентиляторы на винты M3 через резиновые антивибрационные проставки (идут в комплекте с Noctua). Не используй двусторонний скотч — от вибрации всё отклеится через неделю.
3 Мозги системы: Python-скрипт, который думает о температуре
Теперь главное — логика управления. Контроллер QUADRO работает с софтом Aquasuite, но он под Windows. Наш DGX Spark работает под Linux. Пишем своего демона на Python.
Как НЕ надо делать: запускать бесконечный цикл с nvidia-smi и тупо выставлять скорость. Это жрёт CPU и создаёт лаги.
Вот рабочий скрипт, который использует библиотеку pyaquacomputer для общения с QUADRO и pynvml для опроса NVIDIA GPU. Он сглаживает показания и меняет скорость плавно.
#!/usr/bin/env python3
"""
DGX Spark Cooling Daemon
Управляет скоростью вентиляторов через Aquacomputer QUADRO
на основе температуры самого горячего GPU в системе.
"""
import time
import logging
from statistics import median
from datetime import datetime
from typing import List
import pynvml
from aquacomputer import Quadro
# ===== КОНФИГУРАЦИЯ =====
FAN_PORT = 0 # Номер порта на QUADRO, к которому подключен хаб с вентиляторами
POLL_INTERVAL = 5 # Секунды между опросами температуры
TEMP_HYSTERESIS = 2 # Гистерезис в °C, чтобы вентиляторы не дёргались
# Кривая температура -> скорость вентилятора (%)
# (температура_градусов, скорость_проценты)
FAN_CURVE = [
(40, 20), # До 40°C - почти тихо
(60, 40), # Нагрев до 60°C - умеренно
(75, 70), # 75°C - активно охлаждаем
(85, 100), # 85°C и выше - полная скорость
]
LOG_FILE = "/var/log/dgx_cooling_daemon.log"
# =======================
logging.basicConfig(
level=logging.INFO,
format='%(asctime)s - %(levelname)s - %(message)s',
handlers=[
logging.FileHandler(LOG_FILE),
logging.StreamHandler()
]
)
logger = logging.getLogger(__name__)
def get_gpu_temperatures() -> List[float]:
"""Возвращает список температур всех GPU в системе."""
temps = []
try:
pynvml.nvmlInit()
device_count = pynvml.nvmlDeviceGetCount()
for i in range(device_count):
handle = pynvml.nvmlDeviceGetHandleByIndex(i)
temp = pynvml.nvmlDeviceGetTemperature(handle, pynvml.NVML_TEMPERATURE_GPU)
temps.append(float(temp))
pynvml.nvmlShutdown()
except pynvml.NVMLError as e:
logger.error(f"NVML error: {e}")
return temps
def calculate_fan_speed(target_temp: float) -> int:
"""Вычисляет скорость вентилятора по кривой на основе температуры."""
# Если температура ниже минимальной точки кривой
if target_temp <= FAN_CURVE[0][0]:
return FAN_CURVE[0][1]
# Если температура выше максимальной точки кривой
if target_temp >= FAN_CURVE[-1][0]:
return FAN_CURVE[-1][1]
# Линейная интерполяция между точками кривой
for i in range(len(FAN_CURVE) - 1):
temp_low, speed_low = FAN_CURVE[i]
temp_high, speed_high = FAN_CURVE[i + 1]
if temp_low <= target_temp <= temp_high:
# Линейная интерполяция
ratio = (target_temp - temp_low) / (temp_high - temp_low)
return int(speed_low + ratio * (speed_high - speed_low))
return 50 # fallback
def main():
logger.info("Starting DGX Spark Cooling Daemon")
# Подключаемся к контроллеру QUADRO
try:
quadro = Quadro()
devices = quadro.detect_devices()
if not devices:
logger.error("No Aquacomputer QUADRO found!")
return
logger.info(f"Found QUADRO: {devices[0]}")
except Exception as e:
logger.error(f"Failed to connect to QUADRO: {e}")
return
last_speed = None
temp_history = []
try:
while True:
# Получаем температуры GPU
current_temps = get_gpu_temperatures()
if not current_temps:
time.sleep(POLL_INTERVAL)
continue
# Определяем температуру самого горячего GPU
max_temp = max(current_temps)
temp_history.append(max_temp)
# Держим только последние 5 измерений для сглаживания
if len(temp_history) > 5:
temp_history.pop(0)
# Используем медиану для фильтрации выбросов
smoothed_temp = median(temp_history)
# Рассчитываем необходимую скорость
new_speed = calculate_fan_speed(smoothed_temp)
# Применяем гистерезис: меняем скорость только если разница значительна
if last_speed is None or abs(new_speed - last_speed) >= 5:
try:
quadro.set_fan_speed(FAN_PORT, new_speed)
last_speed = new_speed
logger.info(
f"GPU temps: {current_temps}, max: {max_temp:.1f}°C, "
f"smoothed: {smoothed_temp:.1f}°C, fan speed: {new_speed}%"
)
except Exception as e:
logger.error(f"Failed to set fan speed: {e}")
time.sleep(POLL_INTERVAL)
except KeyboardInterrupt:
logger.info("Shutting down daemon")
# При завершении ставим вентиляторы на тихий режим
try:
quadro.set_fan_speed(FAN_PORT, 30)
except:
pass
except Exception as e:
logger.error(f"Unexpected error: {e}", exc_info=True)
if __name__ == "__main__":
main()
4 Развёртывание и запуск: превращаем скрипт в службу
Скопируй код в файл, например, /usr/local/bin/dgx_cooling_daemon.py. Сделай его исполняемым и установи зависимости.
# Устанавливаем зависимости
sudo apt update
sudo apt install python3-pip
sudo pip3 install pynvml aquacomputer
# Копируем и настраиваем скрипт
sudo cp dgx_cooling_daemon.py /usr/local/bin/
sudo chmod +x /usr/local/bin/dgx_cooling_daemon.py
# Создаём systemd службу для автозапуска
sudo nano /etc/systemd/system/dgx-cooling.service
Содержимое файла службы:
[Unit]
Description=DGX Spark Cooling Daemon
After=multi-user.target
[Service]
Type=simple
ExecStart=/usr/bin/python3 /usr/local/bin/dgx_cooling_daemon.py
Restart=always
RestartSec=10
User=root
[Install]
WantedBy=multi-user.target
# Активируем и запускаем службу
sudo systemctl daemon-reload
sudo systemctl enable dgx-cooling.service
sudo systemctl start dgx-cooling.service
# Проверяем статус и логи
sudo systemctl status dgx-cooling.service
sudo tail -f /var/log/dgx_cooling_daemon.log
Важно: Контроллер QUADRO должен быть подключён по USB к DGX Spark. Система увидит его как устройство HID. Убедись, что у пользователя (root в нашем случае) есть права на чтение/запись /dev/hidraw*.
Где это всё может сломаться: список частых косяков
- Вентиляторы не вращаются. Проверь, что PWM-хаб подключён правильно (стрелка на коннекторе к пину 4 — PWM сигнал). Питание 12V подано отдельно? QUADRO только даёт сигнал, а не питает мощные индустриальные вентиляторы.
- Скрипт падает с ошибкой «No device found». Подключи QUADRO к другому USB-порту. Выполни
lsusbи ищи Aquacomputer. Может потребоваться перезагрузка. - Температура всё ещё растёт. Убедись в направлении airflow. Воздух должен идти спереди назад через стойку. Проверь, нет ли физических препятствий (кабели, блоки питания других устройств). Если у тебя в стойке ещё и 4 видеокарты RTX Pro 6000 вплотную, проблема может быть в общем тепловом балансе всей стойки.
- Система шумит как реактивный двигатель. Отредактируй кривую
FAN_CURVEв скрипте. Снизь скорость на низких температурах. Noctua Industrial на 50% уже очень эффективны и гораздо тише.
А что, если у меня не DGX, а самосбор?
Принцип тот же. Если ты собрал 4 x RTX 5070 Ti в одном корпусе или даже бюджетный сервер на китайских GPU, проблема перегрева общая. Скрипт будет работать с любыми NVIDIA GPU через NVML. Просто адаптируй кривую охлаждения под тепловыделение своих карт.
Для действительно больших кластеров, где один DGX Spark работает в паре с Mac Studio или другим железом, важно мониторить температуру всех узлов централизованно. Скрипт можно доработать для отправки метрик в Prometheus или Grafana.
Итог: перегрев — это не приговор, а инженерная задача. Не надейся на автопилот производителя. Бери контроль над температурой в свои руки, жми на производительность железа, за которое заплатил. И да пребудет с тобой стабильный, холодный airflow.