Application: KVM 0.12.5 (Kernel-based Virtual Machine).
Задача: выбор типа виртуального диска KVM и параметров конфигурации, создающих наименьшее сопротивление трафику ввода/вывода.
Методика:
Выбор типа носителя виртуального диска;
Выбор типа разметки носителя виртуального диска;
Разметка раздела, выделенного под тесты, форматирование его, если в этом есть необходимость;
Выбор типа виртуального диска;
Выбор типа разметки виртуального диска;
Установка на виртуальный диск операционной системы (Debian Linux Squeeze 6.0.4 (amd64)) по условному сценарию, одинаковому для всех тестов;
Загрузка на диск массива файлов (архив справочных пособий и дистрибутивов, общим объёмом около 5-ти Гигабайт (5 337 369 897 байт, 7489 файла в составе 429-ти директорий)), неизменный на период тестов;
Перед запуском теста сброс дискового "кеша" операционной системы;
Перемещение заготовленного массива файлов в бинарный архив без сжатия с последующей распаковкой такового, что позволит избежать побочных эффектов от перегрузки процессора (синтетические тесты проводить не вижу смысла).
Выбор типа разметки носителя виртуального диска;
Разметка раздела, выделенного под тесты, форматирование его, если в этом есть необходимость;
Выбор типа виртуального диска;
Выбор типа разметки виртуального диска;
Установка на виртуальный диск операционной системы (Debian Linux Squeeze 6.0.4 (amd64)) по условному сценарию, одинаковому для всех тестов;
Загрузка на диск массива файлов (архив справочных пособий и дистрибутивов, общим объёмом около 5-ти Гигабайт (5 337 369 897 байт, 7489 файла в составе 429-ти директорий)), неизменный на период тестов;
Перед запуском теста сброс дискового "кеша" операционной системы;
Перемещение заготовленного массива файлов в бинарный архив без сжатия с последующей распаковкой такового, что позволит избежать побочных эффектов от перегрузки процессора (синтетические тесты проводить не вижу смысла).
Да, методика небыстрая, много работы с установкой системы перед каждой серией тестов, но мне хотелось по возможности воссоздать реальные условия эксплуатации.
Варианты тестов:
disk partition + KVM cache writethrough (default);
disk partition + KVM cache writeback;
disk partition + KVM cache none;
XFS + raw + no preallocation + KVM cache writethrough (default);
XFS + raw + no preallocation + KVM cache writeback;
XFS + raw + no preallocation + KVM cache none;
XFS + raw + preallocation + KVM cache writethrough (default);
XFS + raw + preallocation + KVM cache writeback;
XFS + raw + preallocation + KVM cache none;
XFS + QCOW2 + no preallocation + KVM cache writethrough (default);
XFS + QCOW2 + no preallocation + KVM cache writeback;
XFS + QCOW2 + no preallocation + KVM cache none;
XFS + QCOW2 + preallocation + KVM cache writethrough (default);
XFS + QCOW2 + preallocation + KVM cache writeback;
XFS + QCOW2 + preallocation + KVM cache none;
disk partition + KVM cache writeback;
disk partition + KVM cache none;
XFS + raw + no preallocation + KVM cache writethrough (default);
XFS + raw + no preallocation + KVM cache writeback;
XFS + raw + no preallocation + KVM cache none;
XFS + raw + preallocation + KVM cache writethrough (default);
XFS + raw + preallocation + KVM cache writeback;
XFS + raw + preallocation + KVM cache none;
XFS + QCOW2 + no preallocation + KVM cache writethrough (default);
XFS + QCOW2 + no preallocation + KVM cache writeback;
XFS + QCOW2 + no preallocation + KVM cache none;
XFS + QCOW2 + preallocation + KVM cache writethrough (default);
XFS + QCOW2 + preallocation + KVM cache writeback;
XFS + QCOW2 + preallocation + KVM cache none;
Прежде чем заниматься непосредственно тестированием, подготовим операционную систему носитель к обеспечению достаточно неизменной производительности; в частности, с помощью "cpufrequtils" устанавливаем для всех ядер центрального процессора режим выдачи максимальной частоты (по умолчанию выбран режим адаптивной подстройки частоты центрального процессора в зависимости от нагрузки, вносящий существенные погрешности в результаты любых тестов).
# aptitude install cpufrequtils
# lsmod | grep acpi_cpufreq
# modprobe acpi-cpufreq
# cpufreq-info
# lsmod | grep acpi_cpufreq
# modprobe acpi-cpufreq
# cpufreq-info
....
analyzing CPU 0:
....
available frequency steps: 2.70 GHz, 1.80 GHz, 1.20 GHz
current policy: frequency should be within 1.20 GHz and 2.70 GHz.
The governor "ondemand" may decide which speed to use within this range.
....
analyzing CPU 0:
....
available frequency steps: 2.70 GHz, 1.80 GHz, 1.20 GHz
current policy: frequency should be within 1.20 GHz and 2.70 GHz.
The governor "ondemand" may decide which speed to use within this range.
....
Видно, что ядра процессора готовы переключатся между частотой в 1.20 GHz и 2.70 GHz, шагами по 2.7 GHz, 1.8 GHz и 1.2 GHz. По умолчанию выбрана схема "подачи частоты" по необходимости, что меня не устраивает. Профиль "cpufreq" в Debian Squeeze меняется прямо в скрипте инициализации:
# cat /etc/init.d/cpufrequtils
....
ENABLE="true"
GOVERNOR="performance"
....
ENABLE="true"
GOVERNOR="performance"
....
# /etc/init.d/cpufrequtils restart
Заранее, не тратя время на автоматизацию процесса, вручную создаём тестовый виртуальный сетевой интерфейс и подключаем его к виртуальному системному "мосту" (можно этого и не делать, обходясь поддержкой встроенного в KVM NAT, но мне хотелось простого прямого доступа к тестируемым машинам):
# tunctl -b -t tap0
# ifconfig tap0 0.0.0.0 up
# brctl addif br0 tap0
# ifconfig tap0 0.0.0.0 up
# brctl addif br0 tap0
Теперь пишем скрипт, с помощью которого будем формировать строку запуска виртуальной машины:
# touch ~/start-vm.sh
# chmod ugo+rx ~/start-vm.sh
# chmod ugo+rx ~/start-vm.sh
#!/bin/bash
export PATH=/sbin:/bin:/usr/sbin:/usr/bin:/usr/local/sbin:/usr/local/bin
DATE=`date +"%Y-%m-%d %H:%M:%S"`
# Disk: address disk partition, RAW file or QCOW2 file
DSK0=""
# Cache: "writethrough" (default), "writeback" or "none"
CACHE=""
# "c" - HDD or "d" - CD
BOOTORDER=""
DRIVE0="-drive file=${DSK0},if=ide,index=1,media=disk,snapshot=off,cache=${CACHE},aio=threads"
CD0="-drive file=/path/to/image.iso,if=ide,index=2,media=cdrom"
/usr/bin/kvm -name test -daemonize -enable-kvm ${DRIVE0} ${CD0} -boot ${BOOTORDER} -m 256 -cpu host -smp 1,cores=1 -clock unix -rtc base=utc,clock=vm -no-hpet -vnc :1 -net nic,macaddr=52:54:0c:b8:71:b0,model=rtl8139 -net tap,ifname=tap0,script=no,downscript=no
# VNC: 5901
exit 0
export PATH=/sbin:/bin:/usr/sbin:/usr/bin:/usr/local/sbin:/usr/local/bin
DATE=`date +"%Y-%m-%d %H:%M:%S"`
# Disk: address disk partition, RAW file or QCOW2 file
DSK0=""
# Cache: "writethrough" (default), "writeback" or "none"
CACHE=""
# "c" - HDD or "d" - CD
BOOTORDER=""
DRIVE0="-drive file=${DSK0},if=ide,index=1,media=disk,snapshot=off,cache=${CACHE},aio=threads"
CD0="-drive file=/path/to/image.iso,if=ide,index=2,media=cdrom"
/usr/bin/kvm -name test -daemonize -enable-kvm ${DRIVE0} ${CD0} -boot ${BOOTORDER} -m 256 -cpu host -smp 1,cores=1 -clock unix -rtc base=utc,clock=vm -no-hpet -vnc :1 -net nic,macaddr=52:54:0c:b8:71:b0,model=rtl8139 -net tap,ifname=tap0,script=no,downscript=no
# VNC: 5901
exit 0
Вначале мы запускаем скрипт для установки системы в виртуальную машину, применяя к переменной "BOOTORDER" значение "d", потом запускаем уже установленную систему со значением переменной - "c".
В моём случае дисковый контроллер "virtio" нестабильно себя вёл, запросто мог "увидеть" диск при одном запуске и "не увидеть" его-же при следующем. Пришлось от него отказаться в пользу привычного IDE, в конце-концов тесты на сравнительные, а не абсолютные показатели.
В соответствии с планом пришлось несколько раз устанавливать тестовые операционные системы на вновь создаваемые виртуальные диски. Сценарий установки был неизменен и таков:
Advansed options;
Expert install;
Choose language => English, Location => US, Locale => en_US.UTF-8, Select a keyboard layout => PC-style, Keymap => American English;
Load installer componets from CD => cfdisk-udeb, parted-udeb;
Configure the network => IP manual, Hostname => debian.local;
Set users and passwords => Enable shadow, enable login as root, one new user;
Configure the clock => No using NTP, UTC;
Partition disks => msdos type;
100 GB ATA QEMU HARDDISK, primary, / as Ext3, noatime, bootable;
1.1 GB primary, swap;
Install the base system => linux-image-2.6.32.5-amd64, generic drivers;
Configure the package manager => no network mirror;
Select and install software => SSH server, Standard system utilites;
Install the GRUB boot loader => to the master boot record;
Finish.
Expert install;
Choose language => English, Location => US, Locale => en_US.UTF-8, Select a keyboard layout => PC-style, Keymap => American English;
Load installer componets from CD => cfdisk-udeb, parted-udeb;
Configure the network => IP manual, Hostname => debian.local;
Set users and passwords => Enable shadow, enable login as root, one new user;
Configure the clock => No using NTP, UTC;
Partition disks => msdos type;
100 GB ATA QEMU HARDDISK, primary, / as Ext3, noatime, bootable;
1.1 GB primary, swap;
Install the base system => linux-image-2.6.32.5-amd64, generic drivers;
Configure the package manager => no network mirror;
Select and install software => SSH server, Standard system utilites;
Install the GRUB boot loader => to the master boot record;
Finish.
После инсталляции тестовой операционной системы на неё загружалась масса файлов, время дальнейшей обработки которых и давало возможность оценить производительность дисковой подсистемы. На стороне тестовой системы создавался скрипт, запускающий на исполнение тесты с фиксированием времени, затраченного на исполнение:
# touch ~/start-test.sh
# chmod ugo+rx ~/start-test.sh
# chmod ugo+rx ~/start-test.sh
#!/bin/bash
export PATH=/sbin:/bin:/usr/sbin:/usr/bin:/usr/local/sbin:/usr/local/bin
# DATE=`date +"%Y-%m-%d %H:%M:%S"`
DIRHOME="~"
DIRFROM="${DIRHOME}/from"
DIRTO="${DIRHOME}/to"
echo "tar-step-1-pack-begin: `date +"%Y-%m-%d %H:%M:%S"`" >> ${DIRHOME}/test.log
tar -cf ${DIRTO}/step-1.tar ${DIRFROM}
echo "tar-step-1-pack-end: `date +"%Y-%m-%d %H:%M:%S"`" >> ${DIRHOME}/test.log
echo "tar-step-2-pack-begin: `date +"%Y-%m-%d %H:%M:%S"`" >> ${DIRHOME}/test.log
tar -cf ${DIRTO}/step-2.tar ${DIRFROM}
echo "tar-step-2-pack-end: `date +"%Y-%m-%d %H:%M:%S"`" >> ${DIRHOME}/test.log
cd ${DIRTO}
echo "tar-step-3-unpack-begin: `date +"%Y-%m-%d %H:%M:%S"`" >> ${DIRHOME}/test.log
tar -xf ${DIRTO}/step-1.tar
tar -xf ${DIRTO}/step-2.tar
echo "tar-step-3-unpack-end: `date +"%Y-%m-%d %H:%M:%S"`" >> ${DIRHOME}/test.log
rm -r ${DIRTO}/*
exit 0
export PATH=/sbin:/bin:/usr/sbin:/usr/bin:/usr/local/sbin:/usr/local/bin
# DATE=`date +"%Y-%m-%d %H:%M:%S"`
DIRHOME="~"
DIRFROM="${DIRHOME}/from"
DIRTO="${DIRHOME}/to"
echo "tar-step-1-pack-begin: `date +"%Y-%m-%d %H:%M:%S"`" >> ${DIRHOME}/test.log
tar -cf ${DIRTO}/step-1.tar ${DIRFROM}
echo "tar-step-1-pack-end: `date +"%Y-%m-%d %H:%M:%S"`" >> ${DIRHOME}/test.log
echo "tar-step-2-pack-begin: `date +"%Y-%m-%d %H:%M:%S"`" >> ${DIRHOME}/test.log
tar -cf ${DIRTO}/step-2.tar ${DIRFROM}
echo "tar-step-2-pack-end: `date +"%Y-%m-%d %H:%M:%S"`" >> ${DIRHOME}/test.log
cd ${DIRTO}
echo "tar-step-3-unpack-begin: `date +"%Y-%m-%d %H:%M:%S"`" >> ${DIRHOME}/test.log
tar -xf ${DIRTO}/step-1.tar
tar -xf ${DIRTO}/step-2.tar
echo "tar-step-3-unpack-end: `date +"%Y-%m-%d %H:%M:%S"`" >> ${DIRHOME}/test.log
rm -r ${DIRTO}/*
exit 0
Непосредственно перед каждым запуском теста в тестовой виртуальной машине операционной системе носителя отдавалось указание принудительно записать содержимое "кеша" дисковой подсистемы на физические носители с помощью соответствующей команды:
# sync
Так-же, после каждого теста на упаковку и распаковку массы файлов вручную запускались, последовательно, тесты на скорость записи/чтения в файловую систему с помощью утилит dd и hdparm, что давало возможность подтвердить тренды основных тестов с помощью утилиты "tar":
Вначале в обычном режиме:
# dd if=/dev/zero of=/tmp/test bs=1M count=1024
Потом, по возможности минуя дисковые "кеши", с использованием "прямого доступа":
# dd if=/dev/zero of=/tmp/test bs=1M count=1024 oflag=direct
Напоследок - тест чтения:
# hdparm -Tt /dev/sda
Далее - более детально о подготовке виртуальных дисков.
В первой серии тестов использовался раздел диска (он-же - LVM-раздел). С этим всё просто - указываем KVM на него, как на виртуальный диск, не настраивая ничего.
Все дальнейшие тесты проводились на файловой системе XFS (Silicon Graphics FS), под которую был отформатирован тот-же раздел. Почему XFS? А вот нравится она мне.
Перед форматированием зачищалась начальная область используемого блочного устройства, чтобы затереть всё, что может быть воспринято как "мета"-данные, на всякий случай:
# dd if=/dev/zero of=/dev/sdaX bs=1k count=1000
Создаем файловую систему XFS:
# aptitude install xfsprogs
# mkfs.xfs -d agcount=64 -l size=32m -b size=4k /dev/sdaX
# mkfs.xfs -d agcount=64 -l size=32m -b size=4k /dev/sdaX
Где:
"-d agcount" (allocation groups) - параметр, влияющий на эффективность параллельной записи на устройство. В соответствии с рекомендациями разработчиков на каждые 4 (четыре) Гигабайта на блочном устройстве желательно иметь одну "allocation groups" (250/4~64). Если пропустить назначение этого параметра, драйвер сам будет его определять и, все хором говорят, это не лучшим образом скажется на производительности;
"-l size" - параметр, определяющий размер журнала для "метаданных". Внятных рекомендаций я не нашёл, но подумал, что для 250GB диска вполне должно хватить и 32 (тридцати двух) Мегабайт;
"-b size" - параметр, определяющий размер блока (кластера в терминологии Windows), на которые делится дисковый раздел (грубая логика: большие файлы - большие блоки, маленькие файлы - маленькие блоки) (по умолчанию: 4KB; В XFS для Linux задать размер блока более 4KB невозможно, а жаль).
"-l size" - параметр, определяющий размер журнала для "метаданных". Внятных рекомендаций я не нашёл, но подумал, что для 250GB диска вполне должно хватить и 32 (тридцати двух) Мегабайт;
"-b size" - параметр, определяющий размер блока (кластера в терминологии Windows), на которые делится дисковый раздел (грубая логика: большие файлы - большие блоки, маленькие файлы - маленькие блоки) (по умолчанию: 4KB; В XFS для Linux задать размер блока более 4KB невозможно, а жаль).
Файловая система монтировалась следующим образом, вручную:
# mkdir -p /mnt/storage
# mount -t xfs -o rw,noatime,nodiratime,nodev,nosuid,noexec /dev/sdaX /mnt/storage
# mount -t xfs -o rw,noatime,nodiratime,nodev,nosuid,noexec /dev/sdaX /mnt/storage
Пару раз, в качестве развлечения, файловая система монтировалась в режиме "синхронной" записи:
# mount -t xfs -o rw,noatime,nodiratime,nodev,nosuid,noexec,sync /dev/sdaX /mnt/storage
Естественно, результатом было снижение скорости записи, просто неприемлемое для практической работы системы виртуализации.
По подготовке файлов дисков виртуальных машин - далее.
Если обеспечение компактности виртуального диска стоит прежде обеспечения максимальной производительности дисковой подсистемы, то RAW-диск можно создать с помощью утилиты "kvm-img":
# kvm-img create -f raw /mnt/storage/test-vm.raw 100G
Следует иметь в виду, что для реальной производственной эксплуатации RAW-диск лучше создавать не с помощью утилиты "kvm-img", которая лишь расставляет точки "мета"-данных, а заполнить всё выделенное для файла виртуального диска пространство "нулями" с помощью утилиты "dd", заранее подготавливая всё виртуальное дисковое пространство к немедленному использованию:
# dd if=/dev/zero of=/mnt/storage/test-vm.raw bs=1G count=100
Это долго, да, но оно того стоит (заранее полностью подготовленный утилитой "dd" диск демонстрирует скорость доступа на 10-15% большую, нежели для диска, лишь размеченного для последующего заполнения данными утилитой "kvm-img"):
107374182400 bytes (107 GB) copied, 1437.66 s, 74.7 MB/s
Подход при подготовке виртуального диска формата QCOW2 (QEMU Copy-On-Write), предлагаемого разработчиками KVM, схож с методом подготовки RAW-дисков. Можно создать диск путём объявления наличия файла объёма, ограниченного определённым значением, начальный (для стороннего наблюдателя) размер которого будет минимален (режим по умолчанию):
# kvm-img create -f qcow2 /mnt/storage/test-vm.qcow2 100G
Виртуальный диск при этом создаётся за доли секунды, размер исходного файла крошечный, около 200KB.
Лучше создавать виртуальный диск QCOW2 с разметкой его "мета"-данными (размеченный "мета"-данными диск демонстрирует скорость доступа на 5-7% большую, нежели диск, не размеченный таким образом):
# kvm-img create -f qcow2 -o preallocation=metadata /mnt/storage/test-vm.qcow2 100G
Файл при этом создаётся соответствующего размера, в нашем случае - 100 Гигабайт.
На этом об обстоятельствах - всё.
Работа проводилась с полным соблюдением заявленных выше условий; ушло на это почти три рабочих дня. Каждый тест прогонялся по два раза, после выводилось среднее арифметическое. Все результаты подтверждались контрольными тестами с помощью утилит "dd" и "hdparm". Была мысль выложить "полотенце" таблицы с результатами, но решил ограничится графиками вариантов конфигурации, позволяющих достигнуть максимальной производительности дисковой подсистемы.
Вариант первый, с использованием в качестве виртуального дискового устройства реального дискового или LVM раздела:
Performance of the KVM disk subsystem. Partition variant.
Видно, что пиковая производительность достигается с использованием "кеша" типа "writethrough" (что предусмотрено по умолчанию). Я бы рекомендовал отключать виртуальный "кеш" вообще - стабильнее показатели скорости записи и чтения.
Вариант второй, с использованием RAW-файла, размещённого на файловой системе XFS:
Performance of the KVM disk subsystem. XFS + RAW + preallocation variant.
Видно, что пиковая производительность достигается с использованием "кеша" типа "writeback" ("кеш" файловой системы помогает). Забавно, но использование "кеша" типа "writethrough" (включаемого по умолчанию) демонстрирует просто провальные показатели скорости дисковой подсистемы (привет всем, кто пробовал KVM и разочаровался в нём по причине крайне медленной работы). Если физический дисковый контроллер достаточно серьёзный, с кешем на аккумуляторах, то из RAW-файла можно выжимать максимум, используя виртуальное "кеширование" с алгоритмом "writeback"; в противном случае рекомендую отключить вообще виртуальный "кеш", для пущей сохранности данных (вдруг системный блок отключится более неожиданно, чем обычно).
Вариант третий, с использованием QCOW2-файла, размещённого на файловой системе XFS:
Performance of the KVM disk subsystem. XFS + QCOW2 + preallocation variant.
Видно, что картина в общем повторяет вариант с XFS+RAW, только показатели ниже на 20-25%. Ну, что-же - формат удобный более для лабораторных условий, когда виртуальными машинами нужно постоянно вертеть-крутить, нежели для эксплуатации в производственных условиях, требующих максимальной отдачи в неизменном окружении.
Естественно, что усреднённая скорость обработки массива файлов разного размера существенно ниже пиковых возможностей потоковой записи виртуального или физического дискового устройства. В частности, максимальные достигнутые усреднённые значения скорости записи утилитой "tar" на виртуальный диск не превысили 30 (тридцати) Мегабайт в секунду, в то время как утилита "dd" демонстрировала скорость небуферизированой записи в 78 (семьдесят восемь) Мегабайт в секунду.
4 марта 2013 в 23:54
18 апреля 2013 в 01:45