Pourquoi et comment nous avons migré Babylon.js en Azure

Vous travaillez pour une startup. Soudainement, cette année difficile de codage porte ses fruits: avec le succès, plus de croissance et de demande pour que votre application Web évolue.

Dans ce tutoriel, je souhaite utiliser avec humilité l'une de nos plus récentes «réussites» autour de notre structure de jeu open source WebGL, Babylon.js, et de son site Web. Nous avons été ravis de voir autant de développeurs de jeux sur Internet l'essayer. Mais pour faire face à la demande, nous savions qu'il nous fallait une nouvelle solution d'hébergement Web.. 

Bien que ce didacticiel se concentre sur Microsoft Azure, de nombreux concepts s’appliquent à diverses solutions que vous préférez peut-être. Nous allons également voir les différentes optimisations que nous avons mises en place pour limiter autant que possible la bande passante de sortie de nos serveurs vers votre navigateur..

introduction

Babylon.js est un projet personnel sur lequel nous travaillons depuis plus d'un an maintenant. Comme il s’agit d’un projet personnel (c’est-à-dire notre temps et notre argent), nous avons hébergé le site Web, les textures et les scènes 3D sur une solution d’hébergement relativement économique, au moyen d’une petite machine Windows / IIS dédiée. Le projet a démarré en France, mais a rapidement attiré l’attention de plusieurs spécialistes de la 3D et du Web du monde entier, ainsi que de certains studios de jeux. Nous étions heureux des retours de la communauté, mais le trafic était gérable!

Par exemple, entre février 2014 et avril 2014, nous avions une moyenne de 7 000 utilisateurs / mois avec une moyenne de 16 000 pages vues / mois. Certains des événements auxquels nous avons parlé ont généré des pics intéressants:

Mais l'expérience sur le site Web était encore suffisante. Charger nos scènes ne se faisait pas à une vitesse incroyable, mais les utilisateurs ne se plaignaient pas trop.

Cependant, récemment, un gars cool a décidé de partager notre travail sur Hacker News. Nous étions vraiment heureux pour de telles nouvelles! Mais regardez ce qui est arrivé aux connexions du site:

Jeu terminé pour notre petit serveur! Cela a lentement cessé de fonctionner et l'expérience de nos utilisateurs a été vraiment mauvaise. Le serveur IIS passait son temps à desservir de grandes ressources et images statiques et l'utilisation du processeur était trop élevée. Alors que nous étions sur le point de lancer le projet d'expérience WebGL d'Assassin's Creed Pirates fonctionnant sur Babylon.js, il était temps de passer à un hébergement professionnel plus évolutif en utilisant une solution cloud..

Mais avant de revoir nos choix d’hébergement, parlons brièvement des spécificités de notre moteur et de notre site Web:

  1. Tout est statique sur notre site. Nous n'avons actuellement aucun code côté serveur en cours d'exécution.
  2. Nos fichiers de scènes (fichiers JSON .babylon) et de textures (.png ou .jpeg) peuvent être très volumineux (jusqu’à 100 Mo). Cela signifie que nous devions absolument activer la compression gzip sur nos fichiers de scène .babylon. En effet, dans notre cas, la tarification va être beaucoup indexée sur la bande passante sortante.
  3. Dessiner dans le canevas WebGL nécessite des contrôles de sécurité spéciaux. Vous ne pouvez pas charger nos scènes et textures depuis un autre serveur sans CORS, par exemple.

Crédits: Je voudrais remercier spécialement Benjamin Talmard, un de nos évangélistes techniques français Azure qui nous a aidés à nous installer à Azure.

1. Déplacement vers les sites Web Azure et le service Autoscale

Comme nous aimerions passer le plus clair de notre temps à écrire du code et des fonctionnalités pour notre moteur, nous ne voulons pas perdre de temps sur la plomberie. C’est pourquoi nous avons immédiatement décidé de choisir une approche PaaS et non pas IaaS..

De plus, nous avons aimé l'intégration de Visual Studio avec Azure. Je peux faire presque tout de mon IDE préféré. Et même si Babylon.js est hébergé sur GitHub, nous utilisons Visual Studio 2013, TypeScript et Visual Studio Online pour coder notre moteur. Pour votre projet, vous pouvez obtenir gratuitement la communauté Visual Studio et une version d'évaluation Azure..

Déménager à Azure m'a pris environ cinq minutes:

  1. J'ai créé un nouveau site Web dans la page d'administration: http://manage.windowsazure.com (peut également être créé à l'intérieur de VS).  
  2. J'ai pris le bon ensemble de modifications de notre référentiel de code source correspondant à la version actuellement en ligne.
  3. J'ai cliqué avec le bouton droit sur le projet Web dans l'Explorateur de solutions Visual Studio..

Maintenant, voici la génialité de l'outillage. Comme j'étais connecté à VS en utilisant le compte Microsoft lié à mon abonnement Azure, l'assistant me laissait simplement choisir le site Web sur lequel je souhaitais déployer..

Pas besoin de s'inquiéter d'une authentification complexe, d'une chaîne de connexion ou de quoi que ce soit.

Suivant, Suivant, Suivant et Publier”Et quelques minutes plus tard, à la fin du processus de téléchargement de tous nos actifs et fichiers, le site Web était opérationnel.!

Du côté de la configuration, nous voulions profiter du service sympa à l’échelle automatique. Cela aurait beaucoup aidé dans notre précédent scénario Hacker News.

Tout d'abord, votre instance a été configurée dans la norme mode dans le Échelle languette.

Ensuite, vous pouvez choisir jusqu'à combien d'instances vous souhaitez automatiquement mettre à l'échelle, dans quelles conditions de la CPU, et aussi sur quelles heures planifiées. 

Dans notre cas, nous avons décidé d'utiliser jusqu'à trois petites instances (1 cœur, 1,75 Go de mémoire) et de générer automatiquement une nouvelle instance si le processeur dépasse 80% de son utilisation. Nous allons supprimer une instance si le processeur tombe sous 60%. Le mécanisme de mise à l'échelle automatique est toujours activé dans notre cas - nous n'avons pas défini d'heures programmées spécifiques.

L’idée est vraiment de ne payez que ce dont vous avez besoin pendant des délais et des charges spécifiques. J'aime le concept. Grâce à cela, nous aurions pu gérer les pics précédents sans rien faire grâce à ce service Azure.!

Vous avez également un aperçu rapide de l'historique de la mise à l'échelle automatique via le graphique violet. Dans notre cas, depuis que nous avons migré vers Azure, nous n’avons jamais traité d’instance à ce jour. Et nous allons voir ci-dessous comment minimiser le risque de tomber dans une mise à l'échelle automatique.

Pour conclure sur la configuration du site Web, nous voulions activer la compression gzip automatique sur nos ressources moteur 3D spécifiques (.Babylone et .babylonmeshdata des dossiers). C’était essentiel pour nous, car cela permettrait d’économiser jusqu’à 3 fois la bande passante.et donc… le prix.

Les sites Web fonctionnent sur IIS. Pour configurer IIS, vous devez accéder à la web.config fichier. Nous utilisons la configuration suivante dans notre cas:

                                    

Cette solution fonctionne plutôt bien et nous avons même remarqué que le temps nécessaire pour charger nos scènes a été réduit par rapport à celui de notre hôte précédent. Je suppose que c'est grâce à la meilleure infrastructure et au meilleur réseau utilisés par les centres de données Azure..

Toutefois, je réfléchis depuis longtemps à la migration vers Azure. Et ma première idée n’a pas été de laisser les instances de sites Web servir mes grands actifs. Depuis le début, je suis plus intéressé par le stockage de mes actifs dans le stockage d'objets blob mieux conçu pour cela. Cela nous offrirait également un scénario CDN possible.

2. Déplacement d’actifs dans le stockage Azob Blob, activation de CORS, support Gzip et CDN

La principale raison d'utiliser le stockage d'objets blob dans notre cas est d'éviter de charger le CPU des instances de notre site Web pour les servir. Si tout est desservi via le stockage d'objets blob à l'exception de quelques fichiers HTML, JavaScript et CSS, les instances de notre site Web auront peu de chances d'être mises à l'échelle automatiquement..

Mais cela soulève deux problèmes à résoudre:

  1. Comme le contenu sera hébergé sur un autre nom de domaine, nous tomberons dans le problème de la sécurité entre domaines. Pour éviter cela, vous devez activer CORS sur le domaine distant (Stockage de blob Azure).
  2. Azur Blob Storage ne supporte pas la compression automatique gzip. Et nous ne voulons pas réduire l'utilisation du site Web du processeur si, en contrepartie, nous payons trois fois plus cher en raison de l'augmentation de la bande passante!

Activation du stockage CORS sur blob

Le stockage CORS sur blob est pris en charge depuis quelques mois maintenant. Cet article, Stockage Windows Azure: présentation de CORS, explique comment utiliser les API Azure pour configurer CORS. De mon côté, je ne voulais pas écrire une petite application pour faire ça. J'en ai trouvé un sur le Web déjà écrit: Cynapta Azure CORS Helper - Outil gratuit pour gérer les règles CORS pour Windows Azure Blob Storage.

Je viens alors d'activer le support pour GET et les en-têtes appropriés sur mon conteneur. Pour vérifier si tout fonctionne comme prévu, ouvrez simplement la barre de développement F12 et consultez les journaux de la console:

Comme vous pouvez le constater, les lignes de journal vert indiquent que tout fonctionne bien.

Voici un exemple de cas où cela échouera. Si vous essayez de charger nos scènes à partir de notre stockage d'objets blob directement à partir de votre ordinateur localhost (ou de tout autre domaine), vous obtiendrez ces erreurs dans les journaux:

En conclusion, si vous voyez que votre domaine d’appel n’est pas trouvé dans le "Access-Control-Allow-Origin"En-tête avec un"L'accès est refusé"Juste après, c'est parce que vous n'avez pas défini correctement vos règles CORS. Il est très important de contrôler vos règles CORS; sinon, tout le monde pourrait utiliser vos ressources, et donc votre bande passante, pour un coût élevé sans que vous en soyez informé.! 

Activation du support Gzip sur notre stockage blob

Comme je te le disais avant, Azure Blob Storage ne prend pas en charge la compression automatique gzip. Cela semble également être le cas des solutions de concurrents telles que S3. Vous avez deux options pour contourner ce problème:

  1. Gzip les fichiers toi même sur le client avant de télécharger, téléchargez-le dans le stockage de blob en utilisant vos outils classiques et définissez la codage du contenu en-tête de gzip. Cette solution fonctionne, mais uniquement pour les navigateurs supportant gzip (existe-t-il encore un navigateur ne supportant pas gzip?). 
  2. Gzip les fichiers vous-même sur le client et télécharger deux versions dans le stockage blob: un avec le défaut.extension et un avec le .extension.gzip, par exemple. Configurez un gestionnaire du côté IIS qui capturera la requête HTTP du client, recherchez l'en-tête. accept-encoding mis à gzip et servir les fichiers appropriés en fonction de ce support. Vous trouverez plus de détails sur le code à implémenter dans cet article: Gestion du contenu compressé GZip à partir du CDN Azure.

Dans notre cas, je ne connais aucun navigateur prenant en charge WebGL ni la compression gzip. Donc, si le navigateur ne supporte pas gzip, il n'y a aucun intérêt réel à aller plus loin, car cela signifie probablement que WebGL n'est pas non plus supporté..

J'ai donc choisi la première solution. Comme nous n'avons pas beaucoup de scènes et que nous n'en produisons pas de nouvelles tous les jours, j'utilise actuellement ce processus manuel:

  1. En utilisant 7-zip, je compresse le.Babylone fichiers sur ma machine en utilisant l’encodage gzip et “niveau de compression" à "le plus rapide” Les autres niveaux de compression semblent générer des problèmes dans mes tests.
  2. Je télécharge le fichier à l'aide de CloudBerry Explorer pour Microsoft Azure Cloud Storage.
  3. Je définis manuellement l'en-tête HTTP codage du contenu à gzip avec CloudBerry.

Je sais ce que tu penses. Est-ce que je vais faire ça pour tous mes fichiers?!? Non, vous pouvez créer un outil ou un script post-build qui automatiserait cela. Par exemple, voici un petit outil de ligne de commande que j'ai construit:

string accountName = "yoda"; string containerName = "wwwbabylonjs"; string accountKey = "votremagickey"; string sceneTextContent; // Le premier argument doit être le répertoire de la chaîne ciblée du conteneur Azure Blob Container directory = args [0]; try StorageCredentials creds = new StorageCredentials (accountName, accountKey); Compte CloudStorageAccount = new CloudStorageAccount (creds, useHttps: true); Client CloudBlobClient = account.CreateCloudBlobClient (); CloudBlobContainer blobContainer = client.GetContainerReference (containerName); blobContainer.CreateIfNotExists (); var sceneDirectory = blobContainer.GetDirectoryReference (répertoire); string [] filesArgs = args.Skip (1) .ToArray (); foreach (string spécifie dans filesArgs) string spécdir = Path.GetDirectoryName (filespec); string specpart = Path.GetFileName (filespec); if (spécdir.Length == 0) specdir = Environment.CurrentDirectory;  foreach (fichier de chaîne dans Directory.GetFiles (spécdir, spécpart)) string path = Path.Combine (spécdir, fichier); string sceneName = Path.GetFileName (path); Console.WriteLine ("Travailler sur" + 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 (octets, 0, octets.Longueur);  ms.Position = 0; Console.WriteLine ("Gzip terminé."); blob.UploadFromStream (ms); Console.WriteLine ("Téléchargement dans" + nom du compte + "/" + nom du conteneur + "/" + répertoire + "terminé.");  catch (Exception ex) Console.WriteLine (ex); 

Pour l'utiliser, je pourrais faire ce qui suit:

UploadAndGzipFilesToAzureBlobStorage Scenes / Espilit C: \ Boulot \ Babylon \ Scenes \ Espilit \*.Babylone* pousser une scène contenant plusieurs fichiers (nos scènes incrémentales avec de multiples principes .babylonmeshdata des dossiers).

Ou simplement:

UploadAndGzipFilesToAzureBlobStorage Scenes / Espilit C: \ Boulot \ Babylon \ Scenes \ Espilit \Espilit.babylon pousser un fichier unique.

Pour vérifier que gzip fonctionnait comme prévu avec cette solution, j'utilise Fiddler. Chargez votre contenu à partir de votre ordinateur client et vérifiez dans les traces réseau si le contenu renvoyé est réellement compressé et peut être décompressé:

Activer le CDN

Une fois que vous avez effectué les deux étapes précédentes, il vous suffit de cliquer sur un seul bouton de la page d'administration Azure pour activer CDN et le mapper sur votre stockage d'objets blob:

C'est si simple! Dans mon cas, je dois simplement changer l'URL suivante: http://yoda.blob.core.windows.net/wwwbabylonjs/Scenes en http://az612410.vo.msecnd.net/wwwbabylonjs/Scenes. Notez que vous pouvez personnaliser ce domaine CDN à votre propre si vous voulez.

Grâce à cela, nous sommes en mesure de vous servir nos ressources 3D de manière très rapide, car vous serez servi à partir de l'un des emplacements de nœud répertoriés ci-dessous: Emplacements de nœud Azure Content Delivery Network (CDN).

Notre site Web est actuellement hébergé sur le centre de données Azure Europe du Nord. Mais si vous venez de Seattle, envoyez une requête ping à ce serveur simplement pour télécharger nos fichiers index.html, index.js, index.css de base et quelques captures d'écran. Tous les éléments 3D seront servis à partir du noeud Seattle situé près de chez vous.!

Remarque: toutes nos démonstrations utilisent l'expérience totalement optimisée (stockage d'objets blob à l'aide de la mise en cache gzip, CDN et DB)..

3. Utilisation de HTML5 IndexedDB pour éviter de télécharger à nouveau les actifs

Optimiser les temps de chargement et maîtriser les coûts de bande passante de sortie ne concerne pas que le serveur. Vous pouvez également créer une logique côté client pour optimiser les opérations. Heureusement, nous le faisons depuis la v1.4 de notre moteur Babylon.js. J'ai expliqué en détail comment j'ai implémenté le support pour IndexéDB dans cet article: Utilisation d’IndexedDB pour gérer vos actifs 3D WebGL: partage des commentaires et des astuces de Babylon.JS. Et vous trouverez comment l'activer dans Babylon.js sur notre wiki: Mise en cache des ressources dans IndexedDB.

Fondamentalement, il vous suffit de créer un .babylon.manifest fichier correspondant au nom du .Babylone scène, puis définissez ce que vous souhaitez mettre en cache (textures et / ou scène JSON). C'est tout.

Par exemple, vérifiez ce qui se passe sur la scène de démonstration de Hill Valley. La première fois que vous le chargez, voici les demandes envoyées:

153 éléments et 43,33 Mo reçus. Mais si vous avez accepté de laisser babylonjs.com “utiliser de l'espace de stockage supplémentaire sur votre ordinateur”, Voici ce que vous verrez la deuxième fois que vous chargerez la même scène:

1 élément et 348 octets! Nous vérifions simplement si le fichier manifeste a changé. Sinon, nous chargeons tout de la base de données et nous économisons plus de 43 Mo de bande passante.

Par exemple, cette approche est utilisée dans les jeux Assassin's Creed Pirates:

Pensons à ce sujet:

  • Le jeu lance presque immédiatement une fois chargé, car les actifs sont servis directement à partir de la base de données locale.
  • Votre stockage Web est moins stressé et vous utilisez moins de bande passante-vous coûter moins cher!

Maintenant, cela satisfera à la fois vos utilisateurs et votre patron!

Cet article fait partie de la série Web de développement Web de Microsoft. Nous sommes ravis de partager Microsoft Edge et le nouveau Moteur de rendu EdgeHTML avec toi. Obtenez des machines virtuelles gratuites ou testez à distance sur votre appareil Mac, iOS, Android ou Windows @ http://dev.modern.ie/.