Те, кто уже настраивает VMware Memory Tiering или только присматривается к этой технологии, наверняка задавались вопросом: что происходит с большими страницами памяти (Memory Large Pages)? Вопрос действительно важный, поскольку ответ на него влияет на планирование ёмкости и настройку виртуальных машин. Разберём эту тему подробно.
Немного контекста
Прежде чем переходить к особенностям поведения при многоуровневом хранении памяти, стоит кратко вспомнить, что такое большие страницы (Large Pages) и почему они важны. Архитектура x86 поддерживает три размера страниц: 4 КБ (малые страницы), 2 МБ и 1 ГБ. Два последних размера в совокупности называют «большими страницами». Размер страницы можно сравнить с номиналом купюр в кошельке: крупные купюры удобнее носить с собой, но с них сложнее давать сдачу. Большие страницы работают так же: они снижают нагрузку на TLB (Translation Lookaside Buffer) и уменьшают стоимость обхода таблиц страниц, что даёт потенциальный прирост производительности для нагрузок, интенсивно работающих с памятью. По умолчанию ESX использует страницы размером 2 МБ для виртуальной оперативной памяти гостевых систем, и не случайно: выигрыш в производительности хорошо подтверждён.
Поэтому логично было бы предположить, что при включении Memory Tiering большие страницы остаются активными. Но именно здесь начинается самое интересное.
Memory Tiering меняет правила игры
При включении Memory Tiering на хосте виртуальные машины по умолчанию настраиваются так, что большие страницы исключены из механизма тиринга. На первый взгляд это выглядит нелогично, но на самом деле такое решение вполне обоснованно.
Алгоритм тиринга, встроенный в уровень управления памятью ESX, отслеживает «горячесть» и «холодность» каждой страницы. Активные страницы — рабочий набор виртуальной машины — остаются в Tier 0 (DRAM) для максимальной производительности. Холодные страницы при росте давления на память мигрируют в Tier 1 (NVMe). Всё это происходит интеллектуально, автоматически и не требует ручного вмешательства. Но есть нюанс: для качественной работы алгоритму необходим детальный контроль на уровне мелких блоков.
Как это влияет на большие страницы? Большая страница размером 2 МБ является атомарной единицей — переместить её половину на NVMe невозможно. Весь блок в 2 МБ перемещается целиком либо не перемещается вовсе. Это как пытаться точно регулировать температуру термостатом, который меняет её только с шагом в 10 градусов: работать будет, но без точности. При гранулярности 4 КБ движок тиринга способен принимать хирургически точные решения о том, какие именно страницы горячие, а какие холодные. Именно эта точность обеспечивает высокую эффективность Memory Tiering, поэтому по умолчанию используются малые страницы.
Три сценария размеров страниц
Сравним три размера страниц памяти и их поведение при работе Memory Tiering. Когда все варианты разложены по полочкам, понять их достаточно просто. Вот как ведёт себя каждый размер страницы.
Малые страницы 4 КБ: полная оптимизация
Это оптимальный вариант. Производительность специально оптимизирована для страниц 4 КБ при активном Memory Tiering. Алгоритм тиринга работает с максимальной точностью: горячие страницы остаются в DRAM, а холодные плавно выгружаются на NVMe. ESX намеренно отключает большие страницы на уровне хоста, когда настроен Memory Tiering. Чтобы точно отслеживать и перемещать память без огромных накладных расходов на производительность, ESX возвращается к использованию стандартных базовых страниц 4 КБ для гостевой памяти. Работая на уровне 4 КБ с самого начала, движок тиринга ESX избавлен от необходимости постоянно разбивать крупные страницы, чтобы выяснить, какие данные реально используются.
Большие страницы 2 МБ: включение вручную, с оговоркой
Стандартная конфигурация vSphere предполагает включённые большие страницы 2 МБ (параметр Mem.AllocGuestLargePage установлен в 1), однако при активном Memory Tiering страницы 2 МБ по умолчанию не участвуют в тиринге.
Страница 2 МБ состоит из 512 отдельных страниц по 4 КБ. Допустим, 400 из них горячие и активно используются. В идеале такая большая страница должна целиком остаться в DRAM. Но это означает, что оставшиеся 112 холодных страниц тоже застревают в DRAM, хотя могли бы быть выгружены на NVMe. Эти 112 страниц представляют собой заблокированную ёмкость — и это лишь одна большая страница. Умножьте это на любое количество, и станет ясно, что тысячи холодных страниц могут остаться в DRAM вместо выгрузки на NVMe. При гранулярности 4 КБ движок тиринга освободил бы их, а при гранулярности 2 МБ — не может, поскольку перемещение половины большой страницы невозможно.
Чтобы использовать большие страницы 2 МБ вместе с Memory Tiering, необходимо явно задать VMX-параметр виртуальной машины: monitor_control.disable_mmu_largepages = "FALSE". После установки параметра машина попадает в общий пул многоуровневой памяти, и здесь начинается самое любопытное. Когда большие страницы включены, алгоритм тиринга проактивно разбивает часть больших страниц на основе определённых эвристик и либо выгружает холодные страницы из 2-мегабайтного региона, либо собирает его обратно в большую страницу.
В этом и заключается ключевое противоречие: большие страницы и тиринг тянут в противоположные стороны. Тиринг наиболее эффективен, когда может освобождать память с максимально мелкой гранулярностью, то есть 4 КБ. Большие страницы сознательно снижают эту гранулярность ради эффективности TLB. Эти два механизма фундаментально противоречат друг другу, и этот компромисс важно понимать до того, как включать большие страницы.
Страницы 1 ГБ: только DRAM, без исключений
Здесь действует жёсткое правило. Виртуальные машины, настроенные на использование страниц 1 ГБ, автоматически закрепляются за Tier 0 (DRAM) и никогда не будут использовать ёмкость NVMe Tier 1. Memory Tiering применяет это ограничение автоматически, поэтому никакой специальной настройки не требуется. Однако это необходимо учитывать при планировании ёмкости: такие машины следует рассчитывать исходя из доступного объёма DRAM, а не из общей ёмкости многоуровневой памяти. Их стоит выявить заранее.
Аспект TPS
Есть и вторичный эффект, который стоит понимать, особенно если для экономии памяти используется механизм Transparent Page Sharing (TPS). Как включение больших страниц в среде с тирингом влияет на TPS? Как выясняется, плохо.
TPS не дедуплицирует большие страницы напрямую. На современном оборудовании с Intel EPT или AMD RVI, использующем страницы 2 МБ, TPS и так малоэффективен: вероятность найти два идентичных региона по 2 МБ крайне низка, а их сравнение несёт существенные накладные расходы. Прежде чем TPS сможет дедуплицировать большие страницы, их нужно разбить на малые страницы 4 КБ, а это происходит только при определённых состояниях давления на память.
На практике это означает, что включение больших страниц в среде с тирингом снижает как эффективность алгоритма тиринга, так и экономию от TPS, на которую можно было рассчитывать. Эти две техники движутся в противоположных направлениях в вопросе размера страниц. Поэтому для нагрузок вроде VDI или сред с высокой плотностью виртуальных машин, где TPS исторически приносил пользу, стоит взвесить, готовы ли вы пожертвовать этой экономией.
Итог
Memory Tiering идёт на осознанный компромисс: жертвует эффективностью TLB, которую дают большие страницы, в обмен на операционную точность, необходимую для интеллектуального размещения данных по уровням. Для большинства нагрузок этот обмен оправдан, тем более что задержки NVMe в Tier 1 продолжают снижаться.
Вот как подходить к планированию среды с многоуровневой памятью:
Используйте страницы 4 КБ по умолчанию для виртуальных машин, которые должны получать выгоду от тиринга.
Выявляйте машины со страницами 1 ГБ на раннем этапе планирования ёмкости — они потребляют только DRAM.
Тщательно оценивайте машины с большими страницами 2 МБ: сначала тестируйте и не рассчитывайте на те же характеристики производительности, что в среде без тиринга.
Проработка вопроса больших страниц до включения Memory Tiering избавит от многих сложностей в будущем. При этом беспокоиться не о чем: как только правила понятны, система обрабатывает большую часть этих ситуаций автоматически.