Иногда я берусь за различные задачи по настройке серверов. Некоторое время назад ко мне обратился владелец небольшой хостинговой компании, с интересной проблемой. Он хотел бы на своих серверах, где уже стоял Ubuntu 18.04, запускать виртуальные машины с Windows под KVM.
Однако проведённое им тестирование показало, что дисковая система KVM прилично отставала от показателей, которые у него были под Hyper-V. Он хотел раскочегарить qemu на своих Ubuntu серверах, чтобы избежать закупок дорогих серверных лицензий Windows (бесплатная версия Microsoft Hyper-V Server не устраивала из-за своих ограничений).
0. Диспозиция
Для тестирования использовался SSD Samsung 970 Pro 1TB. Заказчик проверял результаты работы в CrystalDiskMark, поэтому далее в статье все графики из него.
Windows 10 LTSC | Hyper-V 2 CPU |
KVM 2 CPU |
---|---|---|
Начнём с того, что в Ubuntu (16.04 LTS и 18.04) до сих пор используется qemu версии 2.11. Поэтому некоторые плюшки самых последних qemu в этой статье не рассмотрены.
Мы решили что нам нужно избежать привязывания железа к виртуальной машине, так как это осложняет переносимость виртуальных машин, поэтому варианты с прокидыванием SSD в виртуалки были признанны нежелательными.
1. Используем LVM-тома, а не файлы для хранения дисков виртуальных машин.
Логика такая. Файл с виртуальным диском хранится в файловой системе Linux, внутри самого файла находится NTFS. Каждая файловая система потребляет ресурсы при дисковых операциях. Поэтому чем меньше глубина матрёшки, тем быстрее ввод/вывод.
Слой LVM потребляет значительно меньше процессорных ресурсов, чем файловая система. Одна из причин этого то, что блоки в нём значительно больше, чем типичный блок файловой системы (4КБ). Чем больше блок (extent) на физическом устройстве LVM, тем более быстро происходит IO и тем меньше фрагментация.
А ведь даже для SSD случайный ввод/вывод значительно медленнее, чем последовательный.
LVM довольно удобно использовать для
Поэтому при создании Volume Group мы укажем очень большую величину extent: 256MB.
Привлекательной выглядит также возможность создать thin volumes («тонкие» тома), но если учесть, что тонкий том — это дополнительный слой абстракции, то, очевидно, что он будет ухудшать производительность IO. К тому же в libvirt нет элегантного пути автоматического создания дисков для виртуальных машин в «тонком» пуле.
Read ahead на логическом томе стоит отключить, так как он расходует IO без выигрыша, так как теперь никто не занимается дефрагментацией дисков в Windows на SSD.
# Инициализируем физический раздел SSD для группы томов (volume group)
pvcreate /dev/nvme1n1p1
# Создаёт группу том win с размером блока (extent) 256МБ.
vgcreate -s 256M win_pool /dev/nvme1n1p1
# Создаём логический том vm1. Подойдёт для диска C
lvcreate -n vm1 -L 100G -c 4m
# Отключаем упреждающее кеширование при чтении (read ahead)
lvchange -r none /dev/win_pool/vm1
1.1. Thin volume как диск и/или настройки логических томов для снимков
Если вы хотите использовать thin pool, в котором будете создавать тонкие тома, то имеет смысл установить размер чанка у пула в 4МБ, что значительно больше размера по-умолчанию в 64КБ.
Что повлечёт более быструю работу этого слоя абстракции.
Механизм снимков в LVM работает практически на том же самом коде, что и тонкие тома, поэтому для увеличения скорости снимков (snapshot) настройки будут теми же самыми.
lvcreate -c 4m ....
Или в lvm.conf или подобном файле (например lvmlocal.conf):
thin_pool_chunk_size = 4096
Вы можете сами определить оптимальный размер чанка выполнив тестирование следующей командой, подобрав величину --blocksize
:
fio --name=randwrite --filename=/dev/nvme0n1p9 --size=10G --ioengine=libaio --iodepth=1 --buffered=0 --direct=1 --rw=randwrite --blocksize=4m
2. Увеличение количества логических процессоров, выделяемых на каждую виртуальную машину KVM, улучшает дисковую производительность
10 CPU | 8 CPU | 4 CPU |
---|---|---|
Понятно, что вряд ли кто будет выделять на виртуалку 10 процессоров, но было интересно посмотреть на крайний случай.
Тут уже зависит от числа свободных процессоров. На мой взгляд больше 4-х выделять нецелесообразно. При числе потоков равному 8 мы получили максимальную производительность случайного чтения и записи. Это специфика CrystalDiskMark 6.0.2, в котором второй тест проводит 8-ю потоками.
Из чего можно сделать вывод, что хорошо иметь по одному логическому процессору на каждую задачу, активно использующую IO.
3. Используем огромные страницы оперативной памяти, чтобы избежать снижения производительности из-за фрагментации RAM
Этот пакет может пригодиться, когда нам понадобится различная информация о hugepages в процессе эксплуатации.
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
Добавляем:
<memoryBacking>
<hugepages/>
</memoryBacking>
4. Добавляем в каждую виртуальную машину выделенный поток для обслуживания IO
Нужно добавить то, что выделено жирным. Используем virsh
, как и в предыдущем пункте.
<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>
4.1. Для ускорения случайной записи используем кеширование writeback
Для ускорения случайной записи на диск, но с увеличением риска потери данных, можно использовать cache=writeback
в предыдущем пункте. Можно использовать только если есть большая уверенность в качестве и резервировании питания и при наличии бакапов.
5. Настройки дисковой подсистемы в В Virt Manager
Disk bus: VirtIO
Storage format: raw
Cache mode: writeback
IO mode: threads
5.1. Настройка дисковой подсистемы через конфигурационный файл
Qemu 2.11 (который сейчас используется в Ubuntu) поддерживает для типа дисковых виртуальных устройств: virtio-blk и virtio-scsi. Когда в Virt Manager указывается Disk bus: VirtIO
— это означает использование устройства virtio-blk.
Во всех случаях по скорости лучше virtio-blk. Использовать virtio-scsi имеет смысл в экзотических случаях, например, когда нужно подключать сотни дисков к виртуальной машине.
6. В процессе инсталляции Windows устанавливаем драйвер VirtIO
Иначе диск не будет доступен для ОС. Для этого используем образ с драйверами, который предварительно подключаем к виртуальной машине.
7. Результаты после применения всех твиков
На самом деле твик 4.1 не был применён, так как я не был уверен в надёжности питания у клиента.
Hyper-V 2 CPU |
KVM 2 CPU |
KVM 4 CPU |
---|---|---|
Нужно понимать, что эти результаты грешат некой условностью, так как при каждом запуске CrystalDiskMark значения немного отличаются.
KVM из коробки 2 CPU |
KVM после твиков 2 CPU |
---|---|
Мы видим, что удалось существенно ускорить работу дисковой подсистемы в qemu (kvm) при одном и том же числе ядер. Запись была ускорена в среднем на 58%, а чтение на 25%.
Основные элементы успеха: использование LVM-томов вместо файлов qcow2, отдельный поток ввода/вывода и hugepages.
Замеченные ошибки направляйте в личку. Повышаю за это карму.
P.S. vhost-user-blk и vhost-user-nvme
В ходе экспериментов были также и скомпилированы Qemu 2.12 и 3-й версии. Тестировалась опция vhost-user-blk для диска.
В итоге она работала хуже, чем virtio-blk.
vhost-user-blk 4 CPU |
virtio-blk 4 CPU |
---|---|
Для использования vhost-user-nvme нужно было патчить qemu, этот вариант усложнял автоматическое обновление серверов в продакшене, поэтому не был протестирован.
P.P.S. SPDK
Intel разработала этот фреймворк для достижения выдающихся показателей производительности у дисковых систем в виртуальных машинах, которые должны работать на её процессорах.
Чтобы заставить spdk хорошо работать идут на массу ухищрений — выделяют ему отдельные ядра, размещают ядра spdk и виртуальной машины в одном сокете. Загружают виртуальную машину в непрерывный кусок памяти. Если такие меры применять к обычному virtio-blk, то он тоже будет быстрее работать.
SPDK способен работать в 3-х режимах: vhost-user-scsi, vhost-user-blk и vhost-user-nvme. Второй режим доступен только в qemu от 2.12, который ещё не доступен в ubuntu. Режим vhost-user-nvme вообще мегаэкспериментальный — для него нужно патчить qemu. На текущий момент работает только эмуляция scsi и она медленная.
Есть ещё одно серьёзное ограничение для режима vhost-user-scsi — диск spdk не может быть загрузочным.
Make sure bootindex=2 Qemu option is given to vhost-user-scsi-pci device.
Рекорды ставятся, когда они с помощью своего драйвера разделяют SSD на несколько устройств и прокидывают их как vhost-user-nvme. Подход с прокидыванием железа нам не подходил.
Сложилось впечатление, что нормально использовать SPDK можно только с их реализацией логических дисков (которая совершенно отличается от стандартных lvm). Это такой самопальный велосипед со своими снимками и клонированием. Команды все отличаются от LVM.
Сложность в настройке SPDK, поддержке и переносимости виртуальных машин, а также привязанность к процессорам Intel отвернула от его использования.
Благодарности
За изображение спасибо TripletConcept. Его лучше смотреть в полном размере в отдельном окне.
За разрешение поделиться рабочими материалами — st_neon
Вы можете заказать виртуальную машину с SSD у RUVDS по купону ниже.
Замеченные ошибки направляйте в личку. Повышаю за это карму.
Автор: Сергей Ю. Каменев