UMGUM.COM 

KVM + disk IO ( Тесты производительности дисковой подсистемы KVM. )

2 марта 2012  (обновлено 31 января 2015)

OS: Debian Linux Squeeze 6.0.4 (amd64).
Application: KVM 0.12.5 (Kernel-based Virtual Machine).

Задача: выбор типа виртуального диска KVM и параметров конфигурации, создающих наименьшее сопротивление трафику ввода/вывода.

Методика:

Выбор типа носителя виртуального диска;
Выбор типа разметки носителя виртуального диска;
Разметка раздела, выделенного под тесты, форматирование его, если в этом есть необходимость;
Выбор типа виртуального диска;
Выбор типа разметки виртуального диска;
Установка на виртуальный диск операционной системы (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;


Прежде чем заниматься непосредственно тестированием, подготовим операционную систему носитель к обеспечению достаточно неизменной производительности; в частности, с помощью "cpufrequtils" устанавливаем для всех ядер центрального процессора режим выдачи максимальной частоты (по умолчанию выбран режим адаптивной подстройки частоты центрального процессора в зависимости от нагрузки, вносящий существенные погрешности в результаты любых тестов).

# aptitude install cpufrequtils
# 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.
....

Видно, что ядра процессора готовы переключатся между частотой в 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"
....

# /etc/init.d/cpufrequtils restart

Заранее, не тратя время на автоматизацию процесса, вручную создаём тестовый виртуальный сетевой интерфейс и подключаем его к виртуальному системному "мосту" (можно этого и не делать, обходясь поддержкой встроенного в KVM NAT, но мне хотелось простого прямого доступа к тестируемым машинам):

# tunctl -b -t tap0
# ifconfig tap0 0.0.0.0 up
# brctl addif br0 tap0

Теперь пишем скрипт, с помощью которого будем формировать строку запуска виртуальной машины:

# touch ~/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

Вначале мы запускаем скрипт для установки системы в виртуальную машину, применяя к переменной "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.

После инсталляции тестовой операционной системы на неё загружалась масса файлов, время дальнейшей обработки которых и давало возможность оценить производительность дисковой подсистемы. На стороне тестовой системы создавался скрипт, запускающий на исполнение тесты с фиксированием времени, затраченного на исполнение:

# touch ~/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

Непосредственно перед каждым запуском теста в тестовой виртуальной машине операционной системе носителя отдавалось указание принудительно записать содержимое "кеша" дисковой подсистемы на физические носители с помощью соответствующей команды:

# 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

Где:

"-d agcount" (allocation groups) - параметр, влияющий на эффективность параллельной записи на устройство. В соответствии с рекомендациями разработчиков на каждые 4 (четыре) Гигабайта на блочном устройстве желательно иметь одну "allocation groups" (250/4~64). Если пропустить назначение этого параметра, драйвер сам будет его определять и, все хором говорят, это не лучшим образом скажется на производительности;
"-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,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 раздела:

размер: 320 400 640 800 1024 1280
Performance of the KVM disk subsystem. Partition variant.
Performance of the KVM disk subsystem. Partition variant.

Видно, что пиковая производительность достигается с использованием "кеша" типа "writethrough" (что предусмотрено по умолчанию). Я бы рекомендовал отключать виртуальный "кеш" вообще - стабильнее показатели скорости записи и чтения.

Вариант второй, с использованием RAW-файла, размещённого на файловой системе XFS:

Performance of the KVM disk subsystem. XFS + RAW + preallocation variant.
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.
Performance of the KVM disk subsystem. XFS + QCOW2 + preallocation variant.

Видно, что картина в общем повторяет вариант с XFS+RAW, только показатели ниже на 20-25%. Ну, что-же - формат удобный более для лабораторных условий, когда виртуальными машинами нужно постоянно вертеть-крутить, нежели для эксплуатации в производственных условиях, требующих максимальной отдачи в неизменном окружении.

Естественно, что усреднённая скорость обработки массива файлов разного размера существенно ниже пиковых возможностей потоковой записи виртуального или физического дискового устройства. В частности, максимальные достигнутые усреднённые значения скорости записи утилитой "tar" на виртуальный диск не превысили 30 (тридцати) Мегабайт в секунду, в то время как утилита "dd" демонстрировала скорость небуферизированой записи в 78 (семьдесят восемь) Мегабайт в секунду.


Заметки и комментарии к публикации:


Оставьте свой комментарий ( выразите мнение относительно публикации, поделитесь дополнительными сведениями или укажите на ошибку )