Изоляция ресурсов KVM от шумного соседа: проверка CPU, памяти, диска и сети
Изоляция ресурсов KVM от шумного соседа проверяется по метрикам полезной нагрузки. Если шумный сосед в KVM занял CPU, память, очередь диска или сетевой канал, начните смотреть, сохранились ли латентность и пропускная способность контрольной VM. Стало: Также стоит иметь в виду, что по типу виртуализации нельзя судить об оверкоммите, NUMA-размещении и правилах cgroup на хосте.
Какие ресурсы KVM изолирует надёжнее всего?
Связка KVM/QEMU разделяет адресные пространства и состояние виртуальных машин. Реальная стабильность производительности зависит от политик хоста: CPU-квот, привязки vCPU, NUMA-размещения, лимитов block I/O и сетевого шейпинга. Эти механизмы не изолируют все общие очереди, поэтому результат проверяют по SLO полезной нагрузки.
Определить общие ресурсы и SLO жертвы
Для начала разделите слои, через которые проходит запрос. Контрольная нагрузка (victim workload) работает внутри гостя. QEMU обслуживает виртуальные устройства и vCPU, ядро планирует его потоки, а физические CPU, NUMA-узлы, накопители и сетевые порты остаются общими. Поэтому шумный сосед в KVM может увеличить ожидание процессора, очередь диска или задержку в сети.
Для контрольной нагрузки задайте один SLO, например верхнюю границу p99 ответа API. Порог берите из требований сервиса. Базовые показатели снимают в одинаковых прогонах и сохраняют с версиями ядра, QEMU, libvirt и параметрами теста.
Топологию нужно фиксировать до нагрузки. На хосте собирают сведения о CPU, NUMA, привязке vCPU и XML обеих VM, а внутри гостевой системы – топологию и метрики приложения. Без такой карты просадка показывает корреляцию, а не причину. Отдельная RAM в ней ничего не гарантирует, так как контроллер памяти, кэш последнего уровня (LLC), диск и сетевой канал остаются общими.
Проверить квоты, pinning и steal под CPU-aggressor
Изоляция CPU виртуальной машины начинается с топологии vCPU. В libvirt указаны допустимые pCPU, а quota и period ограничивают процессорное время. Привязка vCPU сокращает миграции, но конкуренция внутри ядра и за общий кэш остаётся.
Сначала измерьте контрольную нагрузку без соседа, затем запустите конкурирующую нагрузку на другой VM или в отдельной cgroup. В госте собирайте p50/p95/p99 приложения, очередь выполнения и %steal. Рост %steal означает, что гипервизор отдавал время другой работе. Какой именно VM, счётчик не показывает, а нулевой %steal не исключает конкуренцию за LLC и память.
Сравните свободное планирование, раздельные cpuset и привязку к разным физическим ядрам. Квоту и привязку меняйте по очереди. Для проверки SMT нагрузите соседний аппаратный поток того же ядра. Привязку vCPU оставляйте, если выигрыш в хвостовой латентности оправдывает резерв.
Исключить ballooning, reclaim и удалённый доступ к памяти
В госте на нехватку памяти указывают reclaim, major page faults и подкачка. На хосте похожие симптомы создают memory.high, ballooning, KSM и удалённый NUMA-доступ. Эти симптомы совпадают, поэтому причину определяют сопоставлением метрик гостя и хоста.
Перед нагрузкой сохраните numatune, memoryBacking, huge pages и состояние memballoon. Затем создайте давление на память в другой VM. Во время прогона собирайте PSI для памяти, memory.events, распределение памяти QEMU по NUMA-узлам и латентность приложения. Параметр memory.high замедляет процессы и усиливает reclaim, а memory.max может привести к OOM внутри cgroup.
Как воспроизвести и измерить влияние шумного соседа?
Сначала снимите повторяемые базовые показатели контрольной нагрузки, затем по очереди добавляйте возрастающую нагрузку на CPU, память, диск и сеть. Сравнивайте пропускную способность и распределение латентности, сохраняя конфигурацию и повторяя каждый этап. После остановки соседа проверьте, вернулись ли показатели к исходному уровню.
NUMA-доступ проверяют отдельно: vCPU и память контрольной VM размещают сначала на одном узле, затем на разных. Ограничение I/O в KVM не заменит NUMA-политику, поскольку лимиты диска не влияют на то, с какого узла VM читает память. Если memory pressure не меняется, а латентность растёт при удалённом доступе, проверьте NUMA-размещение и пропускную способность памяти.
Ограничить очередь соседа на общем хранилище
Посмотрите, на каком устройстве лежит диск: разные виртуальные диски могут попадать на один NVMe, RAID или сетевой пул. Изоляция ресурсов cgroup в block I/O опирается на лимиты, которые ядро применяет к процессу QEMU. Через iotune в libvirt задают BPS и IOPS на уровне QEMU, а io.max и io.weight – на уровне cgroup. Вес действует только при конкуренции, жёсткий лимит – всегда.
Профиль контрольной нагрузки не меняют: например, синхронная запись по 4 КиБ при глубине очереди 1. Соседа запускают отдельно для чтения, записи и fsync. После сравнивают p50/p95/p99 латентности операций и пропускную способность. Буферизованная запись без fsync может не дойти до накопителя за время прогона. Поэтому прямой I/O, размер блока и глубину очереди фиксируют.
Лимит задаётся на общем узком участке. Без общей throttle group сосед может использовать второй диск в обход ограничения. Затем повторяют базовый прогон, нагрузку и восстановление. Лимит сработал, если p99 контрольной нагрузки остался в базовом диапазоне, а сосед достиг заданных IOPS. Если нет, проверьте устройство, планировщик ввода-вывода и writeback.
Проверить очереди vhost, shaping и общий uplink
Сетевой трафик проходит через очереди virtio/vhost, CPU для softirq, qdisc, виртуальный коммутатор и uplink. Поэтому перед прогоном сохраните модель интерфейса, число очередей, привязку IRQ и лимиты. В одном прогоне нагружают канал крупными пакетами, в другом – мелкими с высоким PPS. Эти профили нагружают разные части тракта.
На контрольной VM измеряйте латентность, джиттер, потери и прикладную пропускную способность. Работа без потерь не означает стабильный p99, так как очередь может расти перед qdisc или uplink. Шейпинг нужно проверять в обоих направлениях. Очереди virtio-net расходуют CPU, поэтому их число не стоит механически приравнивать к числу vCPU.
Поток мелких пакетов может загрузить softirq и вытеснить QEMU с pCPU. Тот же профиль латентности даёт конкуренция за пропускную способность памяти, поэтому сетевую гипотезу нужно подтверждать отдельно. Для этого сопоставьте IRQ, softnet_stat, сбросы qdisc и загрузку vhost-потоков. Какой бы не оказалась причина, к отчёту приложите топологию, XML libvirt, политики cgroup, параметры нагрузок и сырые ряды.
Построить повторяемую матрицу victim и aggressor
В строке матрицы указывают вид и интенсивность нагрузки соседа, p50/p95/p99 латентности, пропускную способность контрольной VM, метрики ресурса и время восстановления. Порядок один: базовый прогон, нагрузка, остановка соседа, восстановление. Конфигурацию и лимиты менять не нужно.
Какие лимиты снижают помехи без лишней потери мощности?
- CPU-квота ограничивает процессорное время, а cpuset оставляет планировщику выбор внутри набора ядер.
- Параметры io.max или iotune сдерживает BPS и IOPS соседа, не резервируя накопитель целиком.
- Шейпинг ограничивает полосу и кратковременные всплески. Выделенное ядро или устройство нужны лишь при подтверждённом риске для SLO.
Пиннинг CPU KVM проверяйте отдельно: сначала задайте VM пересекающиеся наборы pCPU, затем разведите их по физическим ядрам. Команды ниже фиксируют топологию и складывают вывод в каталог прогона. В каждом таком каталоге укажите автора замера, дату и версии ПО.
Разделить сигналы гостя и доказательства хоста
Метрики гостя показывают влияние на сервис, но редко доказывают причину. Чаще всего смотрят три сигнала. Счётчик %steal указывает на время, отданное гипервизором другой работе. Показатель iowait отражает простой CPU при незавершённых I/O, а скорость диска не измеряет вовсе. PSI даёт долю простоя задач из-за нехватки CPU, памяти или I/O. Ни один из трёх не уличает оверкоммит, поскольку похожие симптомы дают квота, NUMA-размещение, writeback и перегруженный uplink.
На хосте сигнал сопоставляют с cgroup и потоками QEMU. Нужны cpu.stat, cpu.pressure, memory.events, memory.pressure, io.stat, io.pressure, статистика домена libvirt и устройства. Совпадение просадки контрольной нагрузки, давления в её cgroup и активности соседа сужает круг причин. Тот же результат после перезапуска соседа подтверждает вывод.
Клиент публичного VDS обычно не видит cgroup хоста, привязку vCPU к pCPU и устройство хранения. Эту часть картины может дать только провайдер, поэтому в обращении поддержке приложите время, ID VM, профиль теста, базовые показатели, отклонение и сырые ряды. Точный интервал будет полезнее скриншота load average, ведь его можно сопоставить с миграцией VM и телеметрией узла.
Выбрать контроль по измеренному риску
Ограничение нужно выбирать по тому ресурсу, который нарушил SLO. CPU-квота ограничивает соседа, но увеличивает его латентность после исчерпания квоты за период. Параметр cpuset сужает область конкуренции, а выделенное ядро убирает чужие vCPU. Такой резерв дороже и требует учёта SMT, потоков эмулятора и IOThreads.
Для памяти применяют NUMA-привязку, memory.high и отказ от агрессивного ballooning. Для диска выбирают вес, лимит BPS/IOPS или отдельное устройство, для сети – шейпинг, отдельную очередь или uplink. Объём RAM при конкуренции за пропускную способность памяти или LLC не поможет, а любое резервирование снижает коэффициент консолидации.
Выбранное ограничение оценивают по p99 latency и пропускной способности контрольной нагрузки, а не по XML. После миграции хоста, смены тарифа, ядра, QEMU или схемы хранения тест повторяют, так как могут измениться NUMA-топология и устройство хранения. Если мягкий лимит удерживает SLO, выделенный ресурс избыточен. Если хвосты нестабильны, резервирование оправдано измеренным риском.
Изоляцию ресурсов KVM от шумного соседа можно подтвердить, если нагрузка соседа не нарушает SLO контрольной VM, а результат воспроизводится. Недостаточно строки KVM в тарифе, низкого load average или отдельного объёма RAM. Нужны карта общих ресурсов, один изменяемый фактор, временные ряды и проверка восстановления. Если видны только метрики гостя, зафиксируйте влияние на приложение и передайте поддержке точный интервал: без телеметрии хоста причину установить нельзя.