Статьи

Почему и как мы мигрировали Babylon.js в Azure

Вы работаете на стартап. Внезапно этот тяжелый год кодирования окупается — с успехом приходит все больший рост и потребность в масштабировании вашего веб-приложения.

В этом уроке я хочу смиренно использовать одну из наших недавних «историй успеха», касающихся нашей игровой среды с открытым исходным кодом WebGL, Babylon.js и ее веб-сайта . Мы были рады увидеть, как многие разработчики веб-игр попробуют это. Но чтобы удовлетворить спрос, мы знали, что нам нужно новое решение для веб-хостинга.

Хотя данное руководство посвящено Microsoft Azure, многие концепции применимы к различным решениям, которые вы можете предпочесть. Мы также увидим различные оптимизации, которые мы внедрили для максимального ограничения пропускной способности от наших серверов до вашего браузера.

Babylon.js — это личный проект, над которым мы работаем уже больше года. Поскольку это личный проект (т. Е. Наше время и деньги), мы разместили веб-сайт, текстуры и 3D-сцены на относительно дешевом хостинг-решении, используя небольшую выделенную машину Windows / IIS. Проект начался во Франции, но быстро оказался в центре внимания нескольких специалистов по 3D и веб-технологиям по всему миру, а также некоторых игровых студий. Мы были рады отзывам сообщества, но трафик был управляемым!

Например, в период с февраля 2014 года по апрель 2014 года у нас было в среднем 7 000+ пользователей в месяц и в среднем 16 000 просмотренных страниц в месяц. Некоторые из событий, о которых мы говорили, вызвали некоторые интересные пики:

Пики в пользовательских данных

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

Однако недавно крутой парень решил поделиться нашей работой над Hacker News . Мы были очень рады таким новостям! Но посмотрите, что случилось с подключениями сайта:

Большой всплеск пользователей

Игра окончена для нашего маленького сервера! Это медленно перестало работать, и опыт для наших пользователей был действительно плохим. Сервер IIS тратил свое время на обслуживание больших статических ресурсов и изображений, а загрузка ЦП была слишком высокой. Когда мы собирались запустить опытный проект Assassin’s Creed Pirates WebGL, работающий на Babylon.js, пришло время перейти на более масштабируемый профессиональный хостинг с помощью облачного решения.

Но прежде чем рассматривать наш выбор хостинга, давайте кратко поговорим о специфике нашего движка и сайта:

  1. На нашем сайте все статично. В настоящее время у нас нет запущенного серверного кода.
  2. Наши сцены (файлы .babylon JSON) и файлы текстур (.png или .jpeg) могут быть очень большими (до 100 МБ). Это означает, что нам абсолютно необходимо активировать сжатие gzip в наших файлах сцены .babylon. Действительно, в нашем случае цены будут сильно проиндексированы на исходящей полосе пропускания.
  3. Рисование на холсте WebGL требует специальных проверок безопасности. Например, вы не можете загрузить наши сцены и текстуры с другого сервера без включенного CORS.

Благодарности: Я хотел бы особо поблагодарить Бенджамина Талмара , одного из наших французских технических евангелистов Azure, которые помогли нам перейти на Azure.

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

Кроме того, нам понравилась интеграция Visual Studio с Azure. Я могу сделать почти все из моей любимой IDE. И даже если Babylon.js размещен на GitHub , мы используем Visual Studio 2013, TypeScript и Visual Studio Online для кодирования нашего движка. В качестве заметки для вашего проекта вы можете бесплатно получить Visual Studio Community и пробную версию Azure .

Переезд в Лазурный занял у меня примерно пять минут:

  1. Я создал новый веб-сайт на странице администратора: http://manage.windowsazure.com (может быть сделано и внутри VS).
  2. Я взял правильный набор изменений из нашего репозитория исходного кода, соответствующий версии, которая была в данный момент онлайн.
  3. Я щелкнул правой кнопкой мыши веб-проект в обозревателе решений Visual Studio.
Visual Studio Solution Explorer

Теперь здесь приходит удивительный инструмент. Когда я вошел в VS с использованием учетной записи Microsoft, связанной с моей подпиской Azure, мастер позволил мне просто выбрать веб-сайт, на котором я хотел бы развернуть.

Выберите веб-сайт для развертывания

Не нужно беспокоиться о сложной аутентификации, строке подключения или чем-то еще.

« Next, Next, Next & Publish » и через пару минут, в конце процесса загрузки всех наших ресурсов и файлов, веб-сайт запущен и работает!

Что касается конфигурации, мы хотели воспользоваться классным сервисом автоматического масштабирования. Это очень помогло бы в нашем предыдущем сценарии Hacker News.

Во-первых, ваш экземпляр был настроен в стандартном режиме на вкладке Scale .

выбор режима тарифного плана

Затем вы можете выбрать, сколько экземпляров вы хотите автоматически масштабировать , в каких условиях процессора, а также в какое запланированное время.

В нашем случае мы решили использовать до трех небольших экземпляров (1 ядро, 1,75 ГБ памяти) и автоматически порождать новый экземпляр, если загрузка ЦП превышает 80%. Мы удалим один экземпляр, если процессор упадет ниже 60%. Механизм автоматического масштабирования всегда включен в нашем случае — мы не установили определенное запланированное время.

Настройки размера и масштаба

Идея состоит в том, чтобы действительно платить только за то, что вам нужно, в определенные сроки и нагрузки. Я люблю концепцию. Благодаря этому мы смогли бы справиться с предыдущими пиками, ничего не делая благодаря этому сервису Azure!

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

Чтобы завершить настройку веб-сайта, мы хотели включить автоматическое сжатие gzip для наших конкретных ресурсов 3D-движка ( .babylon и .babylonmeshdata ). Это было очень важно для нас, так как это могло сэкономить до 3х полосы пропускания и таким образом … цена.

Веб-сайты работают на IIS. Чтобы настроить IIS, вам нужно зайти в файл web.config . В нашем случае мы используем следующую конфигурацию:

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
<system.webServer>
  <staticContent>
    <mimeMap fileExtension=».dds» mimeType=»application/dds» />
    <mimeMap fileExtension=».fx» mimeType=»application/fx» />
    <mimeMap fileExtension=».babylon» mimeType=»application/babylon» />
    <mimeMap fileExtension=».babylonmeshdata» mimeType=»application/babylonmeshdata» />
    <mimeMap fileExtension=».cache» mimeType=»text/cache-manifest» />
    <mimeMap fileExtension=».mp4″ mimeType=»video/mp4″ />
  </staticContent>
  <httpCompression>
    <dynamicTypes>
      <clear />
      <add enabled=»true» mimeType=»text/*»/>
      <add enabled=»true» mimeType=»message/*»/>
      <add enabled=»true» mimeType=»application/x-javascript»/>
      <add enabled=»true» mimeType=»application/javascript»/>
      <add enabled=»true» mimeType=»application/json»/>
      <add enabled=»true» mimeType=»application/atom+xml»/>
      <add enabled=»true» mimeType=»application/atom+xml;charset=utf-8″/>
      <add enabled=»true» mimeType=»application/babylonmeshdata» />
      <add enabled=»true» mimeType=»application/babylon»/>
      <add enabled=»false» mimeType=»*/*»/>
    </dynamicTypes>
    <staticTypes>
      <clear />
      <add enabled=»true» mimeType=»text/*»/>
      <add enabled=»true» mimeType=»message/*»/>
      <add enabled=»true» mimeType=»application/javascript»/>
      <add enabled=»true» mimeType=»application/atom+xml»/>
      <add enabled=»true» mimeType=»application/xaml+xml»/>
      <add enabled=»true» mimeType=»application/json»/>
      <add enabled=»true» mimeType=»application/babylonmeshdata» />
      <add enabled=»true» mimeType=»application/babylon»/>
      <add enabled=»false» mimeType=»*/*»/>
    </staticTypes>
  </httpCompression>
</system.webServer>

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

Однако я уже некоторое время думаю о переходе в Azure. И моей первой идеей было не позволить экземплярам веб-сайта обслуживать мои большие активы. С самого начала я больше интересовался хранением своих активов в хранилище больших двоичных объектов, лучше предназначенном для этого. Это также предложило бы нам возможный сценарий CDN.

Основная причина использования хранилища BLOB-объектов в нашем случае заключается в том, чтобы не загружать ЦП экземпляров нашего веб-сайта для их обслуживания. Если все обслуживается через хранилище больших двоичных объектов, за исключением нескольких файлов HTML, JavaScript и CSS, у нашего веб-сайта будет мало шансов на автоматическое масштабирование.

Но это поднимает две проблемы для решения:

  1. Поскольку контент будет размещен на другом доменном имени, мы столкнемся с проблемой междоменной безопасности. Чтобы избежать этого, необходимо включить CORS в удаленном домене (хранилище BLOB-объектов Azure).
  2. Azure Blob Storage не поддерживает автоматическое сжатие gzip . И мы не хотим снижать загрузку веб-сайта ЦП, если взамен мы платим в три раза больше из-за увеличения пропускной способности!

CORS для хранения больших двоичных объектов поддерживается уже несколько месяцев. В этой статье, Windows Azure Storage: введение в CORS , объясняется, как использовать API Azure для настройки CORS. Со своей стороны, я не хотел писать небольшое приложение для этого. В Интернете я уже нашел одно: Cynapta Azure CORS Helper — бесплатный инструмент для управления правилами CORS для хранилища BLOB-объектов Windows Azure .

Затем я просто включил поддержку GET и правильные заголовки в моем контейнере. Чтобы проверить, все ли работает должным образом, просто откройте панель разработчика F12 и проверьте журналы консоли:

Журналы консоли F12

Как видите, зеленые строки журнала означают, что все работает хорошо.

Вот пример случая, когда он потерпит неудачу. Если вы попытаетесь загрузить наши сцены из нашего хранилища BLOB-объектов непосредственно с вашего локального компьютера (или любого другого домена), вы получите следующие ошибки в журналах:

Консольные ошибки

В заключение, если вы видите, что ваш вызывающий домен не найден в заголовке « Access-Control-Allow-Origin » с « Доступ запрещен » сразу после этого, то это потому, что вы неправильно установили свои правила CORS. Очень важно контролировать свои правила CORS ; в противном случае любой может использовать ваши активы и, следовательно, вашу пропускную способность, стоив денег, не сообщая об этом!

Как я уже говорил ранее, хранилище BLOB-объектов Azure не поддерживает автоматическое сжатие gzip . Похоже, это также относится к решениям конкурентов, таким как S3. У вас есть два варианта:

  1. Gzip файлы самостоятельно на клиенте перед загрузкой , загрузите его в хранилище BLOB-объектов, используя ваши классические инструменты, и установите заголовок для content-encoding на gzip . Это решение работает, но только для браузеров, поддерживающих gzip (есть ли еще браузер, не поддерживающий gzip?).
  2. Gzip файлы самостоятельно на клиенте и загрузить две версии в хранилище BLOB-объектов : одна со значением по умолчанию .extension и один с .extension.gzip , например. Настройте обработчик на стороне IIS, который будет перехватывать HTTP-запрос от клиента, проверьте, что для заголовка accept-encoding задано значение gzip и обслуживайте соответствующие файлы на основе этой поддержки. Подробнее о коде, который нужно реализовать, вы найдете в этой статье: Обслуживание сжатого содержимого GZip из Azure CDN .

В нашем случае я не знаю ни одного браузера, поддерживающего WebGL и не сжимающего gzip. Так что, если браузер не поддерживает gzip, нет никакого реального интереса идти дальше, так как это, вероятно, означает, что WebGL также не поддерживается.

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

  1. Используя 7-zip , я сжимаю Файлы .babylon на моей машине, используя кодировку gzip и « уровень сжатия » для « самого быстрого ». Другие уровни сжатия вызывают проблемы в моих тестах.
  2. Я загружаю файл с помощью CloudBerry Explorer для облачного хранилища Microsoft Azure .
  3. Я вручную установил content-encoding заголовка HTTP на gzip с CloudBerry.
вручную установите кодировку содержимого заголовка HTTP в gzip с CloudBerry

Я знаю, о чем ты думаешь. Я собираюсь сделать это для всех моих файлов?!? Нет, вы могли бы поработать над созданием инструмента или сценария после сборки, который бы автоматизировал это. Например, вот небольшой инструмент командной строки, который я построил:

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
string accountName = «yoda»;
string containerName = «wwwbabylonjs»;
string accountKey = «yourmagickey»;
string sceneTextContent;
 
// First argument must be the directory into the Azure Blob Container targeted
string directory = args[0];
 
try
{
StorageCredentials creds = new StorageCredentials(accountName, accountKey);
CloudStorageAccount account = new CloudStorageAccount(creds, useHttps: true);
CloudBlobClient client = account.CreateCloudBlobClient();
CloudBlobContainer blobContainer = client.GetContainerReference(containerName);
blobContainer.CreateIfNotExists();
 
var sceneDirectory = blobContainer.GetDirectoryReference(directory);
 
string[] filesArgs = args.Skip(1).ToArray();
 
foreach (string filespec in filesArgs)
{
    string specdir = Path.GetDirectoryName(filespec);
    string specpart = Path.GetFileName(filespec);
 
    if (specdir.Length == 0)
    {
        specdir = Environment.CurrentDirectory;
    }
    foreach (string file in Directory.GetFiles(specdir, specpart))
    {
        string path = Path.Combine(specdir, file);
        string sceneName = Path.GetFileName(path);
 
        Console.WriteLine(«Working on » + sceneName + «…»);
 
        CloudBlockBlob blob = sceneDirectory.GetBlockBlobReference(sceneName);
        blob.Properties.ContentEncoding = «gzip»;
        blob.Properties.ContentType = «application/babylon»;
 
        sceneTextContent = System.IO.File.ReadAllText(path);
 
        var bytes = Encoding.UTF8.GetBytes(sceneTextContent);
        using (MemoryStream ms = new MemoryStream())
        {
            using (GZipStream gzip = new GZipStream(ms, CompressionMode.Compress, true))
            {
                gzip.Write(bytes, 0, bytes.Length);
            }
            ms.Position = 0;
            Console.WriteLine(«Gzip done.»);
            blob.UploadFromStream(ms);
            Console.WriteLine(«Uploading in » + accountName + «/» + containerName + «/» + directory + » done.»);
        }
    }
}
}
catch (Exception ex)
{
Console.WriteLine(ex);
}

Чтобы использовать его, я мог бы сделать следующее:

UploadAndGzipFilesToAzureBlobStorage Scenes / Espilit C: \ Boulot \ Babylon \ Scenes \ Espilit \ * .babylon *, чтобы выдвинуть сцену, содержащую несколько файлов (наши инкрементные сцены с несколькими файлами .babylonmeshdata ).

Или просто:

UploadAndGzipFilesToAzureBlobStorage Scenes / Espilit C: \ Boulot \ Babylon \ Scenes \ Espilit \ Espilit.babylon, чтобы отправить уникальный файл .

Чтобы проверить, что gzip работает должным образом с помощью этого решения, я использую Fiddler . Загрузите свой контент с клиентского компьютера и проверьте в сети следы, действительно ли возвращенный контент сжат и может быть распакован:

Fiddler Web Debugger

Выполнив два предыдущих шага, вам просто нужно нажать одну кнопку на странице администрирования Azure, чтобы включить CDN и сопоставить ее с хранилищем больших двоичных объектов:

включить CDN и отобразить его в хранилище BLOB-объектов

Это так просто! В моем случае мне нужно просто изменить следующий URL: http://yoda.blob.core.windows.net/wwwbabylonjs/Scenes на http://az612410.vo.msecnd.net/wwwbabylonjs/Scenes . Обратите внимание, что вы можете настроить этот домен CDN по своему усмотрению.

Благодаря этому мы можем очень быстро обслуживать наши 3D-ресурсы, поскольку вы будете обслуживаться из одного из перечисленных здесь узлов: местоположения узлов сети доставки контента Azure (CDN) .

В настоящее время наш веб-сайт размещается в центре обработки данных Azure в Северной Европе. Но если вы приехали из Сиэтла, вы пропингуете этот сервер, чтобы загрузить наши базовые файлы index.html, index.js, index.css и пару скриншотов. Все 3D-ресурсы будут обслуживаться в узле Сиэтла рядом с вами!

Примечание. Во всех наших демонстрационных программах используется полностью оптимизированный интерфейс (хранилище больших двоичных объектов с использованием кэширования gzip, CDN и DB).

Оптимизация времени загрузки и управление затратами на пропускную способность не только на стороне сервера. Вы также можете построить некоторую логику на стороне клиента, чтобы оптимизировать вещи. К счастью, мы сделали это начиная с версии 1.4 нашего движка Babylon.js. Я подробно объяснил, как реализовал поддержку IndexedDB в этой статье: Использование IndexedDB для управления вашими активами 3D WebGL: обмен отзывами и советами по Babylon.JS . И вы узнаете, как активировать его в Babylon.js на нашей вики: Кэширование ресурсов в IndexedDB .

По сути, вам просто нужно создать файл .babylon.manifest соответствующий названию сцены .babylon , а затем указать, что вы хотите кэшировать (текстуры и / или сцены JSON). Вот и все.

Например, проверьте, что происходит с демонстрационной сценой Hill Valley. При первой загрузке, вот отправленные запросы:

Запросы отправлены

Получено 153 элемента и 43,33 МБ . Но если вы согласились разрешить babylonjs.com « использовать дополнительное хранилище на вашем компьютере », вот что вы увидите во второй раз, когда загрузите ту же сцену:

Показан только один запрос

1 элемент и 348 байт! Мы просто проверяем, изменился ли файл манифеста. Если нет, мы загружаем все из БД и экономим более 43 МБ полосы пропускания .

Например, этот подход используется в играх Assassin’s Creed Pirates :

Игра Assassins Creed Пираты

Давайте подумаем об этом:

  • Игра запускается практически сразу после ее загрузки, так как ресурсы обслуживаются непосредственно из локальной БД.
  • Ваше веб-хранилище менее подвержено нагрузкам и использует меньшую пропускную способность, что обойдется вам дешевле!

Теперь это удовлетворит и ваших пользователей, и вашего босса!

Эта статья является частью серии технологий веб-разработки от Microsoft. Мы рады поделиться с вами Microsoft Edge и новым механизмом рендеринга EdgeHTML . Получите бесплатные виртуальные машины или проведите удаленное тестирование на устройстве Mac, iOS, Android или Windows @ http://dev.modern.ie/ .