...

Оптимизация сродства серверных процессов и учет NUMA в хостинге

Я увеличиваю производительность сервера за счет Сродство к процессу и осознание NUMA целенаправленно, что позволяет оптимально организовать потоки, ядра и память по отношению друг к другу. Это позволяет снизить задержки, увеличить пропускную способность и добиться стабильного времени отклика в хостинговых средах с большим количеством приложений.

Центральные пункты

Прежде чем приступить к конкретным настройкам, я выясняю свои цели, характер рабочей нагрузки и существующую топологию оборудования. Я анализирую, какие потоки особенно требовательны к памяти и какие процессы нуждаются в коротком времени отклика. Я учитываю, сколько ядер доступно на каждом узле NUMA и каков объем локальной оперативной памяти. Я планирую объединять сервисы на каждом узле таким образом, чтобы Локальность процессора поддерживается. Я измеряю каждое изменение с помощью контрольных показателей и мониторинга, чтобы избежать ложных предположений.

  • AffinityПривязка процессов к основным группам
  • NUMAСохраняйте память локально
  • Топология: Масштабировать узел за узлом
  • Мониторинг: Сделать удаленный доступ видимым
  • ХостингУправление размещением гипервизора

Что означает Process Affinity на сервере?

С Сродство к процессу Я указываю, на каких ядрах процессора работает тот или иной процесс или поток, а не позволяю операционной системе решать это самостоятельно. Благодаря этому содержимое кэша остается неизменным, что уменьшает количество пропусков кэша и переключений контекста. Я закрепляю потоки так, чтобы они эффективно использовали кэш L1/L2/L3 и не перескакивали между ядрами. Это улучшает предсказуемость задержек при высокой нагрузке и обеспечивает равномерное использование зарезервированных ядер. В качестве практического введения можно воспользоваться этим руководством Сродство к процессору в хостинге, потому что я использую его для сравнения типичных вариантов пиннинга.

Понимание NUMA: локальный и удаленный доступ

NUMA разделяет рабочую память на узлы, каждый из которых тесно связан с определенными сокетами процессора. Поток получает доступ к локальной оперативной памяти быстрее, чем к удаленной памяти на других узлах. Эта асимметрия оказывает значительное влияние на реальные рабочие нагрузки, особенно при большом количестве ядер и большого объема оперативной памяти. Поэтому я назначаю потоки и их обращения к памяти на общий узел, чтобы уменьшить задержки и увеличить пропускную способность. Если вы хотите глубже изучить топологию, ознакомьтесь с практическими советами на сайте Узлы NUMA в сервере а затем измеряет эффект в повседневной жизни.

Осознание NUMA в операционной системе и приложениях

Я активирую Осведомленность о NUMA в операционной системе, гипервизоре и приложении, чтобы память выделялась локально. По возможности я держу потоки экземпляра на ядрах одного узла NUMA, а не распределяю их по узлам. Я предпочитаю создавать большие кучи или буферы в локальной оперативной памяти, чтобы дорогостоящие удаленные доступы были редкими. Если в приложении есть несколько рабочих, я структурирую их по узлам в пулы, чтобы избежать вмешательства. Это позволяет четко распределить процессор и память, что заметно сокращает время отклика.

Взаимодействие между Affinity и NUMA

Affinity без NUMA-планирования теряет потенциал, если память расположена на удаленных узлах. Аналогично, наблюдение NUMA малоэффективно, если при планировании часто перемещаются потоки. Поэтому я привязываю потоки к ядрам конкретного узла и обеспечиваю параллельное распределение локальной памяти. Если я масштабирую приложение, то сначала заполняю узел, а затем включаю другие узлы. Такое сочетание привязки ядер и политики распределения памяти обеспечивает постоянный профиль задержек под нагрузкой.

Настройка аппаратного и встроенного ПО (UEFI/BIOS)

Чтобы Affinity и NUMA работали, я установил в прошивке стабильную базу. Я предпочитаю стабильные режимы производительности вместо агрессивных вариантов энергосбережения, чтобы свести к минимуму колебания тактовой частоты и задержки. Важные моменты, которые я проверяю:

  • Профиль производительности: максимальная мощность/производительность вместо сбалансированной; ограничение низких C-состояний, если задержка более важна, чем эффективность.
  • Стратегия турбо/буста: детерминированный буст по требованию, чтобы избежать колебаний P-ядер.
  • SMT/Hyper-Threading: тестируется в зависимости от рабочей нагрузки - для жестких SLA по задержкам я часто прикрепляю критические потоки к физическим ядрам и отделяю SMT от братьев и сестер.
  • Чередование памяти: отключено для оптимизации NUMA, чтобы узлы оставались четко разграниченными.
  • Каналы памяти: симметричная конфигурация слотов DIMM на каждом узле для обеспечения максимальной пропускной способности.

Путь конфигурирования: анализ до распиновки

Я начинаю с записи топологии, обычно с lscpu, numactl -hardware или hwloc. Затем я определяю необходимое количество ядер для каждого сервиса и назначаю их узлу. Я реализую привязку с помощью taskset или через опции systemd, чтобы назначение оставалось воспроизводимым. Во время тестирования я регулирую размер групп ядер до тех пор, пока задержка и пропускная способность не будут в хорошем соотношении. Я слежу за тем, чтобы ни одна из служб, интенсивно использующих процессор, не использовала один и тот же пул ядер и тем самым не вытесняла кэши друг друга.

В Linux мне нравится устанавливать сродство и политику памяти декларативно через cgroups (v2): Я определяю cpuset.cpus и cpuset.mems по узлам и запускаю службы с параметрами systemd, такими как CPUAffinity= и NUMAMask=. Я держу отдельные пулы для пакетных или вторичных процессов, чтобы они не попадали в ядра критичного к задержкам уровня. Для повторяющихся заданий я планирую точные окна запуска, в которые ядра свободны.

Сродство прерываний и ввода/вывода

Локальность нужна не только потокам приложений, но и Прерывания и организую пути ввода-вывода рядом с узлом:

  • Сеть: привяжите очереди RX/TX сетевой карты к ядрам одного и того же узла NUMA (настройте RSS/XPS), чтобы потоки обработки пакетов и приложений совместно использовали кэш и оперативную память.
  • Хранение данных: расставьте очереди NVMe и потоки ввода-вывода по узлам; проверьте распределение очередей для blk-mq, чтобы горячие тома не пересекались между узлами.
  • irqbalance: либо настраивается специально, либо отключается для критических очередей и устанавливается вручную через smp_affinity.

Целенаправленное использование возможностей операционной системы

Я намеренно использую функции ядра для строгих профилей задержки:

  • isolcpus/nohz_full/rcu_nocbs: отделяет ядра от общего планирования, минимизирует тиковую нагрузку и перемещает обратные вызовы RCU - идеально для высокопроизводительных потоков.
  • Политики планировщика: редко используйте SCHED_FIFO/RR для компонентов реального времени; в противном случае используйте CFS с близким расположением.
  • Auto NUMA Balancing: часто отключается для строго периферийных рабочих нагрузок, чтобы ядро не смещало память.
  • Transparent Huge Pages: в основном устанавливается на madvise и использует явные Huge Pages для действительно больших куч, чтобы уменьшить количество пропусков TLB.

Политика хранения с учетом NUMA

С numactl Я применяю предпочтительное распределение локальной памяти или использую такие политики, как preferred и interleave. По возможности я держу большие структуры в памяти, такие как буферные пулы баз данных, в пределах узла. Если потребность в памяти возрастает, я наблюдаю за увеличением количества удаленных обращений и реагирую на это сегментацией или шардингом. Практические знания о настройке дают мне рекомендации по следующим вопросам Балансировка NUMA, которые я затем подтверждаю с помощью нагрузочных тестов. Таким образом, время доступа к памяти остается низким и предсказуемым.

Методы хранения данных: Огромные страницы, кучи и сборка мусора

Управление памятью часто определяет задержки P99. Я использую огромные страницы, где преобладают большие, долгоживущие кучи (например, буферы БД, кучи JVM). Это уменьшает количество пропусков TLB и переходов по страницам. Для рабочих нагрузок JVM я обращаю внимание на размер кучи на узел и активирую оптимизацию NUMA, чтобы потоки GC и кучи оставались локальными. Для .NET и Go я планирую GC и пулы goroutine так, чтобы они не заполняли ядра на разных узлах неконтролируемым образом. В базах данных я разбиваю большие пулы буферов на сегменты, локальные для узла, или запускаю несколько небольших экземпляров на каждом узле.

Практический хостинг: типичные рабочие нагрузки

Базы данных, кэши и крупные серверы приложений чутко реагируют на Локальность процессора и задержки памяти. Распределенная ВМ по нескольким узлам NUMA увеличивает пути вычислений и памяти и замедляет выполнение запросов или вызовов API. Поэтому я размещаю ВМ так, чтобы их vCPU были закреплены за физическим узлом, а память оставалась там. Пулы контейнеров получают согласованные наборы процессоров, чтобы рабочие не прыгали между узлами. Такая забота окупается, особенно для электронной коммерции и API-сервисов с высоким уровнем параллелизма.

Тонкие стратегии приложений

На уровне приложений я развязываю узлы, чтобы сохранить локальность:

  • Рабочие пулы: Один пул на узел NUMA, каждый с локальной очередью, чтобы избежать межузлового взаимодействия.
  • Шардинг: храните данные и сеансы локально на узле; выбирайте хэширование так, чтобы горячие шарды не пересекались на нескольких узлах.
  • Кэши: реплицируются вместо централизованных; читатели предпочитают локальные копии узлов.
  • Привязка потоков в средах выполнения: для сетевых стеков (например, Netty) и клиентов БД привязывайте рабочие ядра к фиксированным ядрам, соблюдайте близость IRQ.

Мониторинг и устранение неисправностей

Разумный мониторинг показывает не только общую загрузку мощностей, поскольку NUMA-эффекты скрыты в значениях деталей узла. Я отслеживаю загрузку процессора на ядро и узел, использование памяти на узел и скорость удаленного доступа. Если отдельные ядра переполнены, а другие остаются неиспользованными, это говорит о плохой настройке сродства. Если оперативная память одного узла переполнена, а у другого есть резерв, мне необходимо скорректировать политику использования памяти или ее размещение. Я использую эти сигналы для объективного документирования узких мест и выработки следующих изменений.

Метрики Примечание/симптом Типичная причина Быстрое действие
Процессор на ядро Некоторые ядра постоянно находятся на высоком уровне Неправильное крепление Перераспределите основные группы
Оперативная память на узел Узел в пределе Память не локальная установить numactl preferred
Удаленный тариф Высокий уровень удаленного доступа VM/контейнер через узлы Набор vCPU/CPU в комплекте
Контекстные переключатели Неравномерная задержка Поход за нитками Сродство контактов сильнее

Антипаттерны и типичные камни преткновения

Я избегаю глобальных лимитов CPU независимо от NUMA, поскольку они распределяют ядра между узлами. Кроме того, „одна большая ВМ“ со слишком большим количеством vCPU редко масштабируется линейно - лучше использовать несколько локальных экземпляров на узлах. Прозрачные огромные страницы в режиме always иногда вызывают пики страничных ошибок; madvise плюс целевые огромные страницы более предсказуемы. Неконтролируемый irqbalance снижает локальность ввода-вывода. И еще: слишком жесткая привязка без буферных ядер может помешать обслуживанию и побочной загрузке - я всегда планирую несколько свободных ядер на узел.

Сделать эффект от работы измеримым

Я измеряю влияние Affinity и изменения в NUMA всегда с воспроизводимыми эталонами. Сравнение "до" и "после" с идентичным набором данных наглядно демонстрирует улучшения. Я сочетаю синтетические тесты с реалистичными профилями нагрузки, чтобы оптимизация приносила плоды в повседневном использовании. Ключевые показатели, такие как задержки P95 и P99, зачастую более значимы, чем средние значения. Это позволяет мне подтвердить правильность принятых решений и выявить побочные эффекты на ранней стадии.

Виртуализация и контейнеры

В настройках гипервизора я использую vNUMA, чтобы гостевая ВМ понимала физическую топологию. Я упаковываю vCPU ВМ в физически соответствующий узел, чтобы минимизировать удаленный доступ. Для контейнеров я определяю запросы и лимиты ЦП, чтобы наборы ЦП оставались согласованными, а менеджер топологии соблюдал локализацию узлов. Я распределяю крупные ВМ с большим количеством виртуальных процессоров по узлам, только если приложение допускает внутреннюю сегментацию. Я оцениваю каждое размещение на основе задержки, пропускной способности и использования на каждом узле.

Оркестровка: Cgroups, Kubernetes и др.

В контейнерах я полагаюсь на гарантированные или burstable классы со стабильными наборами CPU и назначением mems. Менеджер топологии в режиме „single-numa-node“ помогает сохранять локальность стручков. Для долго работающих в реальном времени частей я использую менеджер процессоров в „статическом“ режиме, чтобы сохранить эксклюзивность ядер. Я планирую HugePages как запросы/лимиты и группирую поды по роли рабочей нагрузки, чтобы узлы не были неоднородно перегружены. Важно: поддерживайте метки узлов должным образом, чтобы правила размещения не нарушали локальность непреднамеренно.

Роль хостинг-провайдера

Хороший поставщик обеспечивает прозрачность Топология NUMA, возможности сродства и понимание метрик узлов. Я слежу за тем, чтобы гипервизор и оркестровка серьезно относились к NUMA и чтобы размещение vCPU оставалось контролируемым. Мониторинг, обеспечивающий квоты CPU, RAM и удаленных ресурсов на узел, также важен. Это позволяет мне самому определять, насколько строго я буду расставлять квоты и задавать политику памяти. Такой контроль делает требовательные рабочие нагрузки надежными и предсказуемыми.

Операционная модель: безопасное внедрение изменений

Я внедряю политики пиннинга и NUMA итеративно: сначала на узле, с четко определенными шагами отката. Я документирую топологию, назначения и параметры ядра, чтобы обеспечить воспроизводимость. Для релизов я использую канареечный трафик, отслеживаю P95/P99, контекстные переключения и удаленные тарифы в течение как минимум одной фазы полной нагрузки и только после этого начинаю широкое внедрение. Это позволяет сохранить стабильность улучшений и управлять рисками.

Передовой опыт, компактно применяемый

Я начинаю каждую оптимизацию с тщательного Анализ топологии и документирую распределение ядра и узлов. Затем я разделяю рабочие нагрузки таким образом, чтобы база данных, кэш и сервер приложений получали отдельные ресурсы узла. Я выделяю критически важные процессы и устанавливаю приоритет локальной памяти перед точной настройкой размера группы. Каждую настройку я сопровождаю бенчмарками и метриками узла, чтобы четко видеть эффект. При росте я планирую узел за узлом и поддерживаю экземпляры на низком уровне, вместо того чтобы раздувать монолитный гигантский экземпляр.

Резюме и последующие шаги

С помощью целевых Сродство к процессу и реальной осведомленности о NUMA, я заметно ускоряю выполнение рабочих нагрузок на одном и том же оборудовании. Четкое размещение, локальное распределение памяти и последовательное измерение результатов имеют решающее значение. Объединение виртуальных машин и контейнеров вблизи узла снижает задержки и увеличивает пропускную способность. Я рекомендую начать пилотный проект на одном из узлов, протестировать сродство и политику памяти и выбрать оптимальные настройки. Таким образом, производительность будет расти шаг за шагом без необходимости покупать новые серверы.

Текущие статьи

Администратор проверяет состояние сервера Linux перед контролируемым развертыванием Livepatch.
Безопасность

Успешное тестирование KernelCare Live Patching: рекомендации для администраторов

Надежное тестирование KernelCare Live Patching: как проверить совместимость, статус патчей, работоспособность приложений, поэтапное внедрение и незаменимую стратегию перезагрузки.

Администратор в центре обработки данных, занимающаяся серверным оборудованием
Серверы и виртуальные машины

CloudLinux OS 9: возможности и ограничения в условиях виртуального хостинга

CloudLinux OS 9 модернизирует системную основу для виртуального хостинга. Однако решающее значение по-прежнему имеют лицензия, версия, установленные компоненты и интеграция с панелью управления — особенно в случае LVE, CageFS, Isolates и Shared Pro.

Техник устанавливает SSD-накопитель Enterprise NVMe в сервер в центре обработки данных
Серверы и виртуальные машины

SSD-накопители PCIe 5.0 в центре обработки данных: маркетинговый ход или реальное повышение производительности?

ТВЕРДЫЕ ДИСКИ NVMe по стандарту PCIe 5.0 значительно увеличивают доступную пропускную способность на каждую линию. Однако в центре обработки данных это дает ощутимое преимущество только в том случае, если платформа, топология, твердотельный диск и рабочая нагрузка направлены на устранение одного и того же узкого места в системе ввода-вывода.