Выберите продукт

CPU pinning и NUMA для VDS в 2026: vCPU, irqbalance и предсказуемая производительность

Разбираем CPU pinning и NUMA на VDS: когда это реально помогает, как измерять steal time и хвосты p99, чем отличаются taskset, systemd CPUAffinity и cpuset cgroup, и как не убить сеть/диск неправильными IRQ.
CPU pinning и NUMA для VDS в 2026: vCPU, irqbalance и предсказуемая производительность

Зачем трогать CPU pinning и NUMA на VDS

CPU pinning (закрепление потоков за конкретными CPU) и NUMA-настройки обычно всплывают тогда, когда «в среднем всё быстро», но в проде случаются странные хвосты задержек: редкие пики latency, дрожание p99, плавающая скорость сборок, джиттер у real-time/стриминга или непредсказуемые задержки БД.

На VDS добавляется ещё один слой неопределённости: вы видите vCPU, а под ними скрыты физические ядра хоста, планировщик гипервизора, соседние виртуалки и политика распределения прерываний (IRQ). Поэтому цель pinning/NUMA здесь не «ускорить всё на 30%», а сделать производительность предсказуемой и убрать случайные деградации.

Важно: на типичном VDS вы не контролируете размещение vCPU на физике так, как на выделенном сервере. Но вы всё равно можете навести порядок внутри гостя: развести критичные и фоновые процессы по CPU, уменьшить миграции потоков и проследить, чтобы IRQ/softirq не забивали «дорогие» ядра.

  • Ограничить «шумные» фоновые процессы и увести их с CPU, где крутится критичная нагрузка.
  • Снизить миграции потоков между CPU (меньше cache-miss и меньше джиттера).
  • Не дать IRQ/softirq съедать CPU, выделенные под p99.
  • Если гость видит NUMA — уменьшить штраф за удалённую память (точечно и измеримо).

Базовые понятия: vCPU, steal time и «почему иногда тормозит без причины»

vCPU против pCPU: что вы реально закрепляете

Внутри гостя вы видите CPU 0..N и можете закреплять процессы за ними. Это закрепление внутри гостевой ОС. А вот соответствие «vCPU → физическое ядро» (pCPU) решает гипервизор. Поэтому pinning в госте чаще полезен для локальности кэшей и предсказуемости планировщика Linux, а не для «выбора лучшего физического ядра».

Steal time: главный маркер конкуренции на хосте

Steal time — время, когда ваш vCPU хотел выполняться, но гипервизор отдал физическое ядро другим задачам. Это один из самых честных индикаторов «соседи шумят» или «хост перегружен».

Как посмотреть быстро:

top

В top обращайте внимание на %st. Для более детального анализа по всем CPU:

mpstat -P ALL 1

Если %steal заметно растёт под нагрузкой — pinning внутри гостя может сгладить хвосты, но не отменит физическую конкуренцию. Тогда сильнее работают «приземлённые» меры: уменьшить размазывание нагрузки по всем vCPU, убрать фон, а при необходимости масштабироваться по ресурсам.

Ожидание от CPU pinning на VDS лучше формулировать так: «меньше вариативности и меньше микропровалов», а не «магический прирост на ровном месте».

Пример мониторинга steal time и загрузки CPU в Linux (mpstat)

Как понять, есть ли NUMA и имеет ли смысл оптимизация

NUMA (Non-Uniform Memory Access) на реальном железе означает, что память «ближе» к одним ядрам и «дальше» от других. В виртуализации гость может видеть NUMA-топологию, а может не видеть — зависит от режима виртуализации и настроек хоста.

Проверяем в госте:

lscpu
numactl --hardware

Если numactl показывает 1 node — для гостя NUMA фактически «плоская», и большинство NUMA-настроек смысла не имеют. Если nodes несколько — можно аккуратно тестировать привязку CPU и памяти, но помните: вы всё равно не управляете тем, как гипервизор разложил ваши vCPU по сокетам/нодам хоста.

Где NUMA обычно заметнее

  • Базы данных и in-memory хранилища (много случайного доступа к памяти).
  • JVM/Go-сервисы с большим heap и высоким RPS.
  • Нагрузки, чувствительные к latency: очереди, телеметрия, финтех.
FastFox VDS
Облачный VDS-сервер в России
Аренда виртуальных серверов с моментальным развертыванием инфраструктуры от 195₽ / мес

CPU pinning на практике: taskset и systemd

Быстрый pinning через taskset (для эксперимента)

taskset удобен для диагностики и коротких тестов:

taskset -c 2,3 your_command

Посмотреть текущую маску процесса:

taskset -p 1234

Минус подхода: после рестарта сервиса всё теряется, и легко забыть, что «временно закрепляли» процесс.

Закрепление CPU для systemd-сервиса (практичный вариант на проде)

Самый удобный путь в 2026 — задавать affinity на уровне юнита systemd. Создайте drop-in:

systemctl edit your.service

Добавьте:

[Service]
CPUAffinity=2 3

Примените изменения:

systemctl daemon-reload
systemctl restart your.service

Плюсы: декларативно, прозрачно, переживает рестарты. И удобно аудировать, когда вы разбираете «почему p99 поехал».

Если критичная нагрузка запускается воркерами/очередями, полезно также выстроить единый способ запуска и лимитов через systemd. По теме близко: очереди и воркеры: Supervisor vs systemd.

cpuset cgroup: более «правильный» pinning, чем taskset

cpuset cgroup позволяет управлять не только тем, на каких CPU могут работать процессы, но и тем, какие CPU доступны целой группе процессов (вместе с дочерними), а на NUMA-системах — ещё и политиками памяти.

Если у вас systemd, то cgroups у вас уже есть: юниты и слайсы. Практичная схема для небольших VDS выглядит так:

  • оставить CPU 0 под «систему» (sshd, journald, агенты мониторинга, мелкие крон-задачи);
  • выделить CPU 1..N под приложение/БД и закрепить их через CPUAffinity или через слайс.

Идея простая: системный шум не должен конкурировать за те же CPU, на которых вы держите p99. Но не перегибайте: на инстансах 2–4 vCPU слишком жёсткое разделение иногда ухудшает ситуацию на всплесках.

isolcpus и изоляция ядер: когда стоит, а когда нет

isolcpus — параметр ядра, который исключает указанные CPU из обычного планирования, чтобы вы вручную размещали там критичные потоки. Исторически это применяли для low-latency задач.

Но в 2026 подход стал осторожнее: изоляция CPU — это не только потенциальный профит, но и риски. На практике легко получить одно из двух:

  • «изолированные» CPU простаивают, а остальная система перегружена;
  • IRQ/softirq внезапно остаются на «дорогих» ядрах, и весь эффект от pinning исчезает.

Если хочется пробовать, начинайте с менее инвазивных шагов (systemd affinity, разведение фона, анализ IRQ) и только потом рассматривайте изоляцию.

Проверить текущую командную строку ядра:

cat /proc/cmdline

Любые изменения параметров загрузки делайте только с планом отката и доступом к консоли (особенно на удалённых VDS).

IRQ и irqbalance: скрытый источник «плавающей» производительности

Даже если вы идеально закрепили приложение на CPU 2–3, никто не мешает ядру обрабатывать на этих CPU прерывания от сетевой карты, диска или виртуальных устройств. В итоге растёт softirq, падает throughput и увеличивается latency.

Как увидеть, что вас душат IRQ/softirq

Смотрите распределение прерываний:

cat /proc/interrupts

Если видите, что активные IRQ «прибиты» к тем же CPU, где живёт ваша нагрузка, — это кандидат на перераспределение.

Посмотрите softirq по CPU:

cat /proc/softirqs

Что делает irqbalance и почему он может мешать pinning

irqbalance старается равномерно распределять IRQ по CPU. На «обычных» серверах это часто полезно. Но при CPU pinning может быть наоборот: irqbalance начнёт разбрасывать IRQ по всем CPU, включая те, которые вы хотели оставить «чистыми» под приложение.

Практическое правило:

  • Если вы не делаете pinning и не изолируете CPU — irqbalance обычно оставляют включённым.
  • Если вы выделяете CPU под приложение — либо настраивайте irqbalance (исключения), либо тестируйте вариант без него и сравнивайте метрики.

Проверка статуса сервиса:

systemctl status irqbalance

Нюанс VDS: часть IRQ в госте может быть виртуализована, и ручной контроль окажется ограниченным. Но даже тогда наблюдение за /proc/interrupts помогает понять, откуда берётся джиттер.

Распределение IRQ по CPU в Linux и поиск перегруженных ядер

Практический план работ: внедряем без боли

Шаг 1. Фиксируем базовую линию

До любых изменений зафиксируйте:

  • p50/p95/p99 latency приложения (или запросов к БД);
  • %st (steal time) по CPU;
  • косвенные признаки «давки»: рост system CPU, рост run queue, лишние миграции;
  • распределение IRQ/softirq по CPU.

Минимальный набор команд под нагрузкой:

uptime
mpstat -P ALL 1
pidstat -u -p ALL 1
cat /proc/interrupts

Шаг 2. Мягко выделяем CPU под критичный сервис

Начните с CPUAffinity в systemd для одного сервиса. Выберите, например, 2 CPU под приложение, оставив CPU 0 под систему. После этого перепроверьте tail latency и внимательно посмотрите, не просела ли сеть/диск.

Шаг 3. Убеждаемся, что IRQ не попали на «дорогие» CPU

Если после pinning растёт system CPU или softirq на тех же CPU — это сигнал заняться политикой IRQ и поведением irqbalance.

Шаг 4. Если NUMA видна — тестируем точечно

Если NUMA доступна, тестируйте numactl для конкретного процесса в рамках эксперимента (например, бенчмарк или отдельный воркер). На VDS эффект может быть меньше, чем на bare metal, поэтому критично сравнивать метрики «до/после», а не «включать всё подряд».

Виртуальный хостинг FastFox
Виртуальный хостинг для сайтов
Универсальное решение для создания и размещения сайтов любой сложности в Интернете от 95₽ / мес

Типичные ошибки и анти-паттерны

Ошибка 1: закрепили приложение, но забыли про фон

Если на тех же CPU крутятся агент мониторинга, лог-шейпер, cron-джобы, CI-раннеры — вы сами создаёте конкуренцию. Смысл pinning как раз в том, чтобы развести критичное и шумное.

Частый источник «шума» — задания по расписанию, которые стартуют внезапно и размазываются по CPU. Если вы постепенно переносите запуск задач в systemd, пригодится: cron vs systemd timers.

Ошибка 2: «изолировали CPU» и потеряли эластичность

Изоляция через isolcpus иногда даёт красивые графики на синтетике, а в реальности ухудшает ситуацию при всплесках. Особенно на маленьких инстансах (2–4 vCPU), где каждый CPU на счету.

Ошибка 3: игнорировать steal time

Если %steal высокий, можно долго полировать affinity и IRQ, но физическая конкуренция всё равно будет съедать производительность. Тогда правильнее думать о смене тарифа/класса CPU, масштабировании или выносе самых чувствительных компонентов.

Чек-лист: цель — предсказуемая производительность без сюрпризов

  1. Соберите метрики p95/p99 и параллельно посмотрите %st (steal time).

  2. Сделайте мягкий CPU pinning через systemd CPUAffinity для одного критичного сервиса.

  3. Проверьте /proc/interrupts и /proc/softirqs, убедитесь, что IRQ не «бьют» в те же CPU.

  4. Если pinning есть — убедитесь, что политика irqbalance не мешает вашей схеме (или сравните с вариантом без него).

  5. Если NUMA доступна — тестируйте точечно и измеряйте эффект, а не «включайте всё подряд».

Вывод

CPU pinning в 2026 — это не экзотика, а нормальный инструмент, когда вам нужна предсказуемость на VDS: меньше миграций, меньше джиттера, более стабильные хвосты latency. В связке с пониманием NUMA и аккуратным контролем IRQ можно убрать «случайные просадки», которые сложно объяснить только уровнем приложения.

Рабочая стратегия такая: сначала измеряем (включая steal time), затем делаем минимальные изменения (systemd affinity), и только потом усложняем схему (cpuset, IRQ-политики, изоляция ядер).

Поделиться статьей

Вам будет интересно

VPS vs VDS vs Dedicated: как не ошибиться с производительностью и изоляцией OpenAI Статья написана AI (GPT 5)

VPS vs VDS vs Dedicated: как не ошибиться с производительностью и изоляцией

Цена у VPS, VDS и dedicated — не главное. Важнее предсказуемость под нагрузкой: cpu steal time, noisy neighbor, I/O latency и jitt ...
Basic Auth в Nginx vs OAuth2-proxy vs mTLS: что выбрать для защиты админки и внутренних сервисов OpenAI Статья написана AI (GPT 5)

Basic Auth в Nginx vs OAuth2-proxy vs mTLS: что выбрать для защиты админки и внутренних сервисов

Три способа закрыть админки и внутренние веб-сервисы за reverse proxy: Basic Auth в Nginx, oauth2-proxy (OIDC/SSO) и mTLS. Разбира ...
DNSSEC в 2026: DS record, rollover ключей и recovery после SERVFAIL OpenAI Статья написана AI (GPT 5)

DNSSEC в 2026: DS record, rollover ключей и recovery после SERVFAIL

DNSSEC обычно вспоминают в момент, когда домен внезапно уходит в SERVFAIL у валидирующих резолверов. В этом материале: как устроен ...