Що таке NUMA і чому це важливо на двох процесорах
NUMA (Non-Uniform Memory Access) — архітектура пам'яті двопроцесорного сервера, де у кожного CPU є "своя" пам'ять зі швидким доступом і "чужа" пам'ять іншого сокета з доступом через міжпроцесорну шину. Тема актуальна насамперед для серверів з двома і більше сокетами — те, як обрано процесор, напряму визначає кількість вузлів NUMA та їхній розмір.
Якщо застосунок не враховує NUMA, планувальник ОС може розмістити процес на одному сокеті, а пам'ять виділити на іншому. Результат — просідання продуктивності без видимої причини в моніторингу CPU.
Як подивитись топологію NUMA
lscpu | grep -i numa
numactl --hardware
Команда numactl --hardware покаже кількість вузлів, обсяг пам'яті на кожному та відстані між вузлами (node distances). Значення 10 — звернення до свого вузла, 20-21 — до сусіднього: чим вище число, тим дорожчий промах.
Проблема: пам'ять "не свого" вузла
Типовий сценарій: сервер на двох процесорах, 256 ГБ пам'яті, застосунок запущено без прив'язки. Планувальник Linux переносить процес між ядрами різних сокетів, а виділена пам'ять залишається на першому вузлі. Кожне звернення до другого сокета йде через міжпроцесорний інтерконнект, і затримка зростає.
Це особливо помітно на серверах баз даних, де кеш і буфери мають жити поруч з ядрами, які читають їх тисячі разів на секунду.
Прив'язка процесів: numactl і cpuset
Явна прив'язка процесу до вузла вирішує проблему напряму:
numactl --cpunodebind=0 --membind=0 /usr/bin/mysqld
numactl --interleave=all /usr/bin/myapp
Прапорець --cpunodebind закріплює процес за ядрами вузла 0, --membind — за пам'яттю того ж вузла. Прапорець --interleave=all розподіляє пам'ять рівномірно по всіх вузлах — корисно для застосунків, які самі не вміють працювати з NUMA і не виграють від локальності.
| Параметр | Що робить | Коли використовувати |
|---|---|---|
| --cpunodebind | Закріплює ядра вузла | СУБД, JVM з великою купою |
| --membind | Закріплює пам'ять вузла | Разом з cpunodebind |
| --interleave=all | Чергує пам'ять по вузлах | NUMA-необізнані застосунки |
| --preferred | Віддає перевагу вузлу, але не забороняє інші | Гнучке навантаження |
NUMA в базах даних і віртуалізації
PostgreSQL і MySQL рекомендують запускати один інстанс на NUMA-вузол при великих обсягах пам'яті або явно прив'язувати процес через numactl, якщо інстанс один на весь сервер. У віртуалізації (KVM, Proxmox) варто виділяти віртуальній машині vCPU і пам'ять в межах одного фізичного вузла — інакше гіпервізор зіткнеться з тією ж проблемою міжвузлового трафіку.
Перед зміною прив'язки виміряйте ефект: прогоніть тест до і після через sysbench з навантаженням, близьким до реального, а не синтетичного однопотокового.
Чек-лист налаштування NUMA
- Перевірте topology через numactl --hardware до тюнінгу, а не після.
- Прив'язуйте процес до CPU і пам'яті разом, а не окремо.
- Для NUMA-необізнаних застосунків використовуйте --interleave=all замість ручної прив'язки.
- Вимірюйте затримки і throughput до і після — приріст не завжди очевидний на слабкому навантаженні.