VMware cores per socket и vCPU какой алгоритм верный?
Всем привет, возник вопрос как правильнее распределять ресурсы при создании виртуальной машины и чем руководствоваться. В статьях пишут о том, что количество ядер VM не должно превышать количества ядер на хосте, но при этом на тестовом стенде получается следующее: стенд 4 ядра с 8 потоками
1 случай: CPU 8; Cores per Socket 2; получаем 2 процессора по 4 ядра Bench CPU 4.8
2 случай: CPU 8; Cores per Socket 8; получаем 1 процессор по 8 ядер Bench CPU 5.05
3 случай: CPU 4; Cores per Socket 4; получаем 1 процессор по 4 ядра Bench CPU 3.79
Чем чревато превышение логических ядер над физическими или в логике VMWare Logical processors (в моем случае 8) это и есть кол-во логических ядер которое мы распределяем?
Каждому по потребностям: как мы решали задачу с «нарезкой» vCPU
Всем привет! Возникал ли у вас вопрос, как можно ограничить виртуальную машину по используемым CPU?
У нас в Selectel он возник, когда мы хотели сделать облачную платформу гибче и удешевить инфраструктуру для клиентов. В результате получилась линейка виртуальных машин Shared Line. Это облачные серверы с гарантированной долей производительности ядра — их арендуют те, кому не нужна полная загрузка CPU.
Под катом расскажу, как мы учились «резать» мощности облачных серверов на кусочки.
Зачем нужно управление производительностью виртуальных машин
Можно выделить пару сценариев, где будет полезно управлять производительностью виртуалок:
1. Хотим ограничивать доступный объем ресурсов.
Подобное требование может возникнуть, когда необходимо быть уверенным, что виртуальная машина не потребует весь доступный ресурс по CPU и оперативной памяти. В таком случае мы говорим о жестком ограничении на используемые ресурсы.
2. Хотим приоритизировать процессы.
С приоритизацией все интереснее, так как здесь мы не ограничиваем виртуальную машину напрямую, а лишь устанавливаем ее приоритет в очереди на использование ресурсов.
Зачем это пользователям
Представим человека, который хочет развернуть виртуальную машину и разместить там pet-проект. Если проект будет крутиться на домашнем компьютере (все же дома используют Linux, да?), то может не хватить ресурсов на другой pet-проект, браузер или катку в Dota. А если разворачивать такой проект в облаке, то под него пришлось бы брать целый процессор.
Если на начальном этапе больших нагрузок не предвидится, даже минимальная конфигурация «виртуалки» может быть избыточна — будем платить за простаивающие ресурсы. И тут как раз пригодилась бы возможность создать виртуальную машину с определенной долей ядра.
А организациям пригодится?
Рассмотрим сферическую компанию в вакууме. Допустим, она содержит свою или арендует облачную инфраструктуру у провайдера. На виртуальных машинах развернуто суперважное ПО — например, Jira и Confluence, а также ряд сервисов поменьше — какой-нибудь телеграм-бот для напоминаний. Возможно, есть еще ряд экспериментальных служб и приложений — отдельные сотрудники сделали себе удобные инструменты.
Для надежности каждое приложение или сервис запущено на своей виртуальной машине. Со временем сервисов будет становиться все больше. Какие-то из них станут тяжелее. Часть хостов нужно будет выключать на обслуживание и, рано или поздно, наступит момент, когда ресурсы в инфраструктуре закончатся. Проблема.
Ответ тем, кто умеет в микросервисы и Kubernetes
Даже оркестрация контейнеров и подобные фокусы все равно не гарантируют полной утилизации мощностей.
Самое очевидное, что можно сделать — докупить мощностей если вам не перестали продавать. Это рабочее решение, но не все могут его себе позволить.
Если не докупать, то придется оптимизировать использование ресурсов. Здесь как раз пригодится ограничение виртуальных машин по производительности.
Нетребовательные или редко используемые сервисы можно перевезти на виртуалки с ограничением по CPU и памяти без ухудшения качества работы. Важным сервисам, в свою очередь, можно повысить приоритет, чтобы у них всегда было достаточное количество ресурсов.
И вот мы уже сэкономили на аренде новых серверов, более мудро распределив существующие ресурсы. При этом качество работы сервисов не снизилось, даже еще место освободилось. Win!
А провайдерам инфраструктуры это зачем?
Если обуться в ботиночки облачного провайдера (допустим, Selectel), появится еще несколько причин управлять производительностью виртуальных машин.
Более плотная утилизация ресурсов
Не секрет, что виртуальные машины создаются на специальных «железных» хостах облачного провайдера. В них много памяти и ядер. Иногда возникают ситуации, когда на хосте есть свободные ресурсы, но их столько, что адекватная конфигурация для еще одного виртуального сервера не помещается. То есть вроде бы и в железе есть ресурс, но ни одна конфигурация в него не лезет по параметрам (память, ядра).
В итоге эти «остатки» просто не используются.
Чтобы избежать такой ситуации, провайдеру приходится играть в тетрис (нет, правда). Перекладывать виртуальные машины с хоста на хост, чтобы более плотно упаковать их. Это очень затратный процесс.
Возможность создавать более дешевую инфраструктуру в облаке
Если будет возможность управлять производительностью виртуальных машин, то можно будет оптимизировать стоимость виртуалок. Так, например, в линейке Shared Line можно арендовать 10% мощности сервера с 1 CPU, 512 МБ RAM и сетевым диском на 5 ГБ за 193,60 ₽/мес. При правильных подсчетах можно сэкономить на запуск еще одного проекта.
Итак, зачем это все, мы немного определились. Теперь рассмотрим, какие существуют инструменты и способы ограничения виртуальных машин по использованию ресурсов.
Способы ограничения ВМ по использованию CPU
Сразу оговоримся, что речь в основном пойдет о способах управления производительностью в ОС Linux. Почему так? В лучших традициях ответим мемом:
При разработке линейки Shared Line у нас не было готового ответа, какой именно инструмент использовать. Перед реализацией проводили исследование существующих способов. По понятным причинам в основном искали опенсорсные решения.
В самом начале поисков стало понятно: мы не первые, у кого возникла подобная задача. Сходу нашлось несколько способов ограничения виртуальных машин по используемым ядрам.
Перечислю инструменты в порядке их обнаружения.
CPUTool
Эту утилиту поисковик выдал первой. Очень простой инструмент, который позволяет установить ограничение сверху на потребление CPU для любого процесса по его Process ID. Также утилита умеет устанавливать ограничение при достижении заданного load-average.
Принцип работы
В официальном мануале есть немного информации о принципе работы и примерах использования.
Утилита распределяет процессорное время через механизм таймслайсов. Длительность таймслайса составляет 100 мс. Каждому процессу/группе процессов под управлением CPUTool дается возможность работать только в течение какой-то части таймслайса. Рабочая доля времени внутри него определяется переданным значением аргумента —cpu-limit.
В рамках одного таймслайса CPUTool отправляет процессу сигналы SIGSTOP и SIGCONT. Первый останавливает процесс, а второй — возобновляет.
Плюсы
- Простой и понятный инструмент.
- Может ограничивать потребление процессорного времени.
- Умеет учитывать загрузку системы и останавливать процесс, если нагрузка в системе больше заданного значения.
Минусы
- К каждому процессу добавляется еще и контролирующий процесс cputool. Сам процесс cputool может упасть, и никаких ограничений не останется.
- Постоянно шлет сигналы SIGCONT и SIGSTOP. Обработка большого количества сигналов может сильно нагрузить систему.
- SIGCONT может быть обработан приложением, из-за чего эта утилита подойдет не каждому приложению. Обычно заранее неизвестно, перехватывает ли приложение какие-то сигналы и как их обрабатывает. При использовании CPUTool придется помнить эту особенность.
Вывод
Утилита CPUTool отлично подойдет, когда нужно запустить пару приложений, которые не должны мешать друг другу. Контролировать виртуальные машины с помощью такого инструмента можно, но, какой будет эффект, неясно.
Этот вариант мы отбросили из-за минусов с большим количеством сигналов и необходимостью запускать процесс cputool и следить за ним.
cgroups
Второй находкой был механизм контрольных групп в ядре Linux.
Принцип работы
Механизм cgroups предоставляет возможность объединять процессы в группы. Группами можно управлять, и мониторить потребляемые ресурсы.
Интерфейс контрольных групп представляет собой псевдофайловую систему cgroupfs. То есть настройку работы можно вести через запись значений в специальные файлы. Группировка процессов реализована в коде ядра, а отслеживание потребления и ограничение ресурсов предоставляются набором подсистем — memory, CPU и другими.
Более подробно про cgroups можно прочитать в официальной документации. Вообще возможности cgroups намного шире, чем просто управление потреблением CPU, но мы сконцентрируемся на решении нашей задачи.
Контрольные группы содержат несколько частей, которые вместе дают возможность квотировать CPU у процессов, — Freezer и CPU controller.
Freezer
Для остановки/возобновления работы процесса есть Freezer. Эта подсистема была введена, так как отправка сигналов SIGSTOP/SIGCONT — ненадежный способ остановки и возобновления процесса (пруф).
Проблема с этими сигналами в том, что они видны процессу, в который их отправляют. Более того, сигнал SIGCONT может быть перехвачен и кастомно обработан. Таким образом, остановка/возобновление может сломать приложение, которое перехватывает сигналы.
Подсистема Freezer, в свою очередь, использует внутренние механизмы ядра для остановки и возобновления процессов. Поэтому ее работа не видна процессу, на который он воздействует.
СPU controller
Для управления и мониторинга использования процессора в контрольных группах есть CPU controller. Он позволяет задавать параметры планировщика для группы процессов.
Как вариант, для ограничения процессов по потреблению CPU можно использовать два параметра — cpu.cfs_period_us и cpu.cfs_quota_us. Первый параметр задает период времени, после которого должно произойти перераспределение ресурсов — таймслайс. Второй параметр — cpu.cfs_quota_us — задает доступное для работы время в рамках этого периода. Все показатели времени задаются в микросекундах (на это намекает суффикс _us, но лучше уточнить).
Еще можно использовать параметр cpu.shares.
В этом файле для каждой группы процессов содержится ее вес, который определяет, какую долю процессорного времени может использовать группа. По умолчанию этот параметр равен 1024 единицам для каждой группы. Самое интересное, что реальный, действующий вес определяется исходя из суммы всех весов на текущем уровне иерархии (завернул нормально).
Более наглядно показать особенности работы cpu.shares можно с помощью такой иллюстрации:
Здесь такое поведение, что левой виртуальной машине будет доступно 2/3 ресурсов хоста, а правой — только 1/3. При этом доступный ресурс по CPU для правой виртуальной машины будет делиться поровну между каждым ее ядром.
Действующее значение cpu_shares ядер правой машины будет равно 512/4 = 128, или 8,3% от общего времени. Действующее значение cpu_shares ядра левой машины будет равно 1024, или 66% общего времени.
Поддержка в OpenStack Nova
Облако Selectel построено на базе OpenStack. Поэтому при поиске инструмента мы также оценивали затраты на внедрение в OpenStack.
Нам повезло, и в проекте OpenStack уже предусмотрели использование контрольных групп (дока, дока2). По ходу тестов мы выяснили, что в Nova указанное значение cpu.shares применяется на всю виртуальную машину (пруф). Ну выяснили и выяснили, в чем проблема-то? А проблему будет проще показать на примере.
Посмотрим внимательнее на кусок кода, в котором происходит установка значения cpu_shares для виртуальной машины. На строке 18 видно, что по умолчанию значение cpu_shares для виртуалки масштабируется в зависимости от количества ядер.
Однако далее, в цикле на 22 строке, выполняется проверка наличия кастомного значения cpu_shares в характеристиках ВМ. Если проверка проходит успешно, то есть мы указали свое значение для cpu_shares, указанное значение не масштабируется на количество ядер и устанавливается как есть (строка 23).
Подобное поведение не очень удобно для использования из коробки.
Мы смогли придумать пару вариантов обхода такого поведения:
- Подправить код так, чтобы переданное значение cpu_shares тоже масштабировалось
- Заранее учитывать количество ядер и сразу задавать правильное значение cpu_shares в конфигурации виртуальной машины
Второй же вариант ближе тем, кто любит говорить «Работает – не трогай». Можно же просто держать в голове эту особенность и не писать никакого кода. Просто напиши в конфигурацию нужный вес и все. Profit!
Плюсы
- Нативное решение для ОС Linux.
- Работает незаметно для процесса, которым управляет.
- Поддерживается в OpenStack из коробки.
- Не ограничивает виртуальную машину, если есть свободные ресурсы. Следовательно, виртуалка может работать без ограничений, если есть свободный ресурс.
Минусы
- Нужно учитывать иерархичность cpu.shares при использовании.
- Может показаться, что, установив веса для всех vCPU, мы добьемся успеха по ограничению потребления CPU виртуальной машиной. Однако такой трюк сработает не так, как ожидается. На самом деле сработает, только если указать корректное значение cpu_shares для всей виртуальной машины.
- В случае с OpenStack нужно проделать работу для масштабирования значения cpu_shares. Согласен, правка кода небольшая, но нужно будет хорошенько протестировать это решение.
Вывод
Очень классное решение, которое подойдет для управления большим числом процессов или виртуальных машин. Хорошо масштабируется и автоматизируется.
Ограничиваем «на коленке»
Есть еще более простое решение без использования дополнительного ПО.
Принцип работы
В самом простом варианте можно попробовать запустить больше виртуальных ядер, чем «железных» на хосте. Так, если на хосте шесть CPU, то, запустив шесть виртуальных машин с 2 vCPU, можно считать, что каждое vCPU будет иметь в распоряжении только 0,5 CPU.
В таком подходе отсутствует гибкость в виде установки разных ограничений разным виртуальным машинам. Но это лучше жесткого ограничения на потребление сверху, как в случае с —cpu-limit.
Этот способ хорошо масштабируется за счет добавления хостов. Виртуальные машины не будут ограничены в принципе и будут испытывать steal time, только когда всем резко потребуется процессорное время.
Плюсы
- Не требует дополнительной разработки.
- Простое в понимании.
- Точно так же, как с cgroups, у виртуалки будет возможность занимать больше процессорного времени, чем заявлено, если будет свободный ресурс.
Минусы
- Нужно следить, сколько виртуальных машин запущено на хосте и не превышать заданное соотношение CPU/vCPU. При нарушении соотношения мы рискуем получить виртуалки с меньшим гарантированным процентом, чем заявлено.
- Масштабируется только добавлением новых хостов. Так как виртуальные машины по сути ограничены только параметрами железа, на котором они запущены. Если виртуальную машину, ограниченную через cgroups, можно будет запустить где угодно, то в текущем решении только на специальных хостах.
Вывод
Такой способ организации процентных инстансов удобен тем, что очень прост в реализации и понимании. Несмотря на потерю гибкости в выборе гарантированной доли CPU, можно быстро проверить востребованность подобных виртуальных машин.
Какой путь выбрали мы и почему
Иииии… мы приняли решение использовать ограничение «на коленке».
Почему?
Потому что для начала нам нужно было проверить гипотезу ценности услуги — понять, нужны ли вообще кому-то дешевые серверы с частичной мощностью ядра.
В разработке облачной платформы Selectel мы всегда стараемся найти баланс между профитом и трудозатратами. То есть можно было бы угореть и сделать контрольные группы, наткнувшись по пути на парочку ограничений. Внести патч в OpenStack Nova либо заранее заложить в flavor нужное значение shares.
Но все это было бы нерационально без подтверждения востребованности процентные инстансов у клиентов. Мы сделаем и будем молодцами, а время, потраченное на разработку, не окупится.
Поэтому на данный момент процентные инстансы в Selectel – это виртуальные машины, запущенные на хостах с определенным соотношением CPU/vCPU.
Визуально это выглядит как на картинке:
К слову, благодаря такому решению у Shared Line есть ощутимый профит. В таком варианте нет явного ограничения сверху на потребление CPU. Виртуалка может потреблять хоть 100% CPU до тех пор, пока не возникнет борьба за ресурс. В случае, когда есть конкуренция за ресурсы, всем будет выдано одинаковое количество процессорного времени, но ни в коем случае не меньше выбранного процента производительности — он гарантирован.
Планы
В целом, видно, что интерес к более дешевым виртуальным машинам есть. Shared Line сейчас можно арендовать в Москве и Санкт-Петербурге.
Кстати, если у вас есть мысли, почему вам такой сервер не подойдет, пишите в комментариях!
В дальнейшем, конечно же, мы хотим заехать на использование контрольных групп. Да, в OpenStack можно задать cpu.shares и cpu.cfs_period_us с cpu.cfs_quota_us из коробки. Но для грамотного использования нужно либо патчить OpenStack Nova, либо иначе адаптировать решение.
Переход на контрольные группы чуть облегчит архитектуру решения. Так, например, сейчас под Shared Line у нас выделены отдельные хосты. Рабочая схема, но при ней мы даем гибкость клиентам и отчасти лишаем гибкости себя.
Контрольные группы дадут следующие преимущества:
- можно будет помещать процентные виртуальные машины на любой хост, рядом с любыми другими,
- не нужно будет выделять отдельные хосты под линейку,
- откроется путь к более гибким конфигурациям — например, к 83% ядра (ну а вдруг именно столько вам нужно).
Виртуализация. VMware vSphere
Тут собираю интересное по интересующей меня теме виртуализации.
Страницы
понедельник, 27 апреля 2009 г.
multicore vCPU
Коллеги, уже известно, что vSphere позволит отдавать ВМ до 8 vCPU. Это хорошо. Однако, не все гостевые ОС смогут столько переварить. Например, Win2003 Standart увидит только 4. Обидно, да?
Однако, в ESX\ESXi 4 есть возможность(экспериментальная, правда) представить X vCPU не как X одноядерных процессоров, а как X ядер одного(или там x\2 ядер 2х CPU и т.д.).
- Выключаем ВМ
- Заходим в «Edit Settings. «
- Выбираем «Options»
- «Advanced» -> » General «
- Выбираем » Configuration Parameters . «
- Выбираем » Add Row «
- Пишем опцию » cpuid . coresPerSocket » в столбце » Name «
- Указываем значение (2, 4, или 8) в столбце » Value «
- » OK «
- Включаем ВМ
Например: для ВМ мы указали 4 процессора. Ядер на проц указали 4. ВМ видит 4\4= 1 процессор, с 4 мя ядрами.
11 комментариев:
интересно. А вот ещё вопрос по vSphere. Кто-нибудь уже успел разобраться, в чём разница между виртуальными контроллерами дисков «LSI Logic SAS» и «VMware Paravirtual»?
Понятно, что первый эмулируемый, а второй по идее должен быть полностью синтетический. Из этого есть два следствия.
а) Драйверы под первый уже встроены в ОС, а под второй надо добавлять их отдельно при установке. Так почему же VMware не положила эти драйверы отдельно на диск с VMware Tools? Вытянуть их из MSI для того, чтобы получить возможность сразу установить ОС на контроллер типа «VMware Paravirtual», оказалось совсем нетривиальной задачей.
б) Логично было бы предположить, что при прочих равных производительность синтетического контроллера окажется выше.
Но меня сильно смущает слово «Paravirtual». Раньше оно у меня ассоциировалось исключительно с виртуализацией Linux. Поэтому интересует разница по функциям между двумя этими типами контроллеров. Когда лучше использовать первый, а когда второй?
К сожалению, в Интерете информации по этому вопросу я пока не нашёл. Ответить Удалить
я лично пока не могу давать окончательных ответов. На текущий момент мое видение такое:
про LSI Logic SAS в теории написано следующиее — выбирайте его для дисков под MFC — он поддерживает SCSI 3, ему необходимый. Нужен ли такой контроллер подо что то еще — нет данных.
«Паравиртуализация» применительно к железу означает следующее: если какая то железка паравиртуализированна, то часть соответствующей работы внутри ВМ выполняется на самой железке. Например, в ESX 3 паравиртуализованы видеоконтроллер(для задействования физической видюхи вы вытягиваете ползунок аппаратного ускорения после установки vmware tools) и NIC — TCP Segmentation Offload.
Про производительность контроллера сложно что то утверждать. Зачастую, паравиртуализация дает не увеличение скорости, а уменьшение накладных расходов. Ответить Удалить
хм, но паравиртуализованный контроллер — тоже SAS. Т.е. должен поддерживать SCSI-3. Завтра или послезавтра проверю, подойдёт ли он для кластера. Ответить Удалить
Из неприятного. Четвёртый клиент не работает на Windows 7. Пробова на бете (7000) и на RC (7100). Клиент 2.5 работает без проблем, а 4.0 — нет. Надеюсь, к релизу (сферы, а не Windows 7) починят 🙂 Ответить Удалить
Успешно собрал кластер из двух виртуалок с Windows Server 2008 R2 RC, используя только контроллеры PVSCSI (т.е. как для загрузки, так и для общих дисков).
Правда, валидация не проходит с камими-то дурацкими ошибками, с этим ещё придётся разбираться. Но она точно так же не проходит и с контроллерами LSI. Т.е. это скорее похоже на баг Windows RC, чем vSphere RC 🙂
Но при всём при этом кластер выглядит вполне рабочим. Завтра буду ставить на него SQL Server 2008 SP1. Надеюсь, что vCenter умеет таки с ним работать 🙂
Кстати, я правильно понимаю, что кластеризовать сам vCenter всё ещё нельзя? Ответить Удалить
про кластер vCenter 4 пока не скажу. Ответить Удалить
в общем, да. Установил на тот кластер SQL Server 2008 SP1 CU1, на другую виртуалку поставил vCenter. Тоже на Windows Server 2008 R2 x64 RC (2.5 категорически не работал под 64-битными ОС).
Этот vCenter подключил к SQL Server 2008, используя Windows Authentication (в 2.5 была возможна только SQL Server Authentication). Всё неплохо работает. Особенно порадовала возможность отдавать кластеру vmdk, а не только RDM (тоже новинка vSphere).
интересно, какими будут официальные требования. Ответить Удалить
Оптимизация работы виртуальной инфраструктуры на базе VMWare vSphere
Практика показывает, что любой процесс, в определенной степени, всегда можно оптимизировать. Это вполне можно отнести и к виртуализации. Возможностей оптимизации тут достаточно много, и задача эта многогогранна.
В пределах данной статьи я хочу ознакомить вас с методиками сайзинга виртуальных машин, а так же о методах оптимизации их работы. Материал будет техническим и рекомендуется к ознакомлению всем специалистам по vSphere.
Для начала хотелось бы рассказать о двух технологиях, основным образом влияющих на производительность vSphere. Это технология NUMA и технология работы шедулера гипервизора ESXi.
Про NUMA существует достаточно много подробных статей, пересказывать эту информацию не вижу смысла, ограничусь лишь базовым описанием для целостности материала. Итак, NUMA – Non Uniform Memory Access. На русский язык это можно перевести как Неравноценный Доступ к Памяти.
Современные многосокетные сервера, по сути, представляют собой несколько изолированных односокетных компьютеров, объединенных на одной материнской плате. Каждый процессор монопольно владеет своими слотами оперативной памяти, и только он имеет к ней доступ. Аналогично, каждый процессор имеет свои персональные PCI-E шины, к которым подключены различные устройства материнской платы, а так же слоты расширения PCI-E. Процессоры соединены между собой высокоскоростной шиной обмена данными, по которой они получают доступ к «чужим» устройствам, делая запрос на это соответствующему процессору-хозяину. По понятным причинам, доступ процессора к «своей» памяти происходит гораздо с меньшими накладными расходами, чем к «чужой». Пока это все, что необходимо знать о данной технологии.
vSphere прекрасно знает про NUMA и старается размещать виртуальные ядра машин на тех физических процессорах, в чьей памяти сейчас находится оперативная память виртуальной машины. Но тут возникают подводные камни. Производители серверов любят включать в BIOS по умолчанию эмуляцию NUMA. То есть сервер представляется операционной системе как НЕ NUMA устройство, и vSphere не может использовать свою оптимизацию для управления данной технологией. В документации по vSphere рекомендуется отключать (Disable) данную опцию в BIOS, это позволяет vSphere самостоятельно разбираться с вопросом.
Рассмотрим потенциальные проблемы, которые могу возникнуть с NUMA. Предполагаем, что vSphere его видит и корректно с ним работает. Для примера будем рассматривать 2-процессорную систему, как самый простой вариант NUMA. Предположим, что на физическом сервере 64 GB оперативной памяти, по 32 на каждом сокете.
1. Мы создаем виртуальную машину (ВМ) с одним виртуальным ядром (vCPU). Естественно, такую виртуальную машину сможет исполнить только один физический процессор. Рассмотрим ситуацию, когда ВМ надо дать 48 GB оперативной памяти. 32 GB памяти ВМ заберет у «своего» физического процессора, а еще 16 ей вынужденно придется забрать у «чужого». И при доступе к этим «чужим» гигабайтам мы получаем гарантированно высокие задержки, что ощутимо снизит быстродействие виртуальной машины и увеличит нагрузку на шину передачи данных между физическими процессорами. Исправить ситуацию можно, если дать виртуальной машине 2 виртуальных сокета по 1 ядру каждый. Тогда vSphere распределит 2 vCPU ВМ по разным физическим процессорам, взяв у каждого по 24 GB оперативной памяти. Дав виртуальной машине 1 виртуальный сокет мы лишим её возможности грамотно использовать 2 физических процессора.
2. Вариант, когда мы создаем в плюс к первому пункту вторую ВМ на 10 GB оперативной памяти и один vCPU. Если бы эта ВМ была одна, то никаких проблем нет, она вполне умещается в одну NUMA ноду с 32 GB оперативной памяти. Но у нас уже есть первая машина, которая у обоих нод NUMA отъела по 24 GB памяти, и у каждой ноды осталось свободно всего по 8 GB. В данной ситуации либо первая, либо вторая ВМ начнут использовать часть «чужой» памяти, хотя вроде бы каждая из них сконфигурирована правильно с точки зрения NUMA. Это очень характерная ошибка и необходимо очень досконально просчитывать вашу виртуальную инфраструктуру при проектировании, а так же комплексно подходить к конфигурированию виртуальных машин при эксплуатации.
Хотелось бы отметить, что vSphere имеет свою четкую логику при работе с NUMA и Hyperthreading.
Если у ВМ всего 1 виртуальный сокет, то при увеличении vCPU, исполнение машины будет производиться на одном физическом процессоре исключительно на его физических ядрах без использования технологии Hyperthreading. При превышении количества vCPU над количеством физических ядер процессора, ВМ продолжит исполняться в пределах этого физического процессора, но уже с использование Hyperthreading. Если количество vCPU превысило количество ядер процессора с учетом Hyperthreading, то начнут использоваться ядра соседних NUMA нод (других физических процессоров), что приведет к потере производительности (если указать неверное количество виртуальных сокетов). В случае, когда физический процессор сильно нагружен, и свободных физических ядер не осталось, то в любом случае будет использоваться технология Hyperthreading (если иное не указано в конфигурации виртуальной машины). Если посмотреть на цифры, то в среднем ВМ теряет порядка 30-40% производительности, если она работает на чистом Hyperthreading по сравнению с чистыми физическими ядрами. Но сам физический процессор имеет общую производительность примерно на 30% больше с технологией Hyperthreading, чем без нее (используя только физические ядра). Данный показатель очень зависит от типа нагрузки и оптимизации приложений ВМ к многопоточной работе.
Если у ВМ более одного виртуального сокета, то vSphere будет оптимизировать работу такой ВМ, размещая исполняемые ядра и оперативную память на разных физических процессорах сервера.
По понятным причинам, ситуация с нагрузкой физического сервера постоянно меняется. Зачастую, возникает неравномерность нагрузки на физических процессорах сервера. vSphere следит за этим. Шедулер анализирует положение дел, вычисляет накладные расходы на перемещение ВМ или её части на другую NUMA ноду (перемещение памяти, ядер). Сравнивает эти расходы с потенциальной выгодой от перемещения и принимает решение — оставлять все как есть или же перемещать. Иными словами, при любой ситуации vSphere старается оптимизировать работу виртуальных машин. Наша задача состоит в том, чтобы упростить vSphere эту задачу и не ставить её в безвыходное положение.
О каких потерях может идти речь при неправильной конфигурации машин с NUMA нодами? Руководствуясь собственным опытом, могу сказать, что потери могут доходить до 30% общей производительности физического сервера. Много это или мало – решать вам.
Теперь, когда мы немного разобрались с NUMA и Hyperthreading, мне хотелось бы чуть подробнее рассказать о работе шедулера с ядрами виртуальных машин, vCPU.
Я не буду вдаваться в совсем уж глубины, это мало кому интересно, но постараюсь рассказать про принципы и методику работы данного механизма. Итак, основной механизм гипервизора работает следующим образом. В оперативной памяти постоянно работает процесс, обслуживающий работу виртуальных машин. Этот процесс можно представить как конвейер состояния READY и хранилище состояния WAIT. Опустим другие, менее значимые состояния виртуальных машин, они сейчас не принципиальны.
Для легкости восприятия, предлагаю воспринимать все vCPU виртуальных машин как цепочку. Каждое звено цепи – это ядро vCPU (world, в терминах vSphere). Таких world у машины столько, сколько у нее vCPU. Есть еще 2 невидимых, служебных world, сопутствующих каждой виртуальной машине. Один отвечает за обслуживание машины в целом, второй за её ввод-вывод. Реальное потребление вычислительной мощности этими служебными мирами совершенно незначительное, а потребление ими оперативной памяти можно оценить по показателю overhead у каждой виртуальной машины. Стоит отметить, что при создании ВМ размером в весь физический хост, с равным количеством виртуальных и физических ядер, могут возникнуть некоторые потери производительности. Этого момента я коснусь чуть ниже.
Конвейер READY, это «труба», в которую по очереди сброшены все такие цепочки. Таймслот – это время, в течение которого виртуальные машины исполняются физическим процессором (исполняются их vCPU). На это время виртуальная машина практически без потерь, аналогично физическому серверу, использует физические процессоры аппаратного сервера (pCPU). Максимальная величина таймслота искусственно ограничена величиной порядка 1 миллисекунды. После окончания таймслота, vCPU ВМ принудительно помещаются шедулером в очередь конвейера READY. Шедулер имеет возможность менять очередность виртуальных машин в конвейере READY, приоритет каждой машины вычисляется исходя из её текущей фактической нагрузки, её прав на ресурсы (Shares), как давно машина была на физическом процессоре и еще нескольких менее значимых параметров. Логично предположить, что если ВМ на хосте одна, то она всегда будет проходить конвейер очереди READY без задержек т.к. у нее нет конкурентов на ресурсы со стороны других ВМ.
Каким образом шедулер располагает миры виртуальных машин на физических ядрах? Представим себе таблицу, которая имеет по ширине столько столбцов, сколько ядер у нашего физического сервера (с учетом Hyperthreading). По высоте каждая строка будет соответствовать очередному такту процессора(ов) сервера. Давайте представим себе 2-процессорный сервер, по 6 физических ядер на процессор, + Hyperthreading. Всего получим 24 ядра на сервер. Предположим, что у сервера высокая нагрузка, и vSphere вынуждена использовать Hyperthreading, так будет проще считать. Допустим, у нас есть несколько виртуальных машин:
• 4 штуки по 1 ядру
• 4 штуки по 2 ядра
• 2 штуки по 8 ядер
• 1 штука по 16 ядер
Итак, наступает первый таймслот, шедулер выбирает претендентов. Пусть первой будет машина на 16 ядер. Первые 16 физических ядер (pCPU) заняты, осталось 8. Туда поместились, допустим, 4 машины по 2 ядра (причем машина на 16 ядер должна иметь 2 виртуальных сокета, чтобы корректно работать с NUMA). Всё, таймслот заполнен полностью, это идеальный вариант. Мы не теряем производительность, pCPU не простаивают. Остальные виртуальные машины в это время не работают и находятся в очереди ожидания READY. Предположим, что «счастливые» виртуальные машины получили одинаковый по величине таймслот (хотя в реальности у всех ВМ таймслот разный и зависит от множества факторов). Итак, наступает второй таймслот, и шедулеру надо его заполнить.
Остались не обслуженными машины:
• 4 штуки по 1 ядру
• 2 штуки по 8 ядер
Начинаем заполнять, 2 машины по 8 ядер, 4 машины по 1, осталось 4 свободных pCPU, можно положить туда две 2-ядерных машины, которые уже отработали в первом таймслоте. Больше мы туда уместить ничего не можем, не помещается. Таймслот опять заполнен полностью и мы не теряем мощность.
Аналогичным образом шедулер будет и далее наполнять таймслоты мирами виртуальных машин, стараясь сделать это максимально эффективно, чтобы уменьшить «дыры» в заполнении и повысить КПД виртуальной среды.
Ниже представлен негативный вариант расположения виртуальных машин на хосте. Одна большая машина размером в хост, и одна малая, с 1 vCPU. При равных правах на ресурсы и равных потребностях к производительности эти машины получат одинаковое количество таймслотов, то есть поделят между собой процессорное время. Т.к. обе машины не смогут работать одновременно (не умещаются в один таймслот), то работать они будут по очереди, причем малая машина будет работать в пустом таймслоте, где кроме нее больше никого не будет (таймслот израсходуется практически впустую). Большая машина при всем желании не сможет получить процессорное время, даже если оно этой машине необходимо. Например, при частоте центрального процессора 3 ГГц, обе эти машины смогут максимум получить по 1.5 ГГц.
Виртуализация позволяет создать на хосте несколько виртуальных машин, и может сложиться ситуация, когда суммарное количество vCPU всех машин будет больше количества pCPU физического хоста. Это вполне нормальное явление, но нужно четко осознавать, что одновременно все vCPU не смогут получить 100% от своей завяленной мощности. Иными словами, если у вас на одном хосте виртуализации находятся несколько нагруженных машин и их общее количество vCPU больше чем pCPU хоста, то с высокой долей вероятности эти машины будут мешать друг другу, что снизит их суммарную производительность.
Сейчас хотелось бы вернуться к созданию виртуальной машины величиной в весь хост. Хорошо, пусть такая ВМ заняла собой целиком первый таймслот и отработала его. Теперь вспоминаем про системные миры, сопутствующие этой машине. Их тоже надо исполнять, как надо исполнять сам гипервизор и его собственные системные процессы. То есть надо и им выдавать таймслоты и занимать в них некоторое количество pCPU. А что в это время делать нашей большой ВМ? Правильно, ожидать освобождения ВСЕХ pCPU, чтобы иметь возможность там уместиться. То есть мы гарантированно теряем производительность на служебных задачах гипервизора (таймслотах), а это плохо (вспоминаем пример выше с большой и малой машинами). Для примера, программный iSCSI инициатор под высокой нагрузкой потребляет до 6 ГГц процессорной мощности. Это было бы не так заметно в случае с малыми ВМ т.к. они работали бы параллельно служебным процессам (в этих же таймслотах). А для большой ВМ так не получится т.к. она занимает весь таймслот целиком, все его pCPU, и не может уместиться в таймслот, если хоть один его pCPU уже кем-то занят, пусть и системным процессом.
О каких потерях может идти речь при неправильном конфигурировании виртуальной инфраструктуры и размещении машин по нодам? От нуля до бесконечности (в теории). Все зависит от конкретной ситуации.
Отдельно хотелось бы озвучить главное правило при сайзинге виртуальных машин: давайте виртуальной машине МИНИМАЛЬНО возможные ресурсы, при которых она сможет выполнять свои задачи. Не нужно давать ВМ 2 ядра, если хватает одного. Не нужно давать 4, если хватает 2-х (лишние ядра занимают место в таймслоте). Аналогично с памятью, не стоит выдавать машине лишнего. Возможно, другой машине может не хватить, не говоря уже о возникающих проблемах с живой миграцией (по сути копированием объема памяти ВМ) и NUMA.
Теперь, разобравшись с механизмом размещения vCPU виртуальных машин на pCPU таймслота, давайте вспомним про NUMA и его правила размещения. Для шедулера гипервизора все эти правила имеют значение при заполнении таймслота т.к. pCPU таймслота могут относиться к разным NUMA нодам. Теперь, помимо сложностей учета NUMA при конфигурировании виртуальных машин на хосте, мы получили и ограничения, накладываемые методикой работы шедулера гипервизора с таймслотами. Если мы хотим получить хорошую производительность ВМ, нужно обращать внимание на все подводные камни и руководствоваться следующими правилами:
• Стараться не создавать машины-гиганты (по сравнению с размером хоста)
• Для больших машин надо учитывать ограничения, накладываемые технологией NUMA
• Не стоит злоупотреблять с количеством vCPU по отношению к pCPU хоста
• Несколько мелких или средних машин всегда будут иметь преимущество в гибкости и общей производительности перед огромными машинами
Напоследок хотелось бы сказать о работе шедулера гипервизора с вводом-выводом. При обращении виртуальной машины к своему виртуальному аппаратному обеспечению, гипервизор приостанавливает работу ВМ, снимает её с pCPU и ставит в хранилище WAIT. В таком состоянии машина не работает, она просто ждет. В это время гипервизор трансформирует («подделывает») команды виртуального устройства гостевой машины в реальные команды, соответствующие командам гипервизора, после чего гипервизор возвращает виртуальную машину в конвейер READY. Аналогичная «заморозка» виртуальной машины происходит и при ответе виртуального устройства машине (гипервизору необходимо снова трансформировать ответ, но уже в обратную сторону ). Чем больше команд ввода-вывода производит виртуальная машина, тем чаще она находится в «заморозке» WAIT, и тем меньше её производительность. Чем более «старые» виртуальные устройства ввода-вывода использует виртуальная машина, тем сложнее гипервизору трансформировать команды, и тем дольше ВМ находится в состоянии WAIT.
VMWare прямо и официально не рекомендует виртуализовывать приложения с гиперактивным вводом-выводом. Уменьшить негативное влияние от состояния WAIT можно с помощью использования паравиртуальных устройств для виртуальной машины. Это 10-гигабитная сетевая карта VMXNET3 и паравиртуальный SCSI контроллер жесткого диска PVSCSI. Так же уменьшению влияния WAIT и общему повышению производительности способствует применение в физических серверах аппаратных устройств, предназначенных для ускорения работы виртуальных машин. Это различные сетевые и HBA адаптеры с поддержкой аппаратного iSCSI offload, прямого доступа к памяти, сетевые карты с поддержкой виртуализации и т.д.
На этом я хотел бы остановиться. Надеюсь, информация в данной статье была вам интересна, и вы сможете более эффективно подойти к построению или эксплуатации своей виртуальной инфраструктуры.