Varför och hur vi migrerade Babylon.js till Azure

Du arbetar för en start. Plötsligt betalar det svåra året av kodning med framgång med ökad tillväxt och efterfrågan på din webbapplikation.

I den här handledningen vill jag ödmjukt använda en av våra senaste "succeshistorier" kring vår webbglädje WebGL, Babylon.js och dess hemsida. Vi har varit glada att se så många webbspel devs prova det. Men för att hålla fast vid efterfrågan visste vi att vi behövde en ny webbhotelllösning. 

Medan denna handledning fokuserar på Microsoft Azure gäller många av koncepten för olika lösningar du kanske föredrar. Vi ska också se de olika optimeringarna vi har infört för att så mycket som möjligt minska utmatningsbandbredd från våra servrar till din webbläsare.

Introduktion

Babylon.js är ett personligt projekt vi har arbetat med i över ett år nu. Eftersom det är ett personligt projekt (det vill säga vår tid och pengar), har vi värd webbplatsen, texturer och 3D-scener på en relativt billig värdlösning med en liten, dedikerad Windows / IIS-maskin. Projektet startade i Frankrike, men var snabbt på radarn av flera 3D-och webbspecialister runt om i världen samt några spelstudior. Vi var nöjda med gemenskapens feedback, men trafiken var hanterbar!

Till exempel, mellan februari 2014 och april 2014, hade vi i genomsnitt 7K + användare / månad med i genomsnitt 16K + sidor / månad. Några av de händelser vi har pratat på har skapat några intressanta toppar:

Men erfarenheten på webbplatsen var fortfarande tillräckligt bra. Att ladda våra scener gjordes inte vid stjärnhastighet, men användarna klagade inte så mycket.

Men nyligen beslutade en cool kille att dela vårt arbete med Hacker News. Vi var verkligen glada för sådana nyheter! Men titta på vad som hände med webbplatsens anslutningar:

Spel över för vår lilla server! Det slutade långsamt att fungera, och erfarenheten för våra användare var riktigt dålig. IIS-servern spenderade sin tid på att betjäna stora statiska tillgångar och bilder, och CPU-användningen var för hög. När vi skulle starta Assassin's Creed Pirates WebGL-upplevelseprojektet som kördes på Babylon.js var det dags att byta till en mer skalbar professionell värd genom att använda en molnlösning.

Men innan vi granskar våra värdval, låt oss kortfattat prata om specifikationerna för vår motor och hemsida:

  1. Allt är statiskt på vår hemsida. Vi har för närvarande inte någon server-sidkod som körs.
  2. Våra scener (.Babylon JSON-filer) och texturer (.png eller .jpeg) -filer kan vara mycket stora (upp till 100 MB). Det betyder att vi absolut behövde aktivera gzip-komprimering på våra .babylon-scenfiler. I själva verket kommer prissättningen att indexeras mycket på den utgående bandbredden.
  3. Att skriva in i WebGL-kanfasen behöver särskilda säkerhetskontroller. Du kan inte ladda våra scener och texturer från en annan server utan CORS aktiverad, till exempel.

Credits: Jag skulle vilja speciellt tacka Benjamin Talmard, en av vår franska Azure tekniska evangelist som hjälpte oss att flytta till Azure.

1. Flytta till Azure Web Sites & Autoscale Service

Eftersom vi skulle vilja tillbringa större delen av vår tid på att skriva kod och funktioner för vår motor vill vi inte förlora tid på VVS. Därför beslutade vi omedelbart att välja ett PaaS-tillvägagångssätt och inte en IaaS-en.

Dessutom gillade vi Visual Studio integration med Azure. Jag kan göra nästan allt från min favorit IDE. Och även om Babylon.js är värd på GitHub använder vi Visual Studio 2013, TypeScript och Visual Studio Online för att koda vår motor. Som en anteckning för ditt projekt kan du få Visual Studio Community och en Azure Trial gratis.

Att flytta till Azure tog mig ungefär fem minuter:

  1. Jag skapade en ny webbplats på admin sidan: http://manage.windowsazure.com (kan också göras inom VS).  
  2. Jag tog rätt ändringar från vårt källkodsförråd som matchade den version som för närvarande var online.
  3. Jag högerklickade webbprojektet i Visual Studio Solution Explorer.

Nu här kommer verktygets awesomeness. När jag var inloggad i VS med hjälp av Microsoft-kontot som var bundet till min Azure-prenumeration, lät guiden mig helt enkelt välja den webbplats som jag skulle vilja distribuera.

Du behöver inte oroa dig för komplex autentisering, anslutningssträng eller vad som helst.

Nästa, Nästa, Nästa och Publicera"Och några minuter senare, på slutet av uppladdningsprocessen av alla våra tillgångar och filer, var webbplatsen igång!

På konfigurationssidan ville vi dra nytta av den fina autoscale-tjänsten. Det skulle ha hjälpt mycket i vårt tidigare Hacker News-scenario.

Först har din förekomst konfigurerats i Standard läge i Skala flik.

Då kan du välja upp till hur många instanser du vill automatiskt skala, i vilka CPU-förhållanden, och även på vilka schemalagda tider. 

I vårt fall har vi bestämt oss för att använda upp till tre små instanser (1 kärna, 1,75 GB minne) och att automatiskt kasta en ny instans om CPU går över 80% av användningen. Vi tar bort en instans om CPU faller under 60%. Autoscaling-mekanismen är alltid i vårt fall - vi har inte bestämt specifika schemalagda tider.

Tanken är verkligen att bara betala för vad du behöver under specifika tidsramar och belastningar. Jag älskar konceptet. Med det skulle vi ha kunnat hantera tidigare toppar genom att inte göra något tack vare denna Azure-service!

Du har också en snabb bild på autoskalans historia via lila diagrammet. I vårt fall, eftersom vi flyttat till Azure, gick vi aldrig över en instans hittills. Och vi ska se nedan hur man minimerar risken för att falla i en autoskalning.

För att sluta på webbkonfigurationen ville vi aktivera automatisk gzip-komprimering på våra specifika 3D-motorns resurser (.Babylon och .babylonmeshdata filer). Detta var kritiskt för oss eftersom det kunde spara upp till 3x bandbreddoch därmed ... priset.

Webbplatser körs på IIS. För att konfigurera IIS måste du gå in i web.config fil. Vi använder följande konfiguration i vårt fall:

                                    

Denna lösning fungerar ganska bra och vi märkte till och med att tiden för att ladda våra scener har minskat jämfört med vår tidigare värd. Jag antar att detta är tack vare den bättre infrastrukturen och nätverket som används av Azure datacenter.

Men jag har tänkt på att flytta mig till Azure ett tag nu. Och min första idé var inte att låta webbplatser instans tjäna mina stora tillgångar. Sedan början har jag varit mer intresserad av att lagra mina tillgångar i bloblagret som är bättre utformat för det. Det skulle också erbjuda oss ett möjligt CDN-scenario.

2. Flytta tillgångar till Azure Blob Storage, möjliggör CORS, Gzip Support & CDN

Den främsta orsaken till att du använder blob-lagring är att undvika att ladda CPU-enheten till våra webbplatser för att tjäna dem. Om allt serveras via blob-lagringsutrymmen förutom några HTML-, JavaScript- och CSS-filer, kommer våra webbplatser att få lite chanser att autoska.

Men detta väcker två problem att lösa:

  1. Eftersom innehållet kommer att vara värd för ett annat domännamn kommer vi att falla in i säkerhetsproblemet på flera olika områden. För att undvika det måste du aktivera CORS på fjärrdomänen (Azure Blob Storage).
  2. Azurblå Blob Storage stöder inte automatisk gzip-komprimering. Och vi vill inte sänka CPU-webbplatsens användning om vi i utbyte betalar tre gånger priset på grund av ökad bandbredd!

Aktiverar CORS på Blob Storage

CORS på blob storage har blivit stödda i några månader nu. Den här artikeln, Windows Azure Storage: Introducerar CORS, förklarar hur man använder Azure API för att konfigurera CORS. På min sida ville jag inte skriva en liten app för att göra det. Jag har hittat en på nätet som redan skrivits: Cynapta Azure CORS Helper - Gratis verktyg för att hantera CORS-regler för Windows Azure Blob Storage.

Jag aktiverade bara stödet till GET och riktiga rubriker på min behållare. För att kontrollera om allt fungerar som förväntat, öppna helt enkelt F12-utvecklingsfältet och kontrollera konsolloggarna:

Som du kan se innebär de gröna loggslinjerna att allt fungerar bra.

Här är ett exempelfall där det kommer att misslyckas. Om du försöker ladda våra scener från vår blob-lagring direkt från din lokala värdmaskin (eller någon annan domän) får du dessa fel i loggarna:

Sammanfattningsvis, om du ser att din anropsdomän inte finns i "Åtkomst-Control-allow-Origin"Rubrik med en"Åtkomst nekad"Strax efter det beror det på att du inte har satt dina CORS-regler korrekt. Det är mycket viktigt att kontrollera dina CORS-regler; annars kan alla använda dina tillgångar, och därmed din bandbredd, kosta pengar utan att låta dig veta det! 

Aktivera Gzip Support på vår Blob Storage

Som jag berättade förut för, Azure Blob Storage stöder inte automatisk gzip-komprimering. Det verkar också vara fallet med konkurrenters lösningar som S3. Du har två alternativ att arbeta kring det:

  1. Gzip filerna själv på klienten innan uppladdning, ladda upp det i bloblagret med dina klassiska verktyg och ställ in innehåll-kodning rubrik till gzip. Den här lösningen fungerar, men bara för webbläsare som stöder gzip (finns det fortfarande en webbläsare som inte stöder gzip?). 
  2. Gzip filerna själv på klienten och ladda upp två versioner i bloblagret: en med standard.förlängning och en med .extension.gzip, till exempel. Ställ in en hanterare på IIS-sidan som kommer att få HTTP-förfrågan från klienten, kolla efter rubriken acceptera-kodande satt till gzip och servera lämpliga filer baserat på detta stöd. Du hittar mer information om koden som ska implementeras i den här artikeln: Visning av GZip-komprimerat innehåll från Azure CDN.

I vårt fall vet jag inte någon webbläsare som stöder WebGL och inte gzip-komprimering. Så om webbläsaren inte stöder gzip är det inte riktigt intressant att gå längre, eftersom det förmodligen betyder att WebGL inte stöds antingen.

Jag har därför valt den första lösningen. Eftersom vi inte har många scener och vi inte producerar en ny varje dag använder jag för tillfället denna manualprocess:

  1. Med hjälp av 7-zip komprimerar jag.Babylon filer på min maskin med gzip-kodning och "kompressionsnivå"Till"snabbast”. De andra kompressionsnivåerna verkar generera problem i mina tester.
  2. Jag laddar upp filen med CloudBerry Explorer för Microsoft Azure Cloud Storage.
  3. Jag ställer in HTTP-rubriken manuellt innehåll-kodning till gzip med CloudBerry.

Jag vet vad du tänker. Ska jag göra det för alla mina filer?!? Nej, du kan arbeta med att bygga ett verktyg eller ett post-build-skript som skulle automatisera det. Till exempel, här är ett litet kommandoradsverktyg som jag har byggt:

sträng accountName = "yoda"; strängbehållareName = "wwwbabylonjs"; strängkontoKey = "yourmagickey"; sträng scenTextContent; // Första argumentet måste vara katalogen i Azure Blob Container-riktad strängkatalog = args [0]; prova StorageCredentials creds = nya 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); sträng [] filesArgs = args.Skip (1) .ToArray (); foreach (strängfilespec i filesArgs) string specdir = Path.GetDirectoryName (filespec); sträng specpart = Path.GetFileName (filespec); om (specdir.Length == 0) specdir = Environment.CurrentDirectory;  foreach (strängfil i Directory.GetFiles (specdir, specpart)) string path = Path.Combine (specdir, fil); sträng scenName = Path.GetFileName (sökväg); Console.WriteLine ("Working on" + scennamn + "..."); CloudBlockBlob blob = sceneDirectory.GetBlockBlobReference (scennamn); blob.Properties.ContentEncoding = "gzip"; blob.Properties.ContentType = "application / babylon"; sceneTextContent = System.IO.File.ReadAllText (bana); var bytes = Encoding.UTF8.GetBytes (sceneTextContent); använder (MemoryStream ms = new MemoryStream ()) använder (GZipStream gzip = nya GZipStream (ms, CompressionMode.Compress, true)) gzip.Write (byte, 0, bytes.Length);  ms.Position = 0; Console.WriteLine ("Gzip gjort."); blob.UploadFromStream (ms); Console.WriteLine ("Uppladdning i" + kontonamn + "/" + containernamn + "/" + katalog + "gjort.");  fångst (Undantag ex) Console.WriteLine (ex); 

För att kunna använda det kunde jag göra följande:

UploadAndGzipFilesToAzureBlobStorage Scenes / Espilit C: \ Boulot \ Babylon \ Scenes \ Espilit \* .Babylon * att driva en scen som innehåller flera filer (våra inkrementella scener med muliples .babylonmeshdata filer).

Eller bara:

UploadAndGzipFilesToAzureBlobStorage Scenes / Espilit C: \ Boulot \ Babylon \ Scenes \ Espilit \Espilit.babylon att trycka a unik fil.

För att kontrollera att gzip fungerade som förväntat med den här lösningen använder jag Fiddler. Ladda ditt innehåll från din klient maskin och kolla in nätverksspåren om innehållet som returneras komprimeras verkligen och kan komprimeras:

Aktiverar CDN

När du har gjort de två föregående stegen behöver du bara klicka på en enda knapp på Azures administrationssida för att aktivera CDN och mappa den till din blob-lagring:

Det är så enkelt! I mitt fall behöver jag helt enkelt ändra följande URL: http://yoda.blob.core.windows.net/wwwbabylonjs/Scenes to http://az612410.vo.msecnd.net/wwwbabylonjs/Scenes. Observera att du kan anpassa den här CDN-domänen själv om du vill.

Tack vare det kan vi betjäna dig våra 3D-tillgångar på ett mycket snabbt sätt, eftersom du kommer att serveras från en av de nodeplatser som listas här: Azure Content Delivery Network (CDN) Node Locations.

Vår webbplats är för närvarande värd för Nord-Europa Azur datacenter. Men om du kommer från Seattle, kommer du att pinga denna server bara för att ladda ner våra grundläggande index.html, index.js, index.css-filer och ett par skärmdumpar. Alla 3D-tillgångar kommer att serveras från Seattle-noden precis i närheten av dig!

Obs! Alla våra demo använder den fullt optimerade upplevelsen (blob-lagring med gzip, CDN och DB caching).

3. Använda HTML5 IndexedDB för att undvika att ladda ner tillgångarna igen

Optimering av laddningstider och kontroll av utmatningsbandbredd kostar inte bara server-sidan. Du kan också bygga en del logik-klientsidor för att optimera saker. Lyckligtvis har vi gjort det sedan v1.4 i vår Babylon.js-motor. Jag har förklarat i detalj hur jag har genomfört stödet till IndexedDB i den här artikeln: Använd IndexedDB för att hantera dina 3D WebGL-tillgångar: dela feedback och tips från Babylon.JS. Och du hittar hur du aktiverar den i Babylon.js på vår wiki: Caching resurser i IndexedDB.

I grund och botten behöver du bara skapa en .babylon.manifest fil som matchar namnet på .Babylon scenen och ställ in vad du vill cache (texturer och / eller JSON-scenen). Det är allt.

Titta t ex på vad som händer med Hill Valley demoscen. Första gången du laddar den, så är de begärda sändningarna:

153 objekt och 43,33 MB mottagna. Men om du har accepterat att låta babylonjs.com "använd extra lagring på din dator", Här är vad du ska se andra gången du laddar samma scen:

1 objekt och 348 byte! Vi kontrollerar bara om manifestfilen har ändrats. Om inte, laddar vi allt från DB och Vi sparar 43 + MB bandbredd.

Till exempel används detta tillvägagångssätt i Assassin's Creed Pirates-spel:

Låt oss tänka på det:

  • Spelet lanserar nästan omedelbart efter att den har laddats en gång, eftersom tillgångarna serveras direkt från den lokala DB.
  • Ditt webblagring är mindre stressat och mindre bandbredd används-kostar dig mindre pengar!

Nu kommer det att tillgodose både dina användare och din chef!

Den här artikeln är en del av web dev-tekniken från Microsoft. Vi är glada att dela Microsoft Edge och den nya EdgeHTML-återgivningsmotor med dig. Få gratis virtuella maskiner eller testa fjärran på din Mac, iOS, Android eller Windows-enheten @ http://dev.modern.ie/.