Оптимизация дисковой подсистемы в KVM

Источник Автор (ruvds) предлагает сделать три шага для увеличения производительности.

Шаг 1. Размещать диски ВМ не в виде файлов, а на устройстве LVM

Логика такая. Файл с виртуальным диском хранится в файловой системе Linux, внутри самого файла находится NTFS.
Каждая файловая система потребляет ресурсы при дисковых операциях. Поэтому чем меньше глубина матрёшки, тем быстрее ввод/вывод.

Слой LVM потребляет значительно меньше процессорных ресурсов, чем файловая система. Одна из причин этого то, что блоки в нём значительно больше, чем типичный блок файловой системы (4КБ).
Чем больше блок (extent) на физическом устройстве LVM, тем более быстро происходит IO и тем меньше фрагментация.

LVM довольно удобно использовать для хостинга виртуальных машин. LVM-тома легко переносимы между физическими дисками, есть снимки (snapshot), изменение размера в режиме онлайн.
Тем более, что virt-manager (libvirt) умеет из коробки создавать логические тома под диски виртуальных машин из Volume group (группы томов).

# Инициализируем физический раздел SSD для группы томов (volume group)
pvcreate /dev/nvme1n1p1

# Создаёт группу том win с размером блока (extent) 256МБ.
vgcreate -s 256M win_pool /dev/nvme1n1p1

# Создаём логический том vm1. Подойдёт для диска C
lvcreate -n vm1 -L 100G win_pool

# Отключаем упреждающее кеширование при чтении (read ahead)
lvchange -r none /dev/win_pool/vm1

Если вы хотите использовать thin pool, в котором будете создавать тонкие тома, то имеет смысл установить размер чанка у пула в 4МБ, что значительно больше размера по-умолчанию в 64КБ.
Что повлечёт более быструю работу этого слоя абстракции.

Механизм снимков в LVM работает практически на том же самом коде, что и тонкие тома, поэтому для увеличения скорости снимков (snapshot) настройки будут теми же самыми.

lvcreate -c 4m -L 300G -T -Zn win_pool/thin
Опция -Zn отключает перезапись чанка нулями при выделении, что повышает скорость работы.

Настройки для lvm.conf или подобного файла (например lvmlocal.conf):

thin_pool_chunk_size = 4096
thin_pool_zero = n
Вы можете сами определить оптимальный размер чанка выполнив тестирование следующей командой, подобрав величину –blocksize:
fio --name=randwrite --filename=/dev/nvme0n1p9 --size=10G --ioengine=libaio --iodepth=1 --buffered=0 --direct=1 --rw=randwrite --blocksize=4m
Посмотреть текущий размер чанка можно командой:
lvs -ao name,chunksize

Шаг 2. Использовать hugepages

Hugepages нужно использовать, чтобы избежать снижения производительности из-за фрагментации RAM

apt install hugepages
Правим /etc/default/grub:
GRUB_CMDLINE_LINUX="default_hugepagesz=1GB hugepagesz=1G hugepages=64"
В данном случае было выделено 64ГБ памяти для всех виртуальных машин в виде hugepages.
Применяем эти настройки для GRUB, чтобы при следующей загрузке системы они стали активны:
grub-mkconfig -o /boot/grub/grub.cfg

Правим описание конфигурации ВМ с помощью “virsh edit vm_name”

Включаем поддержку hugepages

<memoryBacking>
  <hugepages/>
</memoryBacking>

Шаг 3. Выделяем поток для операций ввода-вывода

Добавляем в каждую виртуальную машину выделенный поток для обслуживания IO

**<iothreads>1</iothreads>**
...
<disk type='block' device='disk'>
<driver name='qemu' type='raw' cache='none' io='threads' **iothread='1'/**>
<source dev='/dev/win/terminal'/>
<target dev='vda' bus='virtio'/>
<boot order='2'/>
<address type='pci' domain='0x0000' bus='0x04' slot='0x00' function='0x0'/>
</disk>