Осведомленность о NUMA и привязка ЦП для выделенных серверов
16 мин чтения - 16 июня 2026 г.

Как проверить топологию NUMA и привязать рабочие нагрузки Linux к нужным ядрам и памяти. Охватывает numactl, taskset, systemd, настройки BIOS и стратегии для конкретных рабочих нагрузок.
Понимание NUMA и привязка ЦП для выделенных серверов
На любом сервере с несколькими сокетами место выполнения процесса и место хранения его памяти — это два разных вопроса, и их несогласованность — один из самых простых способов упустить возможность повысить производительность. Поддержка NUMA и привязка к процессору — это два рычага, которые позволяют решить эту проблему. В этой статье рассказывается о том, как работает NUMA, как проверить его в Linux и как правильно привязывать рабочие нагрузки для баз данных, обучения ИИ и сервисов, чувствительных к задержкам.
Как работает NUMA на серверах с несколькими сокетами
Узел NUMA (Non-Uniform Memory Access) — это группа ядер ЦП, связанных с локальным блоком ОЗУ через выделенный контроллер памяти. На двухпроцессорном сервере обычно имеется два узла. Любое ядро может читать любой адрес, но локальный доступ занимает примерно 80 нс, в то время как переход между сокетами через UPI от Intel или Infinity Fabric от AMD занимает около 130–150 нс. В более крупных системах с большим количеством сокетов в худшем случае время доступа к узлу может превышать 250 нс.
Пропускная способность следует той же схеме. Двухсокетная система на базе Sapphire Rapids может поддерживать около 600 ГБ/с при обращении ядер к локальной памяти, но пропускная способность межсокетного соединения составляет лишь небольшую часть этого значения, поэтому трафик, проходящий через него, быстро создает узкое место. Процессоры с большим количеством ядер делают эту структуру более детализированной: технология Sub-NUMA Clustering (SNC) от Intel и Nodes Per Socket (NPS) от AMD разделяют каждый сокет на несколько доменов NUMA, так что «двухсокетная» система может легко представлять Linux четыре или восемь узлов.
Без поддержки NUMA планировщик Linux будет без проблем перемещать поток между сокетами, в то время как его рабочий набор останется на исходном узле. Каждый последующий доступ становится удаленным. Видимым симптомом является высокая загрузка ЦП при низкой фактической пропускной способности, поскольку ядра тратят время на ожидание памяти. Устройства ввода-вывода усугубляют эту проблему. Графический процессор (GPU) или сетевая карта (NIC) подключены к определенному корню PCIe, который принадлежит одному узлу NUMA. Если процесс, подающий данные на него, работает на другом сокете, каждая передача DMA проходит через межсоединительную магистраль.
Проверка топологии NUMA в Linux
Четыре инструмента охватывают практически все необходимое:
lscpuдля быстрого обзора сокетов и узлов.numactl --hardwareдля получения данных об общем объеме памяти узлов и матрицы расстояний между узлами.numastatдля счетчиков попаданий/промахов на процесс.lstopo(из hwloc) для иерархии кэша и локальности устройств PCIe.
Начните с numactl --hardware. Здесь перечислены все узлы, ядра и память, относящиеся к ним, а также матрица расстояний. Значение 10 означает локальность, 20+ — удаленность. Если вы видите один узел на многопроцессорной системе, значит в вашем BIOS включена функция чередования узлов (Node Interleaving), которая скрывает топологию; сначала исправьте это (см. ниже).
Для конкретного процесса numastat -p <PID> показывает, где фактически выделена его память. Важны четыре счетчика:
numa_hit: память, выделенная на предполагаемом узле. Желательно, чтобы это значение было высоким.numa_miss: целевой узел был заполнен, выделение перешло в другое место.numa_foreign: другой узел пытался выделить память локально, но не смог, что указывает на нехватку памяти.other_node: страницы, выделенные на узле, отличном от того, на котором работает процесс. Высокие значения здесь являются классическим признаком плохой привязки.
Для рабочих нагрузок на GPU или сетевые карты запустите lstopo-no-graphics и посмотрите, к какому узлу NUMA подключено каждое устройство PCIe. Если ядра, управляющие устройством, находятся на другом узле, это первое, что нужно исправить.
Привязка к ядрам процессора и политики работы с памятью
Привязка к процессору (или аффинность к процессору) связывает процесс с конкретными ядрами, так что планировщик не может его перенести. Сама по себе этого недостаточно, поскольку Linux по умолчанию использует политику памяти «первого касания»: страницы выделяются на том узле, который первым записывает в них данные. Если поток запускается на неправильном узле до того, как он будет привязан, его память останется там. Необходимо контролировать как размещение, так и выделение памяти одновременно.
Три инструмента покрывают типичные случаи:
| Инструмент | Управление | Используется для |
|---|---|---|
taskset | Только ядра ЦП | Быстрая однократная привязка существующего процесса |
numactl | Ядра ЦП и память | Запуск рабочих нагрузок со строгой локальностью |
| systemd | Ядра ЦП и память, постоянная | Службы, требующие фиксации при перезагрузке |
numactl поддерживает четыре политики использования памяти:
--membind=N: выделять только на узле N, завершать с ошибкой, если он заполнен.--preferred=N: отдавать предпочтение узлу N, при необходимости переключаться на другие.--interleave=all: циклическое распределение между узлами для равномерного распределения пропускной способности.--localalloc: выделять на том узле, на котором находится работающий процессор.
Привязка рабочей нагрузки к одному узлу
Сначала определите, какие ядра принадлежат вашему целевому узлу:
numactl --hardwareЗатем запустите приложение, привязанное к этому узлу как по ядрам, так и по памяти:
numactl --cpunodebind=0 --membind=0 ./your_applicationДля уже запущенного процесса настройте привязку к ЦП с помощью taskset:
taskset -cp 0-7 <PID>Чтобы настройка сохранилась после перезагрузки, задайте ее в модуле systemd:
[Service]
CPUAffinity=0-7
NUMAPolicy=bind
NUMAMask=0Перезагрузите и перезапустите:
sudo systemctl daemon-reload && sudo systemctl restart <service>При ручной привязке отключите автобалансировку ядра, чтобы она не мешала вашему размещению:
sysctl -w kernel.numa_balancing=0Добавьте это в /etc/sysctl.conf для сохранения настроек. Затем проверьте с помощью numastat -p <PID> в течение нескольких минут реальной нагрузки. Если other_node остается близким к нулю, фиксация работает.
Выбор стратегии в зависимости от рабочей нагрузки
Правильный подход зависит от того, что приносит больше пользы для вашей рабочей нагрузки: низкая задержка или совокупная пропускная способность по всем узлам.
| Рабочая нагрузка | Политика | Почему |
|---|---|---|
| Базы данных (PostgreSQL, MySQL, SQL Server) | --cpunodebind + --membind | Большие общие буферы, пути запросов, чувствительные к задержкам |
| Кэш в памяти (Redis, Memcached) | Привязка к одному узлу | Все происходит через доступ к ОЗУ, задержка при удаленном доступе проявляется сразу |
| Обучение и инференция в области ИИ/машинного обучения | Привязка к узлу NUMA графического процессора | Избегает передачи тензоров через корни PCIe |
| Аналитика (Spark, Elasticsearch) | --interleave=all | Большой рабочий набор требует пропускной способности на всех узлах |
| API, чувствительные к задержкам, торговля | Строгая привязка к выводам + IRQ | Предсказуемость важнее пиковой пропускной способности |
| Интенсивное использование сети (RoCEv2, InfiniBand) | Привязка к NUMA-узлу сетевой карты, выделение ядер для IRQ | Обеспечивает локальную обработку прерываний, не мешая потокам приложений |
Специально для рабочих нагрузок на GPU запустите lstopo , чтобы определить, на каком узле NUMA находится GPU, а затем запустить процесс обучения или инференса с numactl --cpunodebind=N --membind=N для того же N. Это один из самых простых способов добиться успеха на многопроцессорном сервере с GPU, поскольку размещение по умолчанию планировщиком часто бывает неверным.
Для рабочих нагрузок HPC и MPI, охватывающих оба сокета, привяжите каждый ранг к отдельному узлу с помощью localalloc , а не чередуя все. Каждый ранг получает локальную память, и параллелизм происходит на уровне ранга.
Одно практическое замечание: если вы привязываете к одному узлу, оставьте на нем 2–4 ГБ свободного места. Узел, работающий почти на полной загрузке, запускает процесс освобождения памяти, что обходится вам в ту задержку, которую вы пытались сэкономить.
Настройки BIOS и ядра, которые необходимо проверить
Точность результатов инструмента зависит от топологии, предоставляемой прошивкой. Несколько настроек, которые необходимо проверить:
- Чередование узлов: отключите его. Когда эта функция включена, BIOS представляет всю память как единый плоский пул и полностью скрывает NUMA от ОС.
numactl --hardwareВ этом случае на многопроцессорном компьютере будет отображаться один узел. - Sub-NUMA Clustering (Intel) или Nodes Per Socket (AMD): включите на процессорах с большим количеством ядер, если требуется более точная локальность. Подтверждается
lscpuпосле перезагрузки. vm.zone_reclaim_mode: установите значение 0 для большинства производственных серверов. Ненулевое значение активно освобождает локальную память вместо выделения удаленно, что может привести к вытеснению полезного кэша страниц.kernel.numa_balancing: оставьте включенным для рабочих нагрузок общего назначения, отключите при ручной привязке. Автобалансировщик будет перемещать страницы и потоки способами, противоречащими вашей политике.
Если вы выполняете настройку NUMA на «голом железе», где вы контролируете BIOS, параметры ядра и аффинность IRQ, вы можете применить все вышеперечисленное, не обходя абстракции гипервизора. Это главная причина, по которой такая работа проще на выделенном оборудовании, чем в облачных виртуальных машинах.
Для многопроцессорных выделенных серверов с полным root-доступом см. выделенные серверы FDC.

Настроенные профили для оптимизации рабочей нагрузки Linux-сервера
Как выбирать, применять и настраивать профили для GPU, баз данных и Linux-серверов с высокой пропускной способностью, с примерами и советами по развертыванию Ansible.
16 мин чтения - 9 июня 2026 г.
Тюнинг Linux OOM Killer для VPS: практическое руководство
12 мин чтения - 8 июня 2026 г.

У вас есть вопросы или вам нужно индивидуальное решение?
Гибкие варианты
Глобальный охват
Мгновенное развертывание
Гибкие варианты
Глобальный охват
Мгновенное развертывание