Hvorfor og hvordan vi flyttet Babylon.js til Azure

Du jobber for oppstart. Plutselig er det harde året med koding som betaler seg - med suksess kommer mer vekst og etterspørsel etter din webapp til å skalere.

I denne opplæringen vil jeg ydmykt bruke en av våre nyere "suksesshistorier" rundt vår WebGL open source-spillramme, Babylon.js og dets nettsted. Vi har vært glade for å se så mange webspills devs prøve det ut. Men for å holde tritt med etterspørselen visste vi at vi trengte en ny web hosting løsning. 

Mens denne opplæringen fokuserer på Microsoft Azure, gjelder mange av konseptene for ulike løsninger du kanskje foretrekker. Vi skal også se de ulike optimeringene vi har satt på plass for å begrense utgangsbåndbredden fra våre servere til nettleseren din så mye som mulig..

Introduksjon

Babylon.js er et personlig prosjekt vi har jobbet med i over et år nå. Siden det er et personlig prosjekt (det vil si vår tid og penger), har vi vært vert for nettstedet, teksturer og 3D-scener på en relativt billig hosting-løsning ved hjelp av en liten, dedikert Windows / IIS-maskin. Prosjektet startet i Frankrike, men var raskt på radaren til flere 3D- og webspesialister over hele verden, samt noen spillstudier. Vi var glade for samfunnets tilbakemeldinger, men trafikken var overkommelig!

For eksempel, mellom februar 2014 og april 2014, hadde vi et gjennomsnitt på 7K + brukere / måned med et gjennomsnitt på 16K + sider vist / måned. Noen av hendelsene vi har snakket på, har generert noen interessante topper:

Men opplevelsen på nettstedet var fortsatt god nok. Lasting av scenene våre ble ikke gjort ved stjernens hastighet, men brukerne klaget ikke så mye.

Men nylig bestemte en fin fyr til å dele vårt arbeid på Hacker News. Vi var veldig glade for slike nyheter! Men se på hva som skjedde med nettstedets tilkoblinger:

Spillet er slutt for vår lille server! Det stoppet langsomt, og erfaringen til brukerne var veldig dårlig. IIS-serveren brukte sin tid på å betjene store statiske ressurser og bilder, og CPU-bruken var for høy. Da vi skulle lansere Assassin's Creed Pirates WebGL-opplevelsesprosjektet som kjører på Babylon.js, var det på tide å bytte til en mer skalerbar profesjonell hosting ved hjelp av en sky løsning.

Men før vi vurderer våre hosting valg, la oss kort snakke om detaljene til vår motor og nettside:

  1. Alt er statisk på vår nettside. Vi har for øyeblikket ingen server-side kode som kjører.
  2. Våre scener (.ababylon JSON-filer) og teksturer (.png eller .jpeg) -filer kan være veldig store (opptil 100 MB). Dette betyr at vi absolutt trengte å aktivere gzip-komprimering på våre .babylon scenefiler. Faktisk, i vårt tilfelle, vil prisingen bli indeksert mye på den utgående båndbredden.
  3. Tegning i WebGL-lerretet krever spesielle sikkerhetskontroller. Du kan ikke laste våre scener og teksturer fra en annen server uten CORS aktivert, for eksempel.

Kreditt: Jeg vil gjerne takke Benjamin Talmard, en av vår franske azuriske tekniske evangelist som hjalp oss med å flytte til Azure.

1. Flytter til Azure Web Sites og Autoscale Service

Som vi ønsker å tilbringe mesteparten av vår tid på å skrive kode og funksjoner for vår motor, ønsker vi ikke å miste tid på rørleggerarbeidet. Derfor bestemte vi oss umiddelbart for å velge en PaaS-tilnærming og ikke en IaaS-en.

Videre likte vi Visual Studio integrasjon med Azure. Jeg kan gjøre nesten alt fra min favoritt IDE. Og selv om Babylon.js er vert på GitHub, bruker vi Visual Studio 2013, TypeScript og Visual Studio Online for å kode vår motor. Som et notat for prosjektet kan du få Visual Studio Community og en Azure Trial gratis.

Flytter til Azure tok meg omtrent fem minutter:

  1. Jeg opprettet et nytt nettsted på admin siden: http://manage.windowsazure.com (kan gjøres inne i VS også).  
  2. Jeg tok de riktige endringene fra kildekodebiblioteket som matchet versjonen som var i øyeblikket online.
  3. Jeg høyreklikket på Web-prosjektet i Visual Studio Solution Explorer.

Nå kommer verktøyets awesomeness. Da jeg var logget inn i VS ved hjelp av Microsoft-kontoen som var bundet til mitt Azure-abonnement, la veiviseren meg bare velge det nettstedet jeg vil distribuere.

Du trenger ikke å bekymre deg for kompleks godkjenning, tilkoblingsstreng eller hva som helst.

Neste, Neste, Neste og Publiser"Og et par minutter senere, på slutten av opplastingsprosessen av alle våre eiendeler og filer, var nettstedet oppe!

På konfigurasjonssiden ønsket vi å dra nytte av den kule autoskala-tjenesten. Det ville ha hjulpet mye i vårt tidligere Hacker News-scenario.

Først har forekomsten din blitt konfigurert i Standard modus i Scale tab.

Deretter kan du velge opp til hvor mange forekomster du vil automatisk skalere, i hvilke CPU-forhold, og også på hvilke planlagte tider. 

I vårt tilfelle har vi bestemt oss for å bruke opptil tre små forekomster (1 kjerne, 1,75 GB minne) og å automatisk kaste en ny forekomst hvis CPUen går over 80% av bruken. Vi fjerner en forekomst dersom CPU faller under 60%. Autoscaling-mekanismen er alltid i vårt tilfelle - vi har ikke angitt bestemte planlagte tider.

Ideen er virkelig å Bare betal for det du trenger under bestemte tidsrammer og belastninger. Jeg elsker konseptet. Med det ville vi ha kunnet håndtere tidligere topper ved ikke å gjøre noe takket være denne Azure-tjenesten!

Du har også en rask visning på autoscaling historie via det lilla diagrammet. I vårt tilfelle, siden vi har flyttet til Azure, gikk vi aldri over en forekomst hittil. Og vi skal se nedenfor for å minimere risikoen for å falle inn i autoskala.

For å konkludere på nettstedet konfigurasjon, ønsket vi å aktiver automatisk gzip-komprimering på våre spesifikke 3D-motorressurser (.babylon og .babylonmeshdata filer). Dette var kritisk for oss, da det kunne spare opptil 3 ganger båndbreddenog dermed ... prisen.

Nettsteder kjører på IIS. For å konfigurere IIS må du gå inn i web.config fil. Vi bruker følgende konfigurasjon i vårt tilfelle:

                                    

Denne løsningen virker ganske bra, og vi la merke til at tiden for å laste scenene våre har blitt redusert i forhold til vår tidligere vert. Jeg gjetter dette er takket være den bedre infrastrukturen og nettverket som brukes av Azure datacenter.

Imidlertid har jeg tenkt på å flytte inn i Azure for en stund nå. Og min første ide var ikke å la websider forekomme å betjene mine store eiendeler. Siden begynnelsen har jeg vært mer interessert i å lagre mine eiendeler i blob-lagringen bedre designet for det. Det vil også gi oss et mulig CDN-scenario.

2. Flytte eiendeler til Azure Blob Storage, Aktivere CORS, Gzip Support & CDN

Den primære grunnen til å bruke blob-lagring i vårt tilfelle er å unngå å laste inn CPUen til våre nettsider for å betjene dem. Hvis alt blir servert via blob-lagringsplassen, bortsett fra noen få HTML-, JavaScript- og CSS-filer, vil våre websider forekomme få sjanser til autoskala.

Men dette reiser to problemer å løse:

  1. Siden innholdet vil bli hostet på et annet domenenavn, vil vi falle inn i sikkerhetsproblemet på tvers av domenen. For å unngå det, må du aktiver CORS på det eksterne domenet (Azure Blob Storage).
  2. Azure Blob Storage støtter ikke automatisk gzip-komprimering. Og vi ønsker ikke å senke CPU-nettstedets bruk hvis vi i bytte betaler tre ganger prisen på grunn av økt båndbredde!

Aktiverer CORS på Blob Storage

CORS på blob storage har blitt støttet i noen måneder nå. Denne artikkelen, Windows Azure Storage: Introduserer CORS, forklarer hvordan du bruker Azure APIer til å konfigurere CORS. På min side ville jeg ikke skrive en liten app for å gjøre det. Jeg har funnet en på nettet allerede skrevet: Cynapta Azure CORS Helper - Gratis verktøy for å håndtere CORS-regler for Windows Azure Blob Storage.

Jeg så bare aktivert støtten til GET og riktige overskrifter på min container. For å sjekke om alt fungerer som forventet, åpner du bare F12 utviklerlinjen og sjekker konsollloggene:

Som du kan se, betyr de grønne logglinjene at alt fungerer bra.

Her er et eksempel på tilfelle hvor det vil mislykkes. Hvis du prøver å laste våre scener fra vår blob-lagring direkte fra din lokale vertsmaskin (eller et annet domene), får du disse feilene i loggene:

Til slutt, hvis du ser at ditt anropsdomene ikke finnes i "Tilgang-Control-La-Origin"Header med en"Tilgang nektes"Like etter det er det fordi du ikke har satt dine CORS regler riktig. Det er veldig viktig å kontrollere CORS-reglene; ellers kan noen bruke dine eiendeler, og dermed båndbredden din, koste penger uten å fortelle deg det! 

Aktiverer Gzip Support på vår Blob Storage

Som jeg fortalte deg før, Azure Blob Storage støtter ikke automatisk gzip-komprimering. Det synes også å være tilfelle med konkurrenters løsninger som S3. Du har to muligheter til å jobbe rundt det:

  1. Gzip filene deg selv på klienten før opplasting, Last opp den i blob-lagringen ved hjelp av de klassiske verktøyene og sett inn innhold-koding header til gzip. Denne løsningen fungerer, men bare for nettlesere som støtter gzip (er det fortsatt en nettleser som ikke støtter gzip uansett?). 
  2. Gzip filene selv på klienten og last opp to versjoner i blob lagring: ett med standard.forlengelse og en med .extension.gzip, for eksempel. Sett opp en handler på IIS-siden som vil fange HTTP-forespørselen fra klienten, sjekk etter overskriften Accept-Encoding satt til gzip og tjen de riktige filene basert på denne støtten. Du finner flere detaljer om koden som skal implementeres i denne artikkelen: Visning av GZip-komprimert innhold fra Azure CDN.

I vårt tilfelle vet jeg ikke hvilken nettleser som støtter WebGL og ikke gzip-komprimering. Så hvis nettleseren ikke støtter gzip, er det ingen reell interesse i å gå videre, da dette sannsynligvis betyr at WebGL ikke støttes heller.

Jeg har derfor valgt den første løsningen. Siden vi ikke har mange scener, og vi ikke produserer en ny hver dag, bruker jeg for øyeblikket denne manuelle prosessen:

  1. Ved å bruke 7-zip, komprimerer jeg.babylon filer på maskinen min ved hjelp av gzip-koding og "komprimeringsnivå" til "raskeste”. De andre komprimeringsnivåene ser ut til å generere problemer i mine tester.
  2. Jeg laster opp filen ved hjelp av CloudBerry Explorer for Microsoft Azure Cloud Storage.
  3. Jeg angir manuelt HTTP-overskriften innhold-koding til gzip med CloudBerry.

Jeg vet hva du tenker. Skal jeg gjøre det for alle mine filer?!? Nei, du kan jobbe med å bygge et verktøy eller et post-build-skript som ville automatisere det. For eksempel, her er et lite kommandolinjeverktøy jeg har bygget:

streng accountName = "yoda"; string containerName = "wwwbabylonjs"; string accountKey = "yourmagickey"; streng sceneTextContent; // Første argumentet må være katalogen i Azure Blob Container targeted string directory = args [0]; prøv StorageCredentials creds = nye StorageCredentials (accountName, accountKey); CloudStorageAccount account = nytt CloudStorageAccount (creds, useHttps: true); CloudBlobClient client = account.CreateCloudBlobClient (); CloudBlobContainer blobContainer = client.GetContainerReference (containerName); blobContainer.CreateIfNotExists (); var sceneDirectory = blobContainer.GetDirectoryReference (katalog); streng [] filesArgs = args.Skip (1) .ToArray (); foreach (streng filespec i filesArgs) string specdir = Path.GetDirectoryName (filespec); streng specpart = Path.GetFileName (filespec); hvis (specdir.Length == 0) specdir = Environment.CurrentDirectory;  foreach (strengfil i Directory.GetFiles (specdir, specpart)) string path = Path.Combine (specdir, fil); streng sceneName = Path.GetFileName (bane); Console.WriteLine ("Arbeider på" + scenenavn + "..."); CloudBlockBlob blob = sceneDirectory.GetBlockBlobReference (sceneName); blob.Properties.ContentEncoding = "gzip"; blob.Properties.ContentType = "application / babylon"; sceneTextContent = System.IO.File.ReadAllText (sti); var bytes = Encoding.UTF8.GetBytes (sceneTextContent); bruker (MemoryStream ms = new MemoryStream ()) bruker (GZipStream gzip = ny GZipStream (ms, CompressionMode.Compress, true)) gzip.Write (bytes, 0, bytes.Length);  ms.Position = 0; Console.WriteLine ("Gzip gjort."); blob.UploadFromStream (ms); Console.WriteLine ("Opplasting i" + kontonavn + "/" + containernavn + "/" + katalog + "ferdig.");  fangst (Unntak ex) Console.WriteLine (ex); 

For å bruke det, kunne jeg gjøre følgende:

UploadAndGzipFilesToAzureBlobStorage Scener / Espilit C: \ Boulot \ Babylon \ Scenes \ Espilit \* .Babylon * å skyve en scene som inneholder flere filer (våre inkrementelle scener med muliples .babylonmeshdata filer).

Eller bare:

UploadAndGzipFilesToAzureBlobStorage Scener / Espilit C: \ Boulot \ Babylon \ Scenes \ Espilit \Espilit.babylon å presse a unik fil.

For å sjekke at gzip jobbet som forventet med denne løsningen, bruker jeg Fiddler. Last inn innholdet fra klientmaskinen din og sjekk inn nettverkssporene hvis innholdet som returneres er komprimert og komprimert:

Aktiverer CDN

Når du har gjort de to foregående trinnene, trenger du bare å klikke på en enkelt knapp på Azures administrasjonsside for å aktivere CDN og kartlegge den til din blob-lagring:

Det er så enkelt! I mitt tilfelle må jeg bare endre følgende URL: http://yoda.blob.core.windows.net/wwwbabylonjs/Scenes to http://az612410.vo.msecnd.net/wwwbabylonjs/Scenes. Merk at du kan tilpasse dette CDN-domenet til deg selv hvis du vil.

Takket være det er vi i stand til å betjene dine 3D-eiendeler på en veldig rask måte, da du blir servert fra en av knuteplassene som er oppført her: Azure Content Delivery Network (CDN) Node Locations.

Vårt nettsted er for tiden vert på Nord-Europa Azur datacenter. Men hvis du kommer fra Seattle, vil du pinge denne serveren bare for å laste ned våre grunnleggende index.html, index.js, index.css-filer og et par skjermbilder. Alle 3D-eiendelene blir servert fra Seattle-noden like i nærheten av deg!

Merk: Alle våre demoer bruker den fullt optimaliserte opplevelsen (blob-lagring ved hjelp av gzip, CDN og DB caching).

3. Bruke HTML5 IndexedDB for å unngå å laste ned eiendommene igjen

Optimalisering av lastetider og kontroll av utgangsbåndbreddekostnader handler ikke bare om server-side. Du kan også bygge en logisk klientside for å optimalisere ting. Heldigvis har vi gjort det siden v1.4 i vår Babylon.js-motor. Jeg har forklart i detalj hvordan jeg har implementert støtten til IndexedDB i denne artikkelen: Bruke IndexedDB til å håndtere dine 3D WebGL-ressurser: deling tilbakemeldinger og tips fra Babylon.JS. Og du finner hvordan du aktiverer den i Babylon.js på vår wiki: Caching ressurser i IndexedDB.

I utgangspunktet må du bare lage en .babylon.manifest fil som matcher navnet på .babylon scene, og sett deretter hva du vil cache (teksturer og / eller JSON scene). Det er det.

For eksempel, se hva som foregår med Hill Valley demo scene. Første gang du laster den, er det sendt forespørsler:

153 varer og 43,33 MB mottatt. Men hvis du har akseptert å la babylonjs.com "bruk ekstra lagring på datamaskinen din", Her er det du vil se andre gang du laster opp samme scene:

1 vare og 348 byte! Vi kontrollerer bare om manifestfilen er endret. Hvis ikke, laster vi alt fra DB og Vi sparer 43 + MB båndbredde.

For eksempel er denne tilnærmingen brukt i Assassin's Creed Pirates-spillene:

La oss tenke på det:

  • Spillet lanserer nesten umiddelbart etter at den har blitt lastet en gang, da eiendelene blir servert direkte fra den lokale DB.
  • Nettlagring er mindre stresset og mindre båndbredde brukes-koster deg mindre penger!

Nå som vil tilfredsstille både brukerne og sjefen din!

Denne artikkelen er en del av web dev-teknologiserien fra Microsoft. Vi er glade for å dele Microsoft Edge og den nye EdgeHTML rendering motor med deg. Få gratis virtuelle maskiner eller test eksternt på Mac, IOS, Android eller Windows-enheten @ http://dev.modern.ie/.