Охлаждение DGX Spark Rack: код мониторинга температуры и компоненты | AiManual
AiManual Logo Ai / Manual.
03 Янв 2026 Гайд

DGX Spark плавится? Собираем систему охлаждения с интеллектом, а не просто вентиляторы

Готовое решение для перегрева DGX Spark: список железа, схема сборки и Python-скрипт для автоматического управления вентиляторами по температуре GPU.

Твой 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, но питание вентиляторов лучше взять отдельно.
💡
Почему именно QUADRO, а не дешёвый реобас? Потому что нам нужна программная логика. Реобас крутит вентиляторы на постоянной скорости. QUADRO позволяет задать кривую: «если GPU0 > 70°C, увеличить скорость с 40% до 80%». Это экономит тишину и ресурс вентиляторов.

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.