Динамическое выделение памяти для виртуальных машин

Данная небольшая заметка посвящена использованию virtio balloon драйвера для "горячего" изменения количества оперативной памяти в гостевых системах. Технология появилась достаточно давно, и использовать её довольно просто, но при этом возникает множество интересных вопросов.

Как это использовать?

Использование balloon драйвера - один из основных способов динамического изменения количества оперативной памяти, выделенной виртуальной машине. Необходимо отметить, рассматриваемый механизм не является аналогом memory hot plug, и требует поддержки со стороны ядра операционной системы; для этого для Linux и Windows систем разработаны соответсвующие драйверы. В подавляющем большинстве дистрибутивов Linux поддержка virtio-balloon включена по умолчанию. Скачивание и установка virtio balloon драйверов для Windows описано тут

Для включения ballooning необходимо запускать qemu с опцией -balloon virtio.

$ qemu-kvm -m 2500 -balloon virtio -drive file=test_fedora.img ...

Узнать количетво памяти, выделенное для вирт машины можно при помощи команды info balloon в консоли qemu monitor

(qemu) info balloon 
balloon: actual=2500
(qemu)

В гостевой системе (Linux) можно воспользоваться командой free для получения информации об использовании оперативной памяти

[root@guest ~]# free -m 
total used free shared buffers cached
Mem: 2453 169 2283 0 14 52
-/+ buffers/cache: 102 2350
Swap: 1023 0 1023
[root@test ~]#

Для изменения количества оперативной памяти используется команда balloon <размер памяти в Мб>

(qemu) balloon 1000
(qemu) info balloon
balloon: actual=1000
(qemu)

В гостевой системе

[root@guest ~]# free -m
total used free shared buffers cached
Mem: 953 169 783 0 14 52
-/+ buffers/cache: 102 850
Swap: 1023 0 1023
[root@test ~]#

Аналогичным образом можно и увеличить размер памяти, но не превышая того предела, который установлен при запуске (параметр -m)

Для Windows систем процесс полностью аналогичен

 

 

 

 

 

 

 

 

 

 

 

 

 

После урезания памяти

 

 

 

 

 

 

 

 

 

 

 

 

 

 

Как это работает?

Balloon драйвер создает в ядре специальный процесс, который по команде с хоста может изменять количество потребляемой им памяти. Оставшаяся память может быть использована всеми остальными процессами в гостевой системе для собственных нужд.

Если необходимо уменьшить количество памяти выделяемое машине, то сначала balloon процесс "раздувается" до необходимого размера, а потом позволяет хосту освободить нужное количество памяти

Увеличение количества памяти происходит аналогичным образом.

При таком методе работы количество памяти, используемое вирт машиной, ограничивается общим количеством памяти указанным в параметре -m.

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

Поэтому для эффективного использования balloon драйвера необходимо каким-то образом получать информацию об реальном использовании памяти в гостевой системе и на основе полученных данных принимать решение об ограничениях. Подобный механизм разрабатывается в настоящий момент. Адам Литке (Adam Litke) Разработал серию патчей для qemu и balloon драйвера, которые позволяют получать дополнительную информацию об использовании памяти. (Делается это при помощи команды info balloon в qemu мониторе.) Последние версии libvirt уже содержат код, который парсит обновленный вывод команды info balloon для получения информации об оперативной памяти гостевой системы. Но по словам Адама пока что эти патчи содержат некоторые проблемы связанные с взаимодействием с qemu, и в настоящее время идет активная работа по их доработке.

Но уже сейчас есть несколько способов получения информации от гостевой системы. Например, можно передавать данные об использовании памяти по сети (разумеется в этом случае сеть должна быть настроена в виртуальной машине). Такой способ используется в проекте MoM. Далее я опишу немного другой способ связи между хост системой и виртуальной машиной, при помощи которого мы сможем управлять balloon драйвером более эффективно.

Получение информации от гостевой системы.

Для передачи информации из гостевой системы на хост можно воспользоваться virtio-serial механизмом. Подробней про него можно прочитать тут и тут. Для совсем тестового примера работы с памятью воспользуемся каналом (pipe) между гостем и хостом. Связь схематично показана на рисунке ниже.

Для создания подобного virtio интерфейса необходимо создать два fifo файла и прописать необходимые параметры qemu

[root@host ~]# mkfifo mon.in 
[root@host ~]# mkfifo mon.out
[root@host ~]# mkfifo mem_pipe.in
[root@host ~]# mkfifo mem_pipe.out
[root@host ~]# qemu-kvm -m 3000 -balloon virtio -monitor pipe:mon \
-device virtio-serial \
-chardev pipe,path=mem_pipe,id=our_pipe,nowait \
-device virtserialport,chardev=our_pipe,name=mem \
-drive file=/dev/vg_virt/test_fedora,if=virtio,boot=on

Теперь qemu monitor доступен через файлы mon.in и mon_out, файлы mem_pipe.in и mem_pipe.out служат для сообщений с гостевой системой через созданный канал. На гостевой системе при этом создается устройство /dev/virtio-ports/mem, служащее для приема и передачи сообщений к хост системе.

Чтобы получать информацию о потреблении памяти виртуальной машины в гостевой системе будет работать следующий простейший скрипт (возможности которого можно неограничено расширять)

#!/bin/sh

MEM_PIPE=/dev/virtio-ports/mem

if [ "x$1" != "x--" ]; then
$0 -- 1> /dev/null 2> /dev/null &
exit 0
fi

while read LINE < $MEM_PIPE
do
if [ $LINE == "mem" ]; then
free -m| grep "Mem" | awk '{print $4}' > $MEM_PIPE
fi
done

Скрипт выполняет простейшую задачу - при приеме сообщения mem, он отсылает хост системе количество свободной памяти (с учетом "условно свободных" кешей). Простестируем работу скрипта

[root@host ~]# echo mem > mem_pipe.in
[root@host ~]# cat mem_pipe.out
100

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

#!/bin/sh

MPIPE_IN=mem_pipe.in
MPIPE_OUT=mem_pipe.out

MONITOR=mon.out
MEM=2000

while true
do
echo mem > $MPIPE_IN # Send request to guest
read FREE_MEM < $MPIPE_OUT # Receive amount of used memory
sync

# Some logic about $BALLOON_MEM
if [ $FREE_MEM -gt 30 ]; then
let MEM=$MEM-31
fi

if [ $FREE_MEM -lt 10]; then
let MEM=$MEM+18
fi

echo balloon $MEM > $MONITOR # Set new balloon value
sleep 1
done

Разумеется в реальных задачах логика управления памятью должна опираться на более подробные данные анализа, включая в себя оценки роста потребления памяти и прогнозы дальнейшего использования, но включение этих возможностей принципиально осуществимо уже с имеющимися механизмами. Надо отметить, что доработка патчей для balloon драйвера позволит получать данные о потреблении памяти не из гостевой системы, а напрямую из qemu monitor.

854

Комментарии

Исправил некоторые ошибки в командах. Замечания и вопросы приветствуются.