
Cloud Gaming и VDI — разные технологии, применяемые для разных задач и даже для разной целевой аудитории. Вместе с тем, если заглянуть к ним под капот, можно увидеть, что у технологий есть много общего — например, одинаковые принципы стриминга видеопотока, методы сжатия передаваемых по сети данных и борьбы с потерями сетевых пакетов. Таким образом, при разработке Cloud Gaming можно отчасти опираться на технологии, примененные в VDI, и наоборот. Именно так мы и поступили при создании сервиса VDI (Cloud Desktop) для облака VK Cloud.
Привет, Хабр. Меня зовут Кирилл Черников. Я руководитель Команды клиентской разработки в VK Tech. В этой статье я расскажу об особенностях Cloud Gaming и VDI, о разнице в требованиях к сервисам, сложностях адаптации игрового решения к задачам VDI и о полученных результатах на примере сервиса VK Play Cloud и платформы VK Cloud.
Начнем с контекста
Мы с командой работаем в сфере Cloud Gaming с 2013 года и за это время значительно прокачали опыт в особенностях построения проектов облачного гейминга и нюансах полного цикла создания стримингового движка, который отвечает за передачу и управление аудио и видео. Через наш движок уже наиграны миллионы сессий на миллиарды минут.
Вместе с тем мы решили не останавливаться на достигнутом и применить свой опыт и имеющиеся наработки для разработки облачного сервиса для быстрого создания безопасных удаленных рабочих мест (VDI) Cloud Desktop.
При этом мы исходили из того, что сервисы Cloud Gaming и VDI архитектурно сходны.
Так, сессия в Cloud Gaming строится следующим образом:
Есть локальные устройства — например, компьютер, телефон, планшет, телевизор, для работы с которыми используются устройства ввода (клавиатура, мышь, геймпад и другие).
Локальное устройство передает управление и аудио на виртуальную машину.
Виртуальная машина выполняет обработку, захватывает аудио и видео, выполняет кодирование и отправляет аудио и видео обратно на локальное устройство, где и воспроизводится конечный результат.

Таким образом, пользователь взаимодействует только со своим локальным устройством, а весь процессинг выполняется на виртуальной машине.
В случае VDI алгоритм идентичен, но добавляется необходимость работы с USB-устройствами, файловой системой, принтерами и буфером обмена.

То есть при адаптации движка Cloud Gaming под VDI в теории не должно возникать никаких сложностей. Но здесь возникает нюанс. И чтобы понять его суть, нужно немного погрузиться в детали.
Подходы к организации VDI
Есть несколько подходов к организации VDI:
классический RDP-подход (Remote Desktop Protocol);
VNC-подход (Virtual Network Computing);
подход с кодированием видео.
Рассмотрим каждый детально.
Классически RDP-подход
Классический RDP-подход основан на передаче метаинформации: виртуальная машина отправляет данные о расположении окон и изменении их свойств.
При этом элементы интерфейса, которые невозможно передать напрямую как отдельные окна или их характеристики, передаются в виде графических объектов, закодированных стандартными форматами изображений (например, JPEG, PNG).

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

Примечание: Сегодня классический RDP почти не применяется. Чаще всего используется гибридный вариант, сочетающий принципы RDP с технологиями кодирования видео.
VNC-подход
VNC-подход использует протокол RFB (Remote FrameBuffer protocol). Принцип работы следующий: с виртуальной машины на локальное устройство передаются изменения экрана — различия в пикселях, предварительно упакованные и сжатые для снижения нагрузки на сеть.

Например, на экране открыто приложение текстового редактора. Когда пользователь выбирает инструмент выделения текста («жирный шрифт»), изменяется внешний вид соответствующей иконки. Эта область экрана обновляется, и ее новая версия сразу же передается на локальное устройство, обеспечивая мгновенное обновление интерфейса.

Подход с кодированием видео
Третий подход — использование методов кодирования видео. Его суть проста: кадр за кадром изображение кодируется, причем последующие кадры зависят от предыдущих, формируя непрерывный видеопоток.

Сравнение подходов
Теперь сравним подходы в деталях.
Для начала остановимся на основных параметрах.
Основные параметры
Качество картинки. Методы RDP и VNC обеспечивают стабильно высокое качество картинки. Подход с кодированием видео позволяет гибко настраивать качество — оно может варьироваться от низкого до максимального в зависимости от текущих условий сети и требований пользователя.
Задержка. В случае RDP и VNC задержки сложно регулировать, поскольку нет возможности контролировать и ограничивать объем информации, передаваемой от виртуальной машины на локальную. В случае кодирования с этим проблем нет, поскольку видео хоть и с потерей качества, но можно сжать для уменьшения задержек.
Работа с приложениями. Подходы RDP и VNC изначально были разработаны для работы с офисными приложениями. Кодирование видео не имеет таких ограничений.
Работа с медиа. RDP и VNC плохо подходят для работы с медиа, в то время как подход с кодированием предназначен именно для этой задачи.
Классический RDP |
VNC |
Кодирование видео |
|
Качество картинки |
Высокое |
Высокое |
Гибкая настройка |
Задержка |
Слабо регулируема |
Слабо регулируема |
Гибкая настройка |
Работа |
Офисные |
Офисные |
Любые |
Работа с медиа |
Подходит плохо |
Подходит плохо |
Отлично подходит |
Cloud Gaming vs VDI: требования к ресурсам
Теперь, когда стало понятно, какие способы могут применяться для организации VDI, остановимся подробнее на сравнении Cloud Gaming и VDI с точки зрения требований к ресурсам ВМ.
GPU, аппаратное ускорение. В Cloud Gaming ускорение на ВМ обязательно. В случае VDI это не обязательно и зависит исключительно от задачи.
CPU. Для запуска игр требуются большие вычислительные мощности, поэтому на ВМ должно быть от 6–8 ядер. VDI зачастую ориентирован на офисные задачи, поэтому в большинстве случаев требование к ядрам начинается от 1–2.
Cloud Gaming |
VDI |
|
GPU, аппаратное ускорение |
Обязательно |
Не обязательно |
CPU |
От 6–8 ядер |
От 1–2 ядер |
Одновременно с этим на клиентской машине для Cloud Gaming должно быть аппаратное ускорение, которое для VDI не обязательно. Но как для Cloud Gaming, так и для VDI нужно 2 более ядер CPU для организации производительной работы с потоками аудио и видео.
Cloud Gaming |
VDI |
|
GPU, аппаратное ускорение |
Почти обязательно |
Не обязательно |
CPU |
От 2 ядер |
От 2 ядер |
Cloud Gaming vs VDI: другие технические требования
Фреймрейт. Для комфортной игры нужно минимум от 30 FPS. Для офисных задач, для которых, как правило, используют VDI, достаточно от 5 FPS.
Общая задержка. Для Cloud Gaming важно, чтобы задержка была не более 100 мс, иначе игроки будут прекращать сессию. В VDI допустимы задержки даже до 500–700 мс.
Битрейт. Чтобы обеспечить высокое качество картинки, для Cloud Gaming нужен битрейт на уровне 4–5 Мбит/с и выше для 720p. В VDI, в зависимости от контента, может хватить и 300–500 Кбит/с.
Качество картинки. В Cloud Gaming возможны просадки качества. В VDI — нет.
Платформа. В обоих случаях поддерживаются любые платформы.
Шрифты. В играх, как правило, мало текста, поэтому качество шрифтов не имеет значения. В сценариях использования VDI — наоборот.
Cloud Gaming |
VDI |
|
FPS |
Не меньше 30 |
От 5 |
Общая задержка |
Не более 100 мс |
Не более 500–700 мс |
Битрейт (720р) |
От 4–5 Мбит/с |
От 300–500 Кбит/с |
Качество картинки |
Возможны просадки |
Высокое почти всегда |
Платформа |
Любая |
Любая |
Шрифты |
Нет акцента на качество |
Высокий акцент на качество |
Cloud Gaming vs VDI: бизнес-требования
Полоса пропускания. Для Cloud Gaming минимальный рекомендуемый канал связи — 25 Мбит/с, оптимальный — 50 Мбит/с (чем выше разрешение монитора игрока, тем шире должна быть полоса пропускания). В VDI полоса пропускания на одну ВМ может быть ограничена лимитом в 1–2 Мбит/с.
Спецификация ВМ. Для Cloud Gaming обязательно мощное графическое оборудование (GPU), так как игровое окружение требует значительных ресурсов. В случае VDI конфигурация ВМ выбирается в зависимости от конкретной задачи — жесткого ограничения на GPU нет.
Cloud Gaming |
VDI |
|
Полоса пропускания |
От 25 Мбит/с на ВМ |
Может быть до 1–2 Мбит/с на ВМ |
Спецификация ВМ |
Сильное ограничение, наличие GPU обязательно |
Слабые ограничения, наличие GPU под задачу |
Стриминговый движок Cloud Gaming и его адаптация под VDI
Что ж, с требованиями определились.
Теперь перейдем ближе к сути нашей задачи, а именно — посмотрим, как устроен стриминговый движок в Cloud Gaming и с чем мы с командой столкнулись, когда адаптировали его под задачи VDI.
Стриминговый движок Cloud Gaming
Верхнеуровнево стриминговый движок Cloud Gaming на стороне виртуальной машины состоит из нескольких основных компонентов, которые взаимодействуют друг с другом.
Из сети в сторону виртуальной машины передаются отчеты, в которых содержится информация о том, как доставляются кадры.
Обработкой этих отчетов занимается блок анализаторов, который на выходе формирует статистику и передает ее в «сердце» движка — ABR (адаптивный алгоритм битрейта).
ABR контролирует передачу данных, определяя необходимые настройки кодирования и объемы передаваемой информации. После анализа статистики он выдает рекомендации: какой битрейт использовать для кодирования следующего кадра и какой объем FEC использовать для отправки следующего кадра. Эти рекомендации передаются кодировщику, ответственному за кодирование кадра, и в модуль Pacing, который контролирует процесс отправки кадров в сеть.

Соответственно, если сеть «чистая» и проблем не возникает (пропускной способности достаточно), картинка кодируется с высоким качеством.
Если же сетевые проблемы есть, о них становится известно еще на этапе анализаторов: анализатор по отчетам из сети узнает, что есть определенный объем потерь или определенные задержки при доставке данных. Он собирает эту статистику и передает ее в ABR.

ABR, анализируя проблемы, может дать две команды: снизить битрейт либо поднять объем FEC (или сделать это одновременно).

После этого кодировщик делает ограничение на кодируемый кадр, а pacing добавляет нужный объем FEC.

Благодаря такому алгоритму стриминговый движок способен поддерживать комфортный уровень играбельности даже при равномерном Lost Rate 40% (проверено лично на Counter-Strike).
Нюанс в том, что этот алгоритм отработки сетевых проблем нельзя в исходном виде перенести на VDI — мы неизбежно получим замыленные шрифты, «дребезжащую» картинку и артефакты, которые сделают невозможной комфортную работу даже с офисными приложениями. Соответственно, для VDI нужен другой подход к управлению битрейтом.
Как управлять битрейтом в VDI
В исходном стриминговом движке Cloud Gaming битрейтом можно управлять напрямую через ABR, который передает нужные параметры кодировщику, тем самым ограничивая размер каждого кадра, даже в угоду уменьшению качества данного кадра. Но в VDI важно, чтобы качество картинки было не ниже определенного уровня (чтобы изображение не было замыленным). Поэтому мы не можем напрямую ограничивать размер кадров.
Поскольку прямое ограничение размера кадров невозможно, приходится менять режим кодирования. Стандартные кодировщики обычно поддерживают два базовых варианта:
ориентация на целевой объем данных, когда задается максимальный или желаемый размер кадра или объем битрейта, в который должен укладываться поток;
ориентация на качество, при которой кадр должен соответствовать определенным критериям.
Таким образом, для VDI мы должны избавиться от кодирования с ориентацией на объем данных и перейти на кодирование с ориентацией на качество. То есть уходим от режимов кодирования, связанных с CBR/VBR/VBV/HRD, к CRF/CQP или другим режимам константного качества.
Чтобы понять, как такие изменения выглядят на уровне кода, покажу, как это реализовано на примере x264.
Cloud Gaming |
VDI |
|
|
|
Здесь видим, что в Cloud Gaming используется vbvBuffer, который имеет строгие ограничения. Это позволяет нам делать кадры определенного размера. Дополнительно мы показываем кодировщику, что стримим 1 FPS, чтобы иметь возможность быстро адаптироваться к изменяющимся требованиям ABR.
В VDI vbvBuffer отключается. Вместо этого мы задаем константу, через которую указываем, с каким фактором надо кодировать изображение (в нашем случае — f_rf_constant = 23.0f).
В результате мы получаем фиксированное качество картинки, но никак не можем контролировать битрейт.
Соответственно, возникает задача что-то делать с большими кадрами. Здесь возможны два пути решения:
Снижение качества изображения. Но этот способ ограничен минимальным порогом качества и, следовательно, малой возможностью управления объемом потока.
Уменьшение частоты кодирования кадров. Такой подход представляется более предпочтительным и управляемым решением.
Останавливаемся на втором варианте.
Соответственно, нам нужно перейти от регулировки битрейта с помощью ABR к регулировке фреймрейта с помощью AFR (Adaptive Frame Rate). При этом, поскольку для ABR проделано много работы, нужен механизм связи, который позволит реализовать такой переход без полного отказа от ABR.
Поиск механизма для связи
Чтобы разобраться, каким должен быть искомый механизм, для начала рассмотрим модуль Pacing в Cloud Gaming.
В Cloud Gaming мы придерживаемся стабильного FPS. Закодированные кадры передаются в модуль Pacing, распределяющий отправку пакетов, на которые разделены кадры, исходя из межкадрового интервала.

Такой алгоритм отлично работает и позволяет гарантировать равномерную скорость передачи данных в сеть. Но это все работает только при условии, что у нас стабильный FPS.
В VDI, отказавшись от постоянного FPS (нужно экономить трафик, исходя из требований, описанных выше), мы вынуждены вводить новую схему обработки кадров. Здесь кадры снова дробятся на пакеты, которые помещаются в специальную очередь. Каждому пакету присваивается метка времени отправки, рассчитанная на основании рекомендаций ABR.
Формула расчета простая: мы делим доступный битрейт, предложенный ABR, на 1000, получая максимальную долю данных, которую можно передать за одну миллисекунду.

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

Архитектура сохранилась аналогичной Cloud Gaming, но изменилась связь компонентов:
Алгоритм ABR теперь передает данные о размере FEC и битрейте не напрямую в кодировщик, а в модуль pacing, куда добавляется очередь пакетов.
Задача очереди — отслеживать появление заторов и информировать AFR.
AFR оперативно корректирует скорость кодирования, сообщая кодировщику о необходимости временно замедлиться, если требуемая скорость отправки данных превышает расчетную рекомендацию ABR.
Таким образом, мы полностью адаптировали стриминговый движок под задачи VDI.
Теперь поговорим об особенностях работы с потоком в VDI.
Особенности работы с потоком в VDI
Начнем со специфики восстановления потока в VDI.
Восстановление потока в VDI
В VDI работают все механизмы обработки ошибок и восстановления валидного потока данных, как и в Cloud Gaming. Например, можно использовать:
IDR / Invalidate Reference / Intra Refresh;
FEC;
Retransmit.
Вместе с тем при работе с VDI нельзя получать артефакты — это плохо сказывается на комфорте использования офисных приложений. Поэтому нам важно отдавать в декодер только валидный поток. Чтобы обеспечить это, нам нужно использовать максимальный DPB и Ref Frames для уменьшения количества IDR.
Экономия трафика
В VDI бизнес-требования часто предписывают минимизировать потребление трафика. Это особенно актуально, когда компания разворачивает сотни виртуальных рабочих мест одновременно.
Для экономии трафика можно использовать два подхода.
Оптимизация FEC. Можно сократить число избыточных пакетов, повысив эффективность передачи данных.
Работа со статической картинкой и повторным кодированием. Например, в Cloud Gaming мы делаем повторное кодирование одной и той же картинки, чтобы поддерживать стабильный FPS даже при работе с беспроводными сетями.
Остановимся подробнее на работе с FEC.
Дискретная модель регулирования FEC
Будем подразумевать, что используется FEC c максимальной мощностью восстановления, — то есть, добавляя n битов избыточной информации, FEC позволит восстановить также n битов потерянной информации.
Нами была разработана дискретная модель регулирования объема FEC, которая основывается на трех основных дискретных величинах:
??, ??, …, ??, ??+?, … ? ? — объем FEC для кадра i;
??, ??, …, ??, ??+?, … ?? — индикатор потери кадра i при передаче по сети;
??, ??, …, ??, ??+?, … ?? — возможные варианты функции расчета объема FEC.
При этом функция расчета может зависеть от нескольких параметров. Среди таковых:
? – временной промежуток для расчета;
? – количество предыдущих кадров;
?????, ?????, … , ?????, ?????+?, …????? — объем потерь пакетов для кадра;
?????, ?????, …, ?????, ?????+?, …????? — значение пинга для кадра i и другие.
Например, можно использовать следующие функции:

Первая рассчитывает объем FEC для кадра на основе максимальных потерь пакетов предыдущих k кадров, а вторая — объем FEC для кадра на основе максимальных потерь пакетов предыдущих k кадров с определенным ограничением.
С помощью этих функций мы можем определить, сколько должны добавить избыточных данных FEC для каждого кадра.
Теперь что касается целеполагания.
Наша аксиома заключается в том, что процент потерянных пакетов для кадра i не зависит от выбора функции расчета объема FEC и количества пакетов FEC.
И в Cloud Gaming, и в VDI это выполняется:
Для Cloud Gaming это выполняется за счет того, что чем больше пакетов FEC мы добавим в поток, тем меньше будет пакетов с полезной нагрузкой. То есть объем данных, которые мы посылаем в сеть, всегда стабилен. Дополнительно это регулируется с помощью Pacing.
В VDI мы можем регулировать скорость передачи данных с помощью очереди.
Таким образом, мы можем гарантировать, что количество данных, уходящих в сеть, всегда будет одинаковым.
Исходя из этого, мы можем вычислить два значения:
суммарный объем FEC для n последних кадров при выборе j-й функции расчета:
???=∑?=?,????
суммарный индикатор потери n последних кадров при выборе j-й функции расчета:
???=∑?=?,????
При этом наша цель — минимизировать первую величину при условии, что вторая не будет больше выбранного максимума.

Благодаря проделанной работе, используя целеполагание ?_??? ≤0,15% и подбирая различные функции определения объема FEC, мы смогли повысить эффективность использования канала практически на 20 пунктов.
Было |
Стало |
|
Общее |
61–63% |
78–80% |
Ethernet |
67–68% |
83–84% |
Wi-Fi |
56–57% |
76–77% |
LTE/3G |
51–53% |
72–74% |
К результатам
Для Cloud Gaming и VDI используются стриминговые движки практически идентичной архитектуры. Благодаря этому даже несмотря на различия в технических и бизнес-требованиях к оборудованию, а также на разную толерантность к допустимым искажениям во время сессии, для построения VDI реально адаптировать игровые технологии. Причем наш кейс показал, что можно не просто создать решение под новые задачи, а реализовать его таким образом, чтобы пользователи не сталкивались с проблемой снижения качества картинки и перерасходом трафика.
В дальнейшем мы планируем сосредоточиться на оптимизации кодирования и задержки управления, на улучшении качества шрифтов при передаче данных рабочего стола. Попробуем поэкспериментировать с гибридными техниками стриминга, включающими учет метаинформации об измененных регионах изображения на стороне виртуальной машины. Также кажется перспективным использование функции ROI (Region of Interest) для трансляции удаленного рабочего стола.