Waarom en hoe we Babylon.js naar Azure hebben gemigreerd

Je werkt voor een startup. Opeens levert dat zware jaar van coderen vruchten af ​​- met succes komt meer groei en vraag naar schaalbaarheid van uw web-app.

In deze zelfstudie wil ik nederig een van onze meer recente 'succesverhalen' gebruiken rond ons WebGL open-source gaming-framework, Babylon.js, en zijn website. We zijn verheugd dat zoveel webgaming-ontwikkelaars het uitproberen. Maar om de vraag bij te houden, wisten we dat we een nieuwe webhostingoplossing nodig hadden. 

Hoewel deze zelfstudie zich richt op Microsoft Azure, zijn veel van de concepten van toepassing op verschillende oplossingen die u misschien wilt. We gaan ook de verschillende optimalisaties bekijken die we hebben ingesteld om de uitvoerbandbreedte van onze servers naar uw browser zo veel mogelijk te beperken.

Invoering

Babylon.js is een persoonlijk project waar we nu ruim een ​​jaar aan werken. Omdat het een persoonlijk project is (dat wil zeggen onze tijd en geld), hebben we de website, texturen en 3D-scènes gehost op een relatief goedkope hostingoplossing met behulp van een kleine, speciale Windows / IIS-computer. Het project startte in Frankrijk, maar was snel op de radar van verschillende 3D- en webspecialisten over de hele wereld, evenals enkele gamingstudio's. We waren blij met de feedback van de community, maar het verkeer was beheersbaar!

Tussen februari 2014 en april 2014 hadden we bijvoorbeeld gemiddeld 7K + gebruikers / maand met een gemiddelde van 16K + bekeken pagina's / maand. Sommige van de evenementen waarmee we hebben gesproken, hebben een aantal interessante pieken opgeleverd:

Maar de ervaring op de website was nog goed genoeg. Het laden van onze scènes gebeurde niet bij de sterren, maar gebruikers klaagden niet zo veel.

Onlangs echter besloot een coole kerel om ons werk op Hacker News te delen. We waren erg blij met dergelijk nieuws! Maar kijk eens wat er gebeurde met de verbindingen van de site:

Spel is over voor onze kleine server! Het stopte langzaam met werken en de ervaring voor onze gebruikers was echt slecht. De IIS-server besteedde zijn tijd aan het bedienen van grote statische elementen en afbeeldingen en het CPU-gebruik was te hoog. Omdat we het WebGL-ervaringproject van Assassin's Creed Pirates op Babylon.js wilden starten, was het tijd om over te schakelen naar een meer schaalbare professionele hosting door een cloudoplossing te gebruiken.

Maar laten we, voordat we onze hostingkeuzes bekijken, kort ingaan op de details van onze engine en website:

  1. Alles is statisch op onze website. We hebben momenteel geen code aan de serverzijde.
  2. Onze scènes (.babylon JSON-bestanden) en texturen (.png of .jpeg) -bestanden kunnen erg groot zijn (tot 100 MB). Dit betekent dat we absoluut gzip-compressie op onze .babylon-scènebestanden moesten activeren. In ons geval zullen de prijzen inderdaad veel worden geïndexeerd op de uitgaande bandbreedte.
  3. Het tekenen in het WebGL-canvas vereist speciale beveiligingscontroles. U kunt onze scènes en structuren niet van een andere server laden zonder CORS ingeschakeld, bijvoorbeeld.

Credits: Ik wil graag speciaal bedanken Benjamin Talmard, een van onze Franse Azure Technical Evangelists die ons hielp verhuizen naar Azure.

1. Verhuizen naar Azure-websites & de Autoscale-service

Omdat we de meeste tijd willen besteden aan het schrijven van code en functies voor onze motor, willen we geen tijd verliezen aan het sanitair. Daarom hebben we meteen gekozen voor een PaaS-aanpak en niet voor een IaaS-benadering.

Bovendien hielden we van Visual Studio-integratie met Azure. Ik kan bijna alles doen van mijn favoriete IDE. En zelfs als Babylon.js wordt gehost op GitHub, gebruiken we Visual Studio 2013, TypeScript en Visual Studio Online om onze engine te coderen. Als aantekening voor uw project kunt u Visual Studio Community en een Azure Trial gratis krijgen.

Verhuizen naar Azure duurde ongeveer vijf minuten:

  1. Ik heb een nieuwe website gemaakt op de beheerpagina: http://manage.windowsazure.com (kan ook binnen VS worden gedaan).  
  2. Ik nam de juiste changeset uit onze broncode-repository die overeenkomt met de versie die op dat moment online was.
  3. Ik klikte met de rechtermuisknop op het webproject in de Visual Studio Solution Explorer.

Nu komt hier de awesomeness van de tooling. Omdat ik was aangemeld bij VS via het Microsoft-account dat is gekoppeld aan mijn Azure-abonnement, kan ik met de wizard eenvoudig de website kiezen waarop ik wil implementeren.

U hoeft zich geen zorgen te maken over complexe verificatie, verbindingsreeks of wat dan ook.

Volgende, Volgende, Volgende & PublicerenEn een paar minuten later, aan het einde van het uploadproces van al onze bestanden en bestanden, was de website actief!

Wat de configuratie betreft, wilden we profiteren van de coole autoscale-service. Het zou veel hebben geholpen in ons vorige Hacker News-scenario.

Ten eerste is uw instantie geconfigureerd in Standaard modus in de Schaal tab.

Vervolgens kunt u kiezen tot hoeveel instanties u automatisch wilt opschalen, in welke CPU-omstandigheden, en ook op welke geplande tijden. 

In ons geval hebben we besloten om maximaal drie kleine exemplaren (1 core, 1,75 GB geheugen) te gebruiken en een nieuwe instantie automatisch te spawnen als de CPU meer dan 80% van het gebruik verliest. We zullen één instantie verwijderen als de CPU minder dan 60% daalt. Het autoschaalmechanisme staat altijd open in ons geval - we hebben geen specifieke geplande tijden ingesteld.

Het idee is echt om betaal alleen voor wat je nodig hebt tijdens specifieke tijdframes en belastingen. Ik hou van het concept. Daarmee hadden we eerdere pieken kunnen verwerken door niets te doen dankzij deze Azure-service!

Je hebt ook een snel overzicht van de autoschaalgeschiedenis via de paarse kaart. Omdat we naar Azure zijn verhuisd, hebben we tot nu toe nooit één instantie overschreden. En we gaan hieronder zien hoe je het risico kunt minimaliseren om in een autoscaling te vallen.

Tot besluit over de configuratie van de website wilden we dat schakel automatische gzip-compressie in op onze specifieke 3D-engine bronnen (.Babylon en .babylonmeshdata bestanden). Dit was cruciaal voor ons omdat het tot 3x de bandbreedte kon besparenen dus ... de prijs.

Websites worden uitgevoerd op IIS. Om IIS te configureren, moet je naar de web.config het dossier. In ons geval gebruiken we de volgende configuratie:

                                    

Deze oplossing werkt redelijk goed, en we hebben zelfs gemerkt dat de tijd om onze scènes in te laden is verminderd in vergelijking met onze vorige host. Ik vermoed dat dit komt door de betere infrastructuur en het netwerk dat door Azure-datacenters wordt gebruikt.

Ik heb er echter over nagedacht om nu al een tijdje Azure te gaan gebruiken. En mijn eerste idee was om geen website-instanties mijn grote bezittingen te laten dienen. Sinds het begin ben ik meer geïnteresseerd in het opslaan van mijn items in de blob-opslag die daarvoor beter is ontworpen. Het zou ons ook een mogelijk CDN-scenario bieden.

2. Assets verplaatsen naar Azure Blob Storage, CORS inschakelen, Gzip-ondersteuning en CDN

De belangrijkste reden om blob-opslag in ons geval te gebruiken, is om te voorkomen dat de CPU van onze website-instanties wordt geladen om ze te serveren. Als alles wordt geserveerd via de blob-opslag, met uitzondering van een paar HTML-, JavaScript- en CSS-bestanden, hebben onze website-instances weinig kansen om automatisch te schalen.

Maar dit werpt twee problemen op om op te lossen:

  1. Aangezien de inhoud wordt gehost op een andere domeinnaam, vallen we in het beveiligingsprobleem tussen verschillende domeinen. Om dat te voorkomen, moet je dat doen schakel CORS op het externe domein in (Azure Blob Storage).
  2. azuur Blob Storage biedt geen ondersteuning voor automatische gzip-compressie. En we willen het CPU-websitegebruik niet verlagen als we in ruil drie keer de prijs betalen vanwege de toegenomen bandbreedte!

CORS inschakelen op Blob Storage

CORS on blob storage wordt nu een paar maanden ondersteund. In dit artikel, Windows Azure Storage: CORS introductie, wordt uitgelegd hoe u Azure API's kunt gebruiken om CORS te configureren. Van mijn kant wilde ik geen kleine app schrijven om dat te doen. Ik heb er al een gevonden op het web: Cynapta Azure CORS Helper - Gratis hulpmiddel voor het beheren van CORS-regels voor Windows Azure Blob Storage.

Vervolgens heb ik de ondersteuning voor GET en de juiste headers op mijn container ingeschakeld. Om te controleren of alles werkt zoals verwacht, opent u eenvoudig uw F12 ontwikkelaarsbalk en controleert u de consolelogboeken:

Zoals je ziet, impliceren de groene logregels dat alles goed werkt.

Hier is een voorbeeldgeval waar het zal falen. Als u onze scènes vanuit onze blob-opslag rechtstreeks vanuit uw lokale hostcomputer (of een ander domein) probeert te laden, krijgt u deze fouten in de logboeken:

Tot slot, als u ziet dat uw aanroepend domein niet wordt gevonden in de "Access-Control-Laat-Origin"Header met een"Toegang is geweigerd"Kort daarna komt dat omdat je CORS-regels niet goed hebt ingesteld. Het is erg belangrijk om je CORS-regels te beheersen; anders zou iedereen uw bezittingen en dus uw bandbreedte kunnen gebruiken, geld kosten zonder u dit te laten weten! 

Gzip-ondersteuning inschakelen op onze Blob Storage

Zoals ik je eerder vertelde, Azure Blob Storage biedt geen ondersteuning voor automatische gzip-compressie. Het lijkt ook het geval te zijn met oplossingen van concurrenten zoals S3. Je hebt twee opties om dat te omzeilen:

  1. Gzip de bestanden jezelf op de client vóór het uploaden, upload het in de blob-opslag met behulp van je klassieke gereedschap en stel de Inhoud coderende header naar gzip. Deze oplossing werkt, maar alleen voor browsers die gzip ondersteunen (is er toch nog een browser die gzip niet ondersteunt?). 
  2. Gzip de bestanden zelf op de client en upload twee versies in de blob-opslag: een met de standaard.uitbreiding en een met de .extension.gzip, bijvoorbeeld. Stel een handler in aan de IIS-zijde die het HTTP-verzoek van de client zal opvangen, controleer de header aanvaarden coderende ingesteld op gzip en dien de juiste bestanden op basis van deze ondersteuning. U vindt meer informatie over de code die moet worden geïmplementeerd in dit artikel: GZip-gecomprimeerde inhoud presenteren van het Azure CDN.

In ons geval ken ik geen enkele browser die WebGL ondersteunt en geen compressie gzip. Dus als de browser gzip niet ondersteunt, is er geen echte interesse om verder te gaan, omdat dit waarschijnlijk betekent dat WebGL ook niet wordt ondersteund.

Ik heb daarom de eerste oplossing gekozen. Omdat we niet veel scènes hebben en we niet elke dag een nieuwe maken, gebruik ik momenteel dit handmatige proces:

  1. Met 7-zip comprimeer ik de.Babylon bestanden op mijn machine met behulp van gzip-codering en "compressie niveau" naar "snelst”. De andere compressieniveaus lijken problemen op te leveren in mijn tests.
  2. Ik upload het bestand met CloudBerry Explorer voor Microsoft Azure Cloud Storage.
  3. Ik stel de HTTP-header handmatig in Inhoud coderende naar gzip met CloudBerry.

Ik weet wat je denkt. Ga ik dat doen voor al mijn bestanden?!? Nee, je zou kunnen werken aan het bouwen van een tool of post-build script dat dat zou automatiseren. Hier is bijvoorbeeld een kleine opdrachtregelprogramma dat ik heb gebouwd:

string accountName = "yoda"; string containerName = "wwwbabylonjs"; string accountKey = "yourmagickey"; string sceneTextContent; // Eerste argument moet de map naar de doelmap string = args [0] van de Azure Blob Container zijn; probeer StorageCredentials creds = nieuwe StorageCredentials (accountnaam, accountKey); CloudStorageAccount-account = nieuwe CloudStorageAccount (creds, useHttps: true); CloudBlobClient client = account.CreateCloudBlobClient (); CloudBlobContainer blobContainer = client.GetContainerReference (containernaam); 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 (stringbestand in Directory.GetFiles (specdir, specpart)) string path = Path.Combine (specdir, bestand); string sceneName = Path.GetFileName (pad); Console.WriteLine ("Bezig met werken aan" + sceneName + "..."); CloudBlockBlob blob = sceneDirectory.GetBlockBlobReference (sceneName); blob.Properties.ContentEncoding = "gzip"; blob.Properties.ContentType = "application / babylon"; sceneTextContent = System.IO.File.ReadAllText (pad); var bytes = Encoding.UTF8.GetBytes (sceneTextContent); using (MemoryStream ms = nieuwe MemoryStream ()) using (GZipStream gzip = new GZipStream (ms, CompressionMode.Compress, true)) gzip.Write (bytes, 0, bytes.Length);  ms.Position = 0; Console.WriteLine ("Gzip gedaan."); blob.UploadFromStream (ms); Console.WriteLine ("Uploaden in" + accountnaam + "/" + containerName + "/" + directory + "done.");  catch (Exception ex) Console.WriteLine (ex); 

Om het te gebruiken, zou ik het volgende kunnen doen:

UploadAndGzipFilesToAzureBlobStorage Scenes / Espilit C: \ Boulot \ Babylon \ Scenes \ Espilit \*.Babylon* om een ​​scène te duwen die bevat meerdere bestanden (onze incrementele scènes met muliples .babylonmeshdata -bestanden).

Of gewoon:

UploadAndGzipFilesToAzureBlobStorage Scenes / Espilit C: \ Boulot \ Babylon \ Scenes \ Espilit \Espilit.babylon duwen uniek bestand.

Om te controleren of gzip werkte zoals verwacht met deze oplossing, gebruik ik Fiddler. Laad uw inhoud vanaf uw clientcomputer en controleer de netwerktracés als de geretourneerde inhoud echt is gecomprimeerd en niet kan worden gecomprimeerd:

CDN inschakelen

Nadat u de twee voorgaande stappen hebt uitgevoerd, hoeft u alleen maar op een enkele knop op de Azure-beheerpagina te klikken om CDN in te schakelen en toe te wijzen aan uw blob-opslag:

Het is zo simpel! In mijn geval moet ik gewoon de volgende URL wijzigen: http://yoda.blob.core.windows.net/wwwbabylonjs/Scenes naar http://az612410.vo.msecnd.net/wwwbabylonjs/Scenes. Merk op dat u dit CDN-domein naar uw eigen domein kunt aanpassen als u dat wilt.

Dankzij dit kunnen we u onze 3D-items op een zeer snelle manier van dienst zijn, omdat u wordt bediend vanuit een van de knooppuntlocaties die hier worden vermeld: Azure Content Delivery Network (CDN) Knooppuntlocaties.

Onze website wordt momenteel gehost in het Noord-Europese Azure-datacenter. Maar als u uit Seattle komt, pingt u deze server gewoon om onze basisindex index.html, index.js, index.css en een paar schermafbeeldingen te downloaden. Alle 3D-items worden vanaf het knooppunt in Seattle bij u in de buurt bediend!

Opmerking: al onze demo's maken gebruik van de volledig geoptimaliseerde ervaring (blob-opslag met behulp van gzip, CDN en DB-caching).

3. HTML5 IndexedDB gebruiken om te voorkomen dat de activa opnieuw worden gedownload

Het optimaliseren van de laadtijden en het regelen van de bandbreedtekosten van de uitvoer gaat niet alleen over de server. Je kunt ook wat logische client-side bouwen om dingen te optimaliseren. Gelukkig hebben we dat gedaan sinds v1.4 van onze Babylon.js-engine. Ik heb tot in detail uitgelegd hoe ik de ondersteuning heb geïmplementeerd IndexedDB in dit artikel: IndexedDB gebruiken om uw 3D WebGL-items te verwerken: feedbacks en tips van Babylon.JS delen. En je zult vinden hoe je het in Babylon.js kunt activeren op onze wiki: de bronnen cachen in IndexedDB.

Kortom, je hoeft alleen maar een te maken .babylon.manifest bestand dat overeenkomt met de naam van de .Babylon scène en stel vervolgens in wat u wilt cachen (texturen en / of JSON-scène). Dat is het.

Kijk bijvoorbeeld wat er gebeurt met de demo-scene van Hill Valley. De eerste keer dat u het laadt, worden hier de verzoeken verzonden:

153 items en 43.33 MB ontvangen. Maar als je het accepteren van babylonjs.com hebt geaccepteerd "gebruik extra opslag op uw computer", Hier is wat u de tweede keer ziet dat u dezelfde scène laadt:

1 item en 348 bytes! We controleren alleen of het manifestbestand is gewijzigd. Zo niet, dan laden we alles van de DB en we besparen 43+ MB bandbreedte.

Deze benadering wordt bijvoorbeeld gebruikt in de Assassin's Creed Pirates-spellen:

Laten we daarover nadenken:

  • Het spel lanceert bijna onmiddellijk nadat het eenmaal is geladen, omdat de activa rechtstreeks vanuit de lokale DB worden bediend.
  • Uw webopslag is minder belast en er wordt minder bandbreedte gebruikt-kost je minder geld!

Dat zal zowel uw gebruikers als uw baas tevreden stellen!

Dit artikel maakt deel uit van de web dev tech-serie van Microsoft. We zijn verheugd om te delen Microsoft Edge en het nieuwe EdgeHTML-renderingengine met jou. Download gratis virtuele machines of test op afstand op uw Mac, iOS, Android of Windows-apparaat @ http://dev.modern.ie/.