Увеличение размера буфера VMBus для повышения производительности сети в ВМ


В компонентах интеграции Hyper-V шина VMBus играет роль широкой магистрали, по которой как потоки автотранспорта снуют потоки пакетов от виртуальных машин к физическим устройствам. Как и в реальной жизни эта магистраль может быть довольно таки сильно занята, и возникают пробки. Если в обычной жизни стоянка в пробке – это удел автомобилистов, то в виртуализации сам сетевой пакет не может судить, сколько времени ему ожидать очереди на отправку. Для этого каждая виртуальная машина имеет буфер. Размер буфера по умолчанию – 1 Мб. Буфер вмещает в себя 655 пакетов (по 1600 байт каждый). В некоторых случаях, о которых мы сейчас поговорим, этого буфера бывает недостаточно. Виртуальная машина может начать терять пакеты, что сразу же сказывается на скорости работы сети. Забегая вперёд, скажу, что рекомендую увеличить размер буфера до 2 МБ, а в некоторых случаях и до 4 МБ (максимально поддерживаемый размер). Когда, как и для чего, – об этом мы сейчас и поговорим.

Гипервизор, обрабатывая запросы от виртуальных машин, делит всё своё время на интервалы – кванты, через которые он обращается к той или иной машине для обмена данными по шине VMBus. В зависимости от количества прерываний, генерируемых виртуальной машиной, и нагрузки на гипервизор, размер кванта (в теории) может достигать 10 миллисекунд. Это означает, что гипервизор раз в 10 мс будет обращаться к виртуальной машине, чтобы обслужить её очередь пакетов на VMBus. В реалии такой размер кванта возникает не часто, но мы исследуем худший сценарий. Что такое 10 миллисекунд для сервера? Физические серверы могут обслуживать до 260000 пакетов в секунду на 10Гбит интерфейсе. Для виртуальной машины при размере кванта в 10 мс за одну секунду происходит сто сеансов обслуживания. Это значит, что виртуальная машина может передать лишь 65500 пакетов с интерфейса (800 Мбит). Если виртуальная машина будет пытаться передать больше (и если по какой-то причине невысоко количество генерируемых прерываний, отвечающее за уменьшение размера кванта), то пакеты начнут теряться. Это вынудит машину пересылать их повторно, что скажется на скорости работы сети. Это не является ограничением драйверов или компонентов интеграции. Просто в данном редком случае значение размера буфера является недостаточным. Если мы увеличим его с 655 до 2600, то это будет соответствовать максимальным возможностям физического сервера и решит потенциальную проблему.

Увеличение размера буфера следует делать для каждой виртуальной машины. Под это будет выделяться реальная память сервера. Если вас не смущает выделение дополнительных пары мегабайт на каждую виртуальную машину из памяти сервера (увеличение буферов до 2МБ в 512 машинах потребует примерно 1ГБ памяти сервера), то смело вносите изменения во все машины, чтобы более не думать о буфере. Как же это сделать?

Размер буфера задаётся внутри виртуальной машины для каждого сетевого интерфейса. В ОС Windows каждый сетевой интерфейс имеет свой уникальный GUID. Увидеть GUID текущей сетевой карты можно в диспетчере устройств в свойствах драйвера сетевой карты:

В редакторе реестра на виртуальной машине следует найти ветвь HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Class\{GUID}\{index} , соответствующую данному интерфейсу:

Внутри значения индекса следует создать два ключа типа DWORD: ReceiveBufferSize и SendBufferSize. Значения этих ключей считаются в килобайтах в шестнадцатеричном виде. 0x400 соответствует размеру буфера по умолчанию в 1МБ. Изменив значение на 0x800, вы зададите размер буфера в 2 МБ. Задав значение 0x1000, получите размер буфера 4МБ. На примере ниже задаются размеры обоих буферов по 2МБ:

 

Если вы хотите добиться изменения размера буфера в виртуальных машинах Linux, то перед компиляцией ядра с компонентами интеграции 2.1 вимательно посмотрите файл NETVSC.H, где явно задаются значения для NETVSC_SEND_BUFFER_SIZE и NETVSC_RECEIVE_BUFFER_SIZE. Помните, что внесение изменений в эти файлы вы делаете на свою ответственность. После внесения изменений требуется перекомпиляция ядра (или по крайней мере модулей Hyper-V). Если есть интерес к установке и настройке компонент интеграции под Linux, я могу написать статью на примере какого-нибудь неподдерживаемого дистрибутива, например, Debian. Очевидно, что с RedHat и SUSE всё проще – там компоненты интеграции сразу поставляются в комплекте.

Не ожидайте от этих изменений существенного увеличения производительности. В 99% случаев размер кванта существенно меньше 10 мс. Да и очередь пакетов на отправку не превышает 1МБ. Однако, для душевного спокойствия администраторов, для достижения стабильности и повышения доступности я бы рекомендовал увеличить размер буфера до 2 или даже до 4 мегабайт на всех промышленно используемых виртуальных машинах. Сами понимаете, что пара мегабайт памяти на одну машину не стоят ваших мыслей о том, как там работает буфер!

Comments (9)

  1. Alex A says:

    Расскажите о результатах, очень интересно!

  2. Нескромные вопросы:

    1. Почему сразу буфер не был сделан 2 или 4 Мб?

    2. Почему отсутствует механизм задания этого буфера через GUI или PoSh? Предложенное решение выглядит как хак. Система после такого хака будет официально поддерживаться?

  3. Alex A says:

    Ну почему "не так".

    Значения по умолчанию в Linux отличаются от более протестированных больших значений в Windows.

    К сожалению, внутри Microsoft, всё что касается ореn sоurсе чуть-ли не засекречено от сотрудников, по каким-то юридическим тонкостям GРL лицензии, так что спросить напрямую у разработчика я не могу, - отшлёпают. 🙂

  4. Alex A says:

    Вообще, компоненты интеграции версии 2.0 находятся в staged area любого ядра, начиная с 2.6.32

    То есть даже в Debian или CentOS, можно просто обновить ядро, и включить модули.

    Компоненты 2.1 (с многопроцессорностью и синхронизацией времени) нужно доставлять отдельно. Задача Microsoft сначала доработать с community драйверы, поданные в staged area, перевести их в основную область ядра, а далее работать над обновлением уже в основе ядра.

    С Debian пошагово делается все не совсем тривиально, потому я и думал рассказать.

  5. Alex A says:

    1. Потому что в 99.9% случаев буфер не наполняется и на 100КБ. Использование 1МБ примерно в 0.05%, а 4МБ а 0.0005% случаев согласно собираемой информации. Ну а просто так забирать по лишних 6МБ на ВМ (два буфера по +3МБ) посчитали расточительным для умолчания.

    2. Для Windows это поддерживается. Функция и ключи реестра документированы.

  6. Ingvar says:

    Большое спасибо. Весьма ценная информация. Про Linux тоже было бы интересно узнать. Насчет RedHat - я так понимаю компоненты интеграции встроены начиная с 6 версии?

  7. В компонентах интеграции для Linux 2.1 в файле NETVSC.H есть такие строчки:

    #define NETVSC_SEND_BUFFER_SIZE 64*1024 // 64K

    #define NETVSC_RECEIVE_BUFFER_SIZE 1024*1024 // 1MB

    Сдаётся мне что то здесь не так 🙂

  8. Коллеги поместили в HyperV один из тестовых DB серверов Oracle под RHEL 5U5 и уже давно тиранят меня проблемой дикого роста времени ответа по сети во время импорта здоровенных дампов (собственно это единственная проблема поэтому от такого решения отказываться никто не собирается), на выходных поэкспериментируем.

    Спасибо за наводку!

  9. К сожалению ситуация не исправилась, на вид всё как прежде

    примерно так это выглядит:

    Reply from 10.1.12.108: bytes=32 time<1ms TTL=64

    Reply from 10.1.12.108: bytes=32 time=3980ms TTL=64

    Reply from 10.1.12.108: bytes=32 time<1ms TTL=64

    Reply from 10.1.12.108: bytes=32 time=3995ms TTL=64

    Reply from 10.1.12.108: bytes=32 time<1ms TTL=64

    Reply from 10.1.12.108: bytes=32 time=3979ms TTL=64

    Reply from 10.1.12.108: bytes=32 time<1ms TTL=64

    Reply from 10.1.12.108: bytes=32 time=3993ms TTL=64

    Reply from 10.1.12.108: bytes=32 time<1ms TTL=64

    Ping statistics for 10.1.12.108:

       Packets: Sent = 1307, Received = 1307, Lost = 0 (0% loss),

    Approximate round trip times in milli-seconds:

       Minimum = 0ms, Maximum = 4503ms, Average = 207ms

Skip to main content