Я показываю, как Сервер балансировки NUMA на хостинговом оборудовании оптимизирует доступ к памяти и снижает задержки за счет привязки процессов и данных к соответствующему узлу NUMA. Решающим фактором является Оптимизация доступа к памяти благодаря локальному доступу, размещению задач и целенаправленной миграции страниц на Linux-хостах с большим количеством ядер.
Центральные пункты
- NUMA Разделяет процессоры и память на узлы; локальный доступ обеспечивает низкий Задержка.
- Автоматический NUMA Balancing переносит страницы и размещает задачи рядом с узлом.
- Размер виртуальной машины на узел, в противном случае существует риск NUMA Trashing.
- Инструменты как показать numactl, lscpu, numad Топология и использовать.
- ТюнингC-состояния, чередование узлов из, Огромные страницы, родственные связи.
Что такое NUMA - и почему это важно для хостинга
NUMA разделяет многопроцессорную систему на Узел, Каждый из них содержит собственные процессоры и локальную память, что делает доступ к близлежащим ядрам быстрее, чем к удаленным. В то время как UMA направляет все ядра по общему пути, NUMA предотвращает узкие места из-за местный каналов памяти на узел. В средах хостинга с большим количеством параллельных виртуальных машин каждая миллисекунда задержки суммируется, поэтому каждый запрос приносит ощутимую пользу. Если вам нужна дополнительная информация, вы можете узнать больше о архитектура NUMA. Для меня очевидно одно: если вы понимаете и используете узлы, вы получаете большую пропускную способность от того же оборудования.
Автоматическая балансировка NUMA в ядре Linux - как это работает
Ядро периодически сканирует части адресного пространства и „неотмеченные“ страницы, чтобы ошибка подсказки могла оптимальный узел видимым. Если сбой произошел, алгоритм оценивает, стоит ли перемещать страницу или перемещать задачу, и избегает ненужных перемещений. Миграция при сбое Данные ближе к исполняющему процессору, а размещение задач NUMA перемещает процессы ближе к их памяти. Сканер распределяет свою работу по частям так, чтобы накладные расходы оставались в пределах шума нормальной нагрузки. Это приводит к постоянной тонкой настройке, которая уменьшает задержки, не требуя жестких правил размещения.
Оптимизация доступа к памяти: локальная и удаленная
Для локального доступа используется Контроллер памяти собственного узла и минимизировать время ожидания интерконнекта. Удаленные доступы обходятся в несколько циклов через QPI/UPI или Infinity Fabric и, таким образом, минимизируют эффективное время доступа. Полоса пропускания. Высокое число ядер усугубляет этот эффект, поскольку все больше и больше ядер конкурируют за одни и те же соединения. Поэтому я планирую так, чтобы горячий код и активные данные собирались на одном узле. Если пренебречь этим, то можно потерять процентные пункты, определяющие время отклика или таймаут во время пиков нагрузки.
Размеры виртуальных машин, NUMA-мусор и обрезка хоста
Я определяю размеры виртуальных машин так, чтобы vCPU и оперативная память помещались в узле NUMA, чтобы избежать межузлового доступа. Часто 4-8 vCPU на узел обеспечивают хорошую производительность. Количество попаданий, в зависимости от платформы и иерархии кэша. Огромные страницы также помогают, поскольку TLB работает эффективнее и миграции страниц происходят реже. При необходимости я устанавливаю Сродство к процессору для процессов, критичных к задержкам, для привязки потоков к подходящим ядрам - подробнее см. Сродство к процессору. Если вы распределяете ВМ по узлам, вы рискуете получить NUMA trashing, т. е. пинг-понг данных и потоков.
Инструменты на практике: numactl, lscpu, numad
С помощью „lscpu“ я прочитал Топология и узлов NUMA, включая назначение ядер. Команда „numactl -hardware“ показывает память на узел и доступные расстояния, что облегчает оценку путей. Демон „numad“ следит за загрузкой и динамически корректирует сродство при перемещении центров нагрузки. Для фиксированных сценариев я использую „numactl -cpunodebind/-membind“ для явной привязки процессов и памяти. Таким образом, я сочетаю автоматическую балансировку с целевыми спецификациями и контролирую результат через „perf“, „numastat“ и „/proc“.
Как я измеряю влияние: Ключевые цифры и команды
Я всегда оцениваю NUMA-Tuning через Серия измерений, а не по интуиции. Три показателя доказали свою эффективность: Соотношение локальных и удаленных просмотров страниц, скорость миграции и распределение задержек (P95/P99).
- В масштабах всей системыnumastat„ показывает локальные/удаленные доступы и перенесенные страницы для каждого узла.
- Связанные с процессом: „/proc//numa_maps“ показывает, где находится память и как она была распределена.
- Вид планировщикаCpus_allowed_list„ и реальный “Cpus_allowed„ проверяют, применяются ли привязки.
Общесистемное представление #
numastat
numastat -m
# Распределение и привязки, связанные с процессом
pid=$(pidof )
numastat -p "$pid"
cat /proc/"$pid"/numa_maps | head
cat /proc/"$pid"/status | grep -E 'Cpus_allowed_list|Mems_allowed_list'
taskset -cp "$pid"
# Счетчик ядра для активности NUMA
grep -E 'numa|migrate' /proc/vmstat
# Трассировка событий для глубокого анализа (активируется на короткое время)
echo 1 > /sys/kernel/debug/tracing/events/mm/enable
sleep 5; cat /sys/kernel/debug/tracing/trace | grep -i numa; echo 0 > /sys/kernel/debug/tracing/events/mm/enable
Я сравниваю в каждом случае A/B: несвязанные и связанные, автоматическое включение/выключение балансировки и различные срезы ВМ. Целью является явное снижение удаленных доступов и шума миграции, а также более жесткие задержки P95/P99. Только когда измеренные значения станут стабильно лучше, я возьмусь за настройку.
Настройки BIOS и встроенного ПО, которые действительно работают
Я отключаю „Node Interleaving“ в BIOS, чтобы структура NUMA оставалась видимой и ядро местный можно планировать. Сокращение C-состояний стабилизирует пики задержки, поскольку ядра реже впадают в состояние глубокого сна, что экономит время пробуждения. Я распределяю каналы памяти симметрично, чтобы каждый узел мог использовать свой максимальный объем памяти. Полоса пропускания достигнуто. Я тестирую префетчеры и функции RAS с помощью профилей рабочей нагрузки, поскольку они помогают или вредят в зависимости от схемы доступа. Я измеряю каждое изменение по сравнению с базовым уровнем и только после этого принимаю настройку на постоянной основе.
Параметры ядра и sysctl, которые делают разницу
Тонкая настройка ядра помогает мне, Накладные и Время отклика балансировщика в соответствии с рабочей нагрузкой. Я начинаю с консервативных настроек по умолчанию и продвигаюсь вперед шаг за шагом.
- kernel.numa_balancingВключение/выключение автоматической балансировки. Я оставляю его включенным для движущихся грузов; я выключаю его для строго прижатых специальных услуг в качестве теста.
- kernel.numa_balancing_scan_delay_msВремя ожидания перед первым сканированием после создания процесса. Выберите большее время, если выполняется много кратковременных задач; меньшее - для долго работающих служб, требующих быстрого приближения.
- kernel.numa_balancing_scan_period_min_ms / _max_msШирина интервалов сканирования. Узкие интервалы увеличивают скорость отклика, но также и нагрузку на процессор.
- kernel.numa_balancing_scan_size_mbДоля адресного пространства за одно сканирование. Слишком большая доля порождает штормы с подсказками, слишком маленькая - реагирует вяло.
- vm.zone_reclaim_mode: Если памяти не хватает, ядро предпочитает локальное восстановление вместо удаленного выделения. Для общих рабочих нагрузок на хостинге я обычно оставляю 0; Для сервисов с локальной памятью, чувствительных к задержкам, я осторожно тестирую более высокие значения.
- Прозрачные огромные страницы (THP): В разделе „/sys/kernel/mm/transparent_hugepage/{enabled,defrag}“ я обычно устанавливаю значение madvise и консервативной дефрагментации. Жесткие профили „всегда“ дают преимущества TLB, но рискуют застопориться из-за уплотнения.
- sched_migration_cost_ns: Оценка стоимости миграции задач. Более высокие значения снижают эффективность перераспределения агрессивных планировщиков.
- cgroups cpusetС cpuset.cpus и cpuset.mems Я чисто разделяю службы по узлам и убеждаюсь, что первое касание остается в пределах допустимых узлов.
# Пример: консервативная, но отзывчивая балансировка
sysctl -w kernel.numa_balancing=1
sysctl -w kernel.numa_balancing_scan_delay_ms=30000
sysctl -w kernel.numa_balancing_scan_period_min_ms=60000
sysctl -w kernel.numa_balancing_scan_period_max_ms=300000
sysctl -w kernel.numa_balancing_scan_size_mb=256
# Осторожно используйте THP
echo madvise > /sys/kernel/mm/transparent_hugepage/enabled
echo defer > /sys/kernel/mm/transparent_hugepage/defrag
Это по-прежнему важно: Меняйте только один регулировочный винт в каждом тестовом раунде и проверяйте эффект на одной и той же кривой нагрузки. Именно так я отделяю причину от следствия.
Правильно размещайте рабочие нагрузки: Базы данных, кэши, контейнеры
Базы данных выигрывают, когда буферные пулы остаются локальными для каждого узла NUMA, а потоки привязаны близко к своим кучам. В кэшах in-memory я устанавливаю значение sharding на Узел чтобы избежать удаленного поиска. Контейнерные платформы получают ограничения и запросы, чтобы поды не прыгали по узлам. Для резервирования памяти я использую Huge Pages, что упрощает хранение хотсетов в Кэши подходят. В следующей таблице компактно представлены стратегии и типичные эффекты.
| Стратегия | Используйте | Ожидаемый эффект | Подсказка |
|---|---|---|---|
| первое касание | Базы данных, кучи JVM | Выделение местной стороны | Выполните инициализацию на целевом узле |
| Interleave | Широко распределенная нагрузка | Равномерное распределение | Не оптимально для горячих точек |
| Прикрепление задач | Услуги, критичные к задержкам | Постоянная задержка | Менее гибкие при изменении нагрузки |
| Автоматическая балансировка | Смешанные рабочие нагрузки | Динамическая близость | Соизмерение накладных расходов с прибылью |
| Огромные страницы | Большие кучи, кэши | Меньше пропусков TLB | Планируйте чистые резервации |
Виртуализация: виртуальная NUMA, планировщик и настройка гостей
Virtual NUMA передает топологию хоста гостевой ОС в упрощенном виде, так что первое касание и Аллокатор работать разумно. Планировщики гипервизора обращают внимание на близость узлов при распределении vCPU и миграции ВМ. Я редко распределяю большие ВМ по нескольким узлам, если только рабочая нагрузка не распределяется широко и не выигрывает от чередования. В гостевой системе я настраиваю кучи JVM или баз данных таким образом, чтобы они оставались локальными на видимых узлах NUMA. Что касается управления памятью в гостевой среде, посмотрите на Виртуальная память, чтобы уменьшить размер страниц и их переключение.
Близость PCIe: NVMe и сетевые карты на нужных узлах
Если возможно, я назначаю SSD-накопители NVMe и быстрые сетевые карты узлу, на котором работает Рабочая нагрузка выполняется. Таким образом, я избегаю запросов ввода-вывода, пересекающих межсоединение и увеличивающих задержку. Я привязываю многоочередные сетевые карты к наборам ядер узла с помощью RSS/RPS, чтобы IRQ оставались локальными. Для стеков хранения стоит разделить пулы потоков по узлам. Если вы уделите этому внимание, то заметно снизите задержки P99 и создадите резерв для пиков нагрузки.
IRQ и сродство очередей на практике
Сначала я проверяю, какие Узел NUMA устройств и соответствующим образом подключать IRQ и очереди. Это обеспечивает локальность путей передачи данных.
Сопоставление устройств # с узлами
cat /sys/class/net/eth0/device/numa_node
cat /sys/block/nvme0n1/device/numa_node
# Установите специальное сродство IRQ (пример: ядра 0-7 узла)
irq=
echo 0-7 > /proc/irq/$irq/smp_affinity_list
# Привязка очередей сетевых карт к ядрам (RPS/RFS)
for q in /sys/class/net/eth0/queues/rx-*; do echo 0-7 > "$q"/rps_cpus; done
sysctl -w net.core.rps_sock_flow_entries=32768
for q in /sys/class/net/eth0/queues/rx-*; do echo 4096 > "$q"/rps_flow_cnt; done
# Улучшение сродства очереди NVMe
echo 2 > /sys/block/nvme0n1/queue/rq_affinity
cat /sys/block/nvme0n1/queue/scheduler # "none" предпочтительнее
„Я запускаю “irqbalance" с осознанием узла или устанавливаю его на исключения для прерываний "горячего пути". Результат - более стабильные задержки, меньшее количество переходов между узлами через IRQ и ощутимое увеличение количества локальных обращений ввода-вывода.
Статическая привязка против динамической балансировки - средний путь
Я использую „наборы задач“ и cgroups, чтобы установить жесткие правила, когда детерминированные Латентность Считает. Я оставляю автоматическую балансировку NUMA активной, когда нагрузка смещается и мне нужно адаптивное приближение. Часто лучше всего работает сочетание: жесткие контакты для горячих трасс, более открытые границы для вспомогательной работы. Я регулярно проверяю, не увеличивается ли количество миграций, так как это сигнализирует о плохом планировании. Цель по-прежнему состоит в том, чтобы выбрать расположение данных и потоков таким образом, чтобы миграции были редкими, но возможными.
NUMA в контейнерах и Kubernetes
Я беру с собой контейнер cpusets и Огромные страницы на линии. Я назначаю капсулы/контейнеры на узел NUMA, сохраняя согласованные объемы процессора и памяти. В оркестрах я устанавливаю политики, которые предпочитают назначение на один узел и, таким образом, соблюдают принцип "первого касания".
- Время выполнения контейнера: „-cpuset-cpus“ и „-cpuset-mems“ удерживают задачи и память вместе; назначают огромные страницы в качестве ресурсов.
- Менеджер топологии/процессораСтрогое или предпочтительное назначение обеспечивает выделение соответствующих ядер и областей памяти.
- Гарантированный QoSФиксированные запросы/лимиты минимизируют перераспределение планировщиком.
Я сознательно разделил побочные и вспомогательные процессы на другие ядра. в пределах того же узла, чтобы горячий путь оставался неповрежденным, но не вступал в межузловую гонку.
Понимание топологий процессоров: CCD/CCX, SNC и Cluster-on-Die
Современные серверные процессоры разделяют сокеты на Поддомены со своими собственными кэшами и путями. Я учитываю это при сокращении ядер и куч:
- AMD EPYCCCD/CCX и „NUMA на сокет“ (NPS=1/2/4) влияют на то, насколько тонко будет выстроена NUMA. Большее количество узлов (NPS=4) повышает локальность, но требует чистого пиннинга.
- IntelSub-NUMA Clustering (SNC2/4) разделяет LLC на кластеры. Хорошо подходит для нагрузок с ограниченным объемом памяти, при условии, что ОС и рабочая нагрузка ориентированы на узлы.
- Близость L3Я связываю потоки, использующие одни и те же кучи, в один кластер L3, чтобы сэкономить трафик когерентности и межкластерные переходы.
Эти опции действуют как мультипликатор: при правильном использовании они увеличивают Местность Кроме того, при неправильной настройке они увеличивают фрагментацию и удаленный трафик.
Пошаговое внедрение и план отката
Я никогда не представляю „большой взрыв“ NUMA-тюнинга. Устойчивый План позволяет избежать неожиданностей:
- Базовый уровеньАппаратная топология, задержки P50/P95/P99, пропускная способность, захват скорости numastat.
- ГипотезаСформулируйте конкретную цель (например, удаленный доступ -30%, P99 -20%).
- Один шагИзмените только один регулировочный винт (например, VM cut, cpuset, политика THP, интервалы сканирования).
- КанарыПротестируйте 5-10% парка под реальной нагрузкой, сохраните готовность к откату.
- ОценкаСравнивайте измеренные значения, определяйте окна регрессии, регистрируйте побочные эффекты.
- РазвернутьРаскатывайте вал за валом, измеряйте еще раз после каждого вала.
- Техническое обслуживаниеПроводите повторные измерения раз в квартал (обновления ядра, прошивки и рабочей нагрузки меняют оптимальный показатель).
Это гарантирует воспроизводимость улучшений и возможность их отмены в течение нескольких минут в случае ошибки.
Распространенные ошибки - и как их избежать
Типичной ошибкой является активация в BIOS функции чередования узлов, которая скрывает топологию NUMA и Балансировка сложнее. Столь же неблагоприятны ВМ с большим количеством vCPU, чем предлагает узел, плюс неаккуратно зарезервированные огромные страницы. Некоторые администраторы жестко привязывают все к узлам и тем самым теряют гибкость при изменении рабочей нагрузки. Другие полностью полагаются на ядро, хотя жесткие "горячие точки" требуют четких правил. Я записываю серии измерений, выявляю отклонения на ранних этапах и шаг за шагом корректирую настройки и политики.
- THP „Всегда“ без контроля: незапланированное уплотнение нарушает латентность. Я предпочитаю использовать „madvise“ и специально резервировать огромные страницы.
- vm.zone_reclaim_mode слишком агрессивно: локальное восстановление может принести больше вреда, чем пользы, в самый неподходящий момент. Сначала отмерьте, потом оттачивайте.
- слепой иркбалансНекритические IRQ перемещаются между узлами. Я устанавливаю исключения или фиксированные маски для горячих путей.
- Смесь чередования + жесткого прижимаПротиворечивая политика порождает пинг-понг. Я принимаю решение в пользу четкой линии для каждой услуги.
- Нечистые кпусетыКонтейнеры видят узел, но отображают память на другие узлы. Всегда устанавливайте „cpuset.mems“ последовательно с набором CPU.
- Особенности суб-НУМА активированы, но не используются: Увеличение количества узлов без планирования увеличивает фрагментацию. Включайте только после тестирования.
Краткое резюме
NUMA Balancing Server целенаправленно объединяет процессы и данные, делая локальный доступ более частым и эффективным. Задержки становятся короче. При подходящем размере виртуальной машины, чистой конфигурации BIOS и использовании таких инструментов, как numactl, создается четкая топология, которую использует ядро. Виртуальная NUMA, огромные страницы и аффинити дополняют автоматическую балансировку, а не заменяют ее. Подключение устройств ввода-вывода рядом с узлами и использование "горячих путей" позволяет отказаться от дорогостоящего удаленного доступа. Таким образом, оборудование хостинга надежно масштабируется, а каждая процессорная секунда приносит больше пользы. полезная нагрузка.


