Что такое NUMA и как он влияет на производительность серверов
В современных серверах производительность определяется не только количеством ядер и частотой CPU, но и тем, как именно процессоры получают доступ к памяти. Именно здесь появляется NUMA — архитектура, которую важно понимать каждому, кто работает с backend, базами данных или высоконагруженными сервисами.
Кратко: UMA vs NUMA
UMA (Uniform Memory Access) — классическая модель:
- вся оперативная память равноудалена от всех процессоров;
- время доступа к памяти одинаковое;
- просто, но плохо масштабируется.
NUMA (Non-Uniform Memory Access):
- память физически разделена на узлы (NUMA nodes);
- каждый процессор (или группа ядер) имеет «свою» локальную память;
- доступ к удалённой памяти медленнее.
Чем больше сервер (2+ сокета CPU), тем выше вероятность, что он работает именно в NUMA-режиме.
Как устроен NUMA внутри сервера
Типичный NUMA-сервер состоит из:
- нескольких CPU сокетов;
- у каждого сокета есть собственный контроллер памяти;
- часть RAM подключена напрямую к этому сокету.
Каждый такой набор образует NUMA node.
Когда поток выполняется на ядре CPU:
- обращение к локальной памяти — быстро;
- обращение к памяти другого NUMA-узла — медленнее (через межпроцессорную шину).
Разница в латентности может составлять 1.5–3 раза, а иногда и больше.
Почему NUMA может резко замедлить приложение
NUMA начинает «стрелять», когда:
- процесс активно работает с памятью;
- потоки часто мигрируют между CPU;
- память аллоцируется на одном узле, а используется на другом.
Типичные симптомы:
- CPU не загружен, а приложение медленное;
- высокая latency без видимых причин;
- нестабильная производительность под нагрузкой.
Это особенно критично для:
- баз данных (PostgreSQL, MySQL, MongoDB);
- JVM-приложений;
- in-memory кэшей;
- high-performance сетевых сервисов.
Как Linux работает с NUMA
Linux NUMA-aware, но не всегда оптимален «из коробки».
Что он делает:
- старается выделять память локально;
- может мигрировать страницы памяти;
- может перемещать процессы между ядрами.
Проблема в том, что:
- scheduler не знает семантику приложения;
- автоматическая миграция памяти — дорогая операция;
- неправильный баланс может быть хуже, чем его отсутствие.
Как посмотреть NUMA на сервере
Проверить NUMA-топологию:
numactl --hardwareВывод покажет:
- количество NUMA nodes;
- какие CPU относятся к каждому узлу;
- объём локальной памяти.
Удобные команды:
lscpu | grep NUMA
numastatПривязка процессов и памяти
Для контроля NUMA используются:
- CPU affinity — к каким ядрам привязан процесс;
- memory policy — с каких узлов выделяется память.
Пример запуска процесса с привязкой:
numactl --cpunodebind=0 --membind=0 ./appЭто гарантирует:
- выполнение на одном NUMA-узле;
- использование локальной памяти;
- предсказуемую производительность.
NUMA и базы данных
Большинство СУБД чувствительны к NUMA:
PostgreSQL:
- часто рекомендуют запускать инстанс в пределах одного NUMA node;
- или вручную настраивать
numactl.
MySQL / MariaDB:
- возможен серьёзный degradation без NUMA binding;
- InnoDB buffer pool особенно чувствителен.
MongoDB / Redis:
- выигрывают от строгой локальности памяти.
Когда NUMA можно игнорировать
NUMA почти не влияет, если:
- сервер с одним CPU сокетом;
- приложение CPU-bound без активной работы с памятью;
- нагрузка низкая и нерегулярная.
Но на production-серверах с 64–256 ядрами — это уже обязательная тема.
Практические рекомендации
- Всегда проверяй NUMA-топологию сервера
- Для БД и high-load сервисов используй
numactl - Избегай лишней миграции потоков
- Тестируй производительность с NUMA и без
- Не полагайся полностью на автоматику Linux
Итог
NUMA — это не экзотика, а стандарт для современных серверов. Он может:
- дать прирост производительности;
- или незаметно убить latency.
Понимание NUMA — обязательный навык для backend-инженера, DevOps и SRE, работающих с реальными нагрузками.
Настроить мониторинг за 30 секунд
Надежные оповещения о даунтаймах. Без ложных срабатываний