Динамическая память в Hyper-V R2 Service Pack 1 - Теория

За последние несколько месяцев я несколько раз начинал писать статью про динамическую память, которая приходит в Hyper-V R2 с Windows Server 2008 R2 Service Pack 1, - и столько же раз откладывал написание статьи. Писать многотомные мемуары, переводя известные статьи главы подразделения виртуализации Microsoft нет никакого желания, - там больно много маркетинга; а реального материала для написания статьи мне не хватало. Сейчас, в разгар TAP программы, с внедрением предварительной версии Service Pack 1 у ключевых заказчиков, у меня появляются материалы. Я решил написать две заметки – теоретическую об архитектуре динамической памяти, поддерживаемых платформах, типичных настойках, использовании динамической памяти, приоритетах и связи с физической памятью, изобилующую глубокой теорией организации памяти в Windows; и более практическую, рассказывающую о настройках динамической памяти через Virtual Machine Manager. Начнем..

Что же такое – динамическая память? Очевидно, это есть некий механизм, который при необходимости увеличивает или уменьшает объём памяти, доступной виртуальным машинам. Как это происходит?

  • Динамически увеличивает или уменьшает объём памяти, предоставленной виртуальной машине
    • Использует технологии горячего добавления (hot add) для предоставления дополнительной памяти ВМ
    • Использует технологии «воздушного шарика» (memory ballooning) для отбирания лишней памяти у ВМ
  • Предоставляет виртуальной машине объём памяти, который та требует + некий буфер
  • Позволяет приоритетами определять, какая ВМ получит память при её недостатке

С точки зрения архитектуры Hyper-V это выглядит следующим образом:

Dynamic Memory VSC (Virtual Service Consumer) – компонента в виртуальной машине, которая

  • Устанавливается вместе с компонентами интеграции, но по умолчанию не активна до тех пор, пока динамическая память для данной машины не будет настроена в свойствах ВМ
  • Добавляет и забирает память у виртуальной машины по необходимости
  • Отслеживает использование памяти виртуальной машиной и передаёт эту информацию в Dynamic Memory VSP

Dynamic Memory VSP (Virtual Service Provider) – компонента на хосте виртуализации, которая

  • Получает информацию об использовании памяти всеми виртуальными машинами от их VSC и направляет консолидированную информацию в балансировщик памяти (Memory Balancer)

Memory Balancer – компонента на хосте виртуализации, которая

  • Следит за использованием памяти самим хостом и виртуальными машинами
  • При необходимости изменений сначала требует у VSP забрать неиспользуемую память у виртуальных машин
  • Когда на хосте появится достаточное количество свободной памяти, инициирует через VSP предоставление дополнительной памяти тем виртуальным машинам, которым она требуется

Каким образом виртуальной машине предоставляется дополнительная память?

  • Используется вариацию технологии Hot Add в виртуальной машине
  • Технология Hot Add использует ACPI триггеры, генерирующие события Plug and Play
  • Динамическая память использует вариацию Hot Add Enlightenment, которая:
    • Работает в обход стандартного драйвера памяти в гостевой системе
    • Напрямую сообщает менеджеру памяти (Memory manager) о появившейся дополнительной памяти через специальный API
  • Данный API портирован на Windows Server Standard и Web, не имеющих возможностей Hot Add
    • Только для виртуальных машин
    • Начиная с версии Release Candidate (в Beta версии поддержки динамической памяти для Standard/Web Server не было)

Каким образом у виртуальной машины забирается память?

Используется метод «воздушного шарика» – в гостевой ОС специальный драйвер начинает потреблять выделенную память, занимая её, чтобы ОС в ВМ не могла к ней обратиться, а по сути, отдавая занятую память гипервизору для других виртуальных машин. Гостевая ОС продолжает считать, что у неё «много» памяти, просто она занята неким процессом и помечена как «driver locked». При последующих добавлениях памяти к этой виртуальной машине память будет добавляться в адресное пространство этого процесса – и высвобождаться им для нужд ОС.

Чтобы понять, как гипервизор понимает, каким виртуальным машинам в настоящее время требуется дополнительная память, а у кого её можно забрать нам потребуется ввести термин загрузка памяти виртуальной машины (Guest Memory Pressure) , в процентах отражающий текущую ситуацию с памятью виртуальной машины – отношения объёма памяти, которую процессы используют в настоящее время к объёму физической памяти, выданной данной машине. Увы, на словах это довольно сложно объяснить, посему я расскажу вам об архитектуре использования памяти в Windows.Поговорим о том, как вообще используется память. Ведь даже без всякой виртуализации мы разделяем физическую память «physical memory» и виртуальную память «virtual memory». Любые приложения и даже ядро ОС работают именно с виртуальной памятью. Как это выглядит?

  • Процессы не адресуют физическую память напрямую
  • Физические страницы памяти представлены процессам в режиме –ядра и –пользователя (kernel-mode processes и user-mode processes) через виртуальное пространство адресов
  • Виртуальное адресное пространство зависит от оборудования и версии ОС (от архитектуры процессора и разрядности исполняемой ОС)
  • Связь между физической и виртуальной памятью довольно абстрактна. Количество виртуальной памяти может существенно превышать объём физической памяти

32-битные версии ОС адресуют только 4ГБ памяти. По умолчанию, память делится пополам между процессами режима ядра и пользователя. Однако это поведение может быть изменено ключами /3GB и UserVA, которые позволяют выделить больше памяти процессам в режиме пользователя.

64-битные версии ОС в теории могут адресовать до 16ЭБ памяти. На деле, текущие 64-бит реализации Windows адресуют до 16ТБ памяти, но как мы знаем, с установкой роли Hyper-V ОС Windows может использовать лишь 1ТБ памяти. Также как и в предыдущем случае, этот виртуальный 1ТБ делится поровну между режимами ядра и пользователя, с возможностью повлиять на этот процесс через BCDEdit.

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

Поговорим о терминологии, используемой в Windows, при описании памяти:

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

Гарантированная (Committed) память – память, выделенная под процесс из физической памяти – оперативной или дисковой (файл подкачки или другие временные файлы памяти).

Свободная (Free) память – память адресного пространства, не используемая процессами.

Предел гарантированной памяти (System Commit Limit) – максимальный объём памяти, которую система может гарантировать процессам. Равен размеру оперативной памяти + файлов подкачки.

Текущее гарантированное значение (Current System Commit Charge) – суммарное количество памяти, гарантированной в настоящий момент процессам.

Пустые страницы (Zeroed Pages) – обнулённые страницы памяти готовые к использованию процессами.

Свободные страницы (Free Pages) – неиспользуемые страницы памяти, которые еще не обнулены, и потому не могут ещё быть переданы другим процессам.

Изменённые страницы (Modified Pages) – страницы, которые уже некоторое время не использовались процессом, но содержат некие изменения, которые необходимо записать на диск перед высвобождением страниц.

Ожидающие страницы (Standby Pages) – страницы памяти, уже записанные на диск, но ещё не высвобожденные. Они могут быть отданы оригинальному процессу, если он к ним обратится, но также могут быть очищены и отданы другому процессу при необходимости.

Рабочее множество процесса (Working Set) – объём гарантированной процессу памяти, находящийся в настоящее время в оперативной памяти.

Активная (Active) память – объём памяти, используемый во всех текущих рабочих множествах.

Итак, возвращаемся к динамической памяти и тому, как же Hyper-V понимает, кому в данный момент память действительно требуется.

Загрузка памяти виртуальной машины (Guest Memory Pressure)

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

Посмотрим на реальном примере:

Моей виртуальной машине в настоящее время гипервизором выделено 798 МБ (на самом деле 798264 Килобайт) памяти. При этом сейчас данная система и её процессы используют 534 МБ (534780КБ) реальной оперативной памяти.

Отношение этих двух значений даёт мне процентный показатель загрузки памяти в виртуальной машине:

При этом 33% памяти в настоящий момент свободны и образуют так называемый свободный буфер (free buffer) .

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

Как же гипервизор принимает решения о необходимости увеличения или уменьшения объёма памяти? Введём понятие шкалы загрузки (pressure band) . В каждой виртуальной машине постоянно считается значение загрузки памяти. Для каждой виртуальной машины гипервизор отслеживает изменения этого параметра. И для каждой виртуальной машины, на основе её исторических показателей, формирует так называемую шкалу загрузки. При этом за некие минимальный и максимальный индикаторы шкалы берёт значения из истории использования данной конкретной виртуальной машины:

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

Какие параметры влияют на процесс распределения памяти? Балансировщик выделяет или забирает память исходя из следующих параметров:

  • Начальное (startup) и максимальное (maximum) значения памяти для виртуальной машины. Начальное вы выставляете таким, чтобы ОС смогла с ним загрузиться. Максимальное выставляете любым, - возможно даже большим, чем объём доступной серверу памяти
  • Значение приоритета виртуальной машины по памяти – об этом мы ещё поговорим
  • Параметра свободного буфера виртуальной машины – задаваемого вами значения, индицирующего, какой процент реальной памяти, предоставленной данной виртуальной машине, должен держаться свободным. Об этом мы также еще поговорим

Как работает свободный буфер?

Каждая виртуальная машина в некий момент времени имеет некий объём реальной памяти. Часть этой памяти – индицируемый термином загрузки памяти используется процессами. Это мы уже рассматривали. Остальная память (100% - загрузка памяти% ) как раз и называется свободным буфером. Некое процентное отношение от выделенной памяти, которое вы хотите оставить в данной виртуальной машине свободным, чтобы она в любой момент времени могла начать использовать реальную память.

Объём памяти в любой момент состоит из занятой памяти (её процент характеризуется значением загрузки памяти) и буфером.

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

Чтобы понять это на реальном примере, рассмотрим ситуацию:

Моя виртуальная машина сконфигурирована с начальным значением памяти в 512МБ и максимальным в 64ГБ. Значение в процентах свободного буфера я установил равным 25%. То есть я предполагаю, что четверть всей памяти, выделенной виртуальной машине, не будет использоваться активными процессами, а будет резервом для будущего использования. Очевидно, что как только она начнет использоваться, процентное значение свободного буфера упадет ниже требуемых 25% и балансировщик начнёт добавлять память виртуальной машине.

Предположим, что в некий момент времени моя виртуальная машина получила 673 МБ, а реально потребляет 515МБ:

Согласно формуле, озвученной выше, размер буфера свободной памяти должен вычисляться по формуле:

Тогда объём памяти, который балансировщик должен предоставить виртуальной машине целевой памяти в объёме:

Так как в данный момент памяти машина имеет меньше, и свободный буфер составляет менее требуемых 25%, балансировщик начинает процесс добавления памяти:

Поговорим о настройке приоритетов для динамической памяти

Очевидно, что не всегда количество физической памяти на сервере будет достаточным, чтобы покрыть аппетиты виртуальных машин. Когда запрашиваться у балансировщика будет больше чем он может предоставить, он начнёт кому-то отказывать. Кому именно, и в какой мере – зависит от приоритета в настройках динамической памяти каждой виртуальной машины.

Разницу между объёмом целевой памяти (сколько виртуальная машина хотела бы получить от балансировщика при наличии неограниченного объёма свободной памяти) и реально выданной памятью называется штрафом. Логично предположить, что чем выше приоритет, тем меньше штраф. То есть для виртуальных машин с высоким приоритетом динамической памяти, балансировщик будет пытаться выделить максимальный объём и достичь целевого значения. Для виртуальных машин с меньшим приоритетом буфер свободной памяти может быть существенно меньше запрашиваемого, так что значение штрафа будет высоким.

Резерв памяти для родительского раздела

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

Значение MemoryReserve в ветви реестра HKLM\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Virtualization позволяет настроить данный резерв.

Изменение данного значения потребует перезагрузки узла.

Файл подкачки в виртуальных машинах

Включение динамической памяти для виртуальной машины делает необходимым использование её файла подкачки (pagefile). Ведь в случае нехватки реальной памяти на узле и требовании балансировщика отобрать память у вашей виртуальной машины, она начнёт активно писать свою память в файл подкачки, чтобы отдать требуемый кусок памяти балансировщику.

Каким объёмом задать файл подкачки, – тема для отдельного исследования. Я для себя уже наметил некоторую формулу, которой готов поделиться по почте (в комментариях отвечать не буду). Очевидно, что стандартные значения, предлагаемые вам операционной системой вполне достаточны. Однако если вы выставляете максимальным значением памяти стандартные 64ГБ, то рискуете получить файл подкачки аналогичного размера. Если вас тема затронула, и вы имеете свои соображения, пишите, обсудим.

Хочу подвести некий итог. Service Pack 1 для Windows Server 2008 R2 и Hyper-V Server R2 принёс два крупных нововведения. Поддержку динамической памяти и поддержку полноценного видео и USB устройств в виртуальных машинах через RemoteFX. Мы рассмотрели обе технологии, а в ближайшем будущем я расскажу о том, как данными нововведениями можно управлять при помощи System Center Virtual Machine Manager, который также получит долгожданный пакет обновлений вскоре после самой ОС.