Подробный гайд: Настройка CPU-пиннинга для KVM в Astra Linux 1.8

Гайд по CPU-пиннингу для KVM в Astra Linux 1.8: привязка vCPU к ядрам для снижения задержек и роста производительности виртуальных машин.

2026.04.28                  


Подробный гайд: Настройка CPU-пиннинга для KVM в Astra Linux 1.8Подробный гайд: Настройка CPU-пиннинга для KVM в Astra Linux 1.8

Примечание:

  • Astra Linux 1.8 основана на Debian 11/12. Все утилиты libvirt, qemu-kvm и systemd работают по стандартам Debian, поэтому гайд совместим и с другими deb-based дистрибутивами. Для версий Special Edition (SE) учитывайте модуль мандатного контроля доступа Parsec (обычно не мешает работе libvirt).

Что такое CPU-пиннинг и зачем он нужен

CPU-пиннинг (привязка vCPU к физическим ядрам/потокам) исключает миграцию задач планировщиком ядра Linux между ядрами.

Это:

  • Снижает задержки (latency) и jitter
  • Уменьшает кэш-промахи L1/L2/L3
  • Повышает производительность ВМ с реальным временем, СУБД, сетевыми функциями (DPDK, OVS)
  • Гарантирует предсказуемое распределение ресурсов

Важно:

Пиннинг применяется только при старте ВМ. Динамическое изменение требует перезапуска.


1. Подготовка системы

# Обновить пакеты
sudo apt update && sudo apt upgrade -y

# Установить необходимые компоненты (если ещё не стоят)
sudo apt install -y qemu-kvm libvirt-daemon-system libvirt-clients bridge-utils virtinst

# Убедиться, что libvirt работает
sudo systemctl enable --now libvirtd

2. Анализ топологии CPU

Перед пиннингом нужно понять, как физически расположены ядра, потоки и NUMA-узлы.

# Подробная таблица ядер, потоков, сокетов и NUMA
lscpu -e

# Визуальная схема (установить, если нет)
sudo apt install -y hwloc-nox
hwloc-ls --output-format png > cpu_topology.png

# Проверка NUMA
numactl --hardware

Пример вывода lscpu -e:

CPU NODE SOCKET CORE L1d:L1i:L2:L3 ONLINE MAXMHZ    MINMHZ
0   0    0      0    0:0:0:0       yes    3600.0000 800.0000
1   0    0      0    0:0:0:0       yes    3600.0000 800.0000
2   0    0      1    1:1:1:0       yes    3600.0000 800.0000
3   0    0      1    1:1:1:0       yes    3600.0000 800.0000
...
  • CPU = логический ID (используется в cpuset)
  • CORE = физическое ядро
  • Потоки с одинаковым CORE но разным CPU — это Hyper-Threading / SMT.

Рекомендация:

  • Для low-latency избегайте привязки к SMT-соседям (пиньте только чётные или только нечётные CPU, либо отключите HT в BIOS).

3. Изоляция ядер на хосте (рекомендуется)

Чтобы хост-ОС и фоновые процессы не использовали выделенные под ВМ ядра, их нужно изолировать.

Вариант A: isolcpus (проверенный, простой)

sudo nano /etc/default/grub

Найти строку GRUB_CMDLINE_LINUX_DEFAULT и добавить:

isolcpus=2,3,4,5 nohz_full=2,3,4,5 rcu_nocbs=2,3,4,5

Замените 2,3,4,5 на нужные логические CPU из lscpu -e. Не изолируйте CPU 0 и 1 (оставьте под хост/IRQ).

Применить и перезагрузить:

sudo update-grub
sudo reboot

Вариант B: systemd/cgroups v2 (современный)

sudo systemctl set-property system.slice AllowedCPUs=0,1
sudo systemctl set-property user.slice AllowedCPUs=0,1

Подходит, если вы не хотите править GRUB. Требует перезапуска сервисов.

Проверка изоляции:

cat /sys/devices/system/cpu/isolated
# Должно вывести: 2,3,4,5

4. Настройка CPU-пиннинга в libvirt

Шаг 1: Открыть конфигурацию ВМ

virsh edit <имя_ВМ>

Шаг 2: Настроить <vcpu> и <cputune>

Пример для ВМ с 4 vCPU, привязанными к физическим CPU 2,3,4,5:

  <vcpu placement='static'>4</vcpu>
  <cputune>
    <vcpupin vcpu='0' cpuset='2'/>
    <vcpupin vcpu='1' cpuset='3'/>
    <vcpupin vcpu='2' cpuset='4'/>
    <vcpupin vcpu='3' cpuset='5'/>
    <emulatorpin cpuset='0-1'/>
  </cputune>

Пояснения:

  • placement='static' обязательно (иначе libvirt будет игнорировать пиннинг)
  • vcpu='N' — номер виртуального ядра внутри ВМ (начинается с 0)
  • cpuset='X' — логический ID физического CPU из lscpu
  • Можно указывать диапазоны: cpuset='2-5' или списки: cpuset='2,4,6,8'
  • <emulatorpin> привязывает эмулятор QEMU (поток qemu-kvm, не vCPU). Рекомендуется выносить на отдельные ядра хоста.

Шаг 3: Сохранить и выйти

virsh edit автоматически проверит синтаксис и применит изменения при сохранении.


5. Применение и проверка

Перезапуск ВМ (пиннинг применяется только при старте)

virsh destroy <имя_ВМ>
virsh start <имя_ВМ>

Проверка привязки

# Информация по vCPU
virsh vcpuinfo <имя_ВМ>

# Пример вывода:
# VCPU: 0
# CPU: 2
# State: running
# ...

# Проверка через taskset (PID процесса qemu)
ps aux | grep qemu | grep <имя_ВМ>
taskset -pc <PID>
# Должно вывести: pid <PID>'s current affinity list: 2,3,4,5

Визуальная проверка

htop
# F2 → Setup → Display options → Tree view
# Ищите процессы qemu-system-x86_64, смотрите на столбец CPU

6. NUMA-оптимизация (бонус для производительности)

Если система многосокетная или с несколькими NUMA-узлами, пиннинг без учёта NUMA может снизить производительность из-за удалённого доступа к памяти.

  <numatune>
    <memory mode='strict' nodeset='0'/>
  </numatune>
  <cputune>
    <vcpupin vcpu='0' cpuset='0,2'/>
    <vcpupin vcpu='1' cpuset='1,3'/>
    <emulatorpin cpuset='0,1'/>
  </cputune>
  <cpu mode='host-passthrough' check='partial'>
    <numa>
      <cell id='0' cpus='0-1' memory='4096' unit='KiB'/>
      <cell id='1' cpus='2-3' memory='4096' unit='KiB'/>
    </numa>
  </cpu>

nodeset='0' означает, что вся память ВМ будет выделяться из NUMA-узла 0. Используйте lscpu -e и numactl --hardware для сопоставления CPU и узлов.


7. Типичные ошибки и рекомендации

Ошибка Причина Решение
invalid cpuset '6' Указан несуществующий логический CPU Проверьте lscpu -e, учитывайте SMT
vcpu pinning ignored placement='auto' или отсутствует static Замените на placement='static'
ВМ не стартует после правки Синтаксическая ошибка XML virsh domxml-to-native qemu-argv /tmp/vm.xml для проверки
Хост "тормозит" Изолированы CPU под IRQ/host Не изолируйте CPU 0, оставьте 1-2 под хост
Пиннинг "сбрасывается" Используется virsh setvcpus или live-migration Пиннинг сохраняется только в XML, live-миграция требует перенастройки на целевом хосте

Best Practices

  1. Никогда не пиньте на cpu 0 (используется под host/irq/ACPI)
  2. Для low-latency: отключите SMT в BIOS или пиньте только на чётные CPU
  3. Сопоставляйте vCPU и pCPU 1:1, не используйте overcommit
  4. Выносите <emulatorpin> на отдельные ядра
  5. Регулярно проверяйте dmesg | grep -i cpu и /var/log/libvirt/qemu/*.log
  6. В Astra Linux SE при включённом Parsec убедитесь, что профиль libvirt разрешает cpuaffinity (обычно настроено по умолчанию)

Полезные команды-шпаргалка

# Топология
lscpu -e
numactl --hardware

# Редактирование ВМ
virsh edit <vm>

# Проверка привязки
virsh vcpuinfo <vm>
virsh dominfo <vm> | grep -i cpu

# Перезапуск
virsh destroy <vm> && virsh start <vm>

# Мониторинг в реальном времени
watch -n 1 'virsh vcpuinfo <vm> | grep -E "VCPU|CPU"'

Заключение

CPU-пиннинг в Astra Linux 1.8 настраивается стандартными средствами libvirt.