La structure de pile logicielle traditionnelle des applications en ligne Taobao est Nginx + Velocity + Java, c'est-à-dire:
Dans ce système, Nginx transmet la demande à une application Java, qui gère la transaction et rend les données dans la page finale à l'aide d'un modèle de vitesse.
Après avoir introduit Node.js, nous serons inévitablement confrontés aux problèmes suivants:
Comment concevoir la structure de topologie de la pile technologique et comment choisir la méthode de déploiement, est-elle considérée comme scientifique et raisonnable? Une fois le projet terminé, comment diviser le trafic, ce qui est pratique et rapide pour le fonctionnement et la maintenance? Lorsque vous rencontrez des problèmes en ligne, comment éliminer le danger dès que possible et éviter de plus grandes pertes? Comment assurer la santé de l'application et le gérer au niveau de la planification de l'équilibrage de la charge? Topologie du système
Selon notre réflexion et notre pratique sur la séparation des extrémités avant et arrière (II) - sur la base de l'exploration du modèle des extrémités avant et arrière, la vitesse doit être remplacée par Node.js, de sorte que cette structure devient:
C'est bien sûr l'objectif idéal. Cependant, la première introduction de la couche Node.js dans la pile traditionnelle est une nouvelle tentative après tout. Pour être en sécurité, nous avons décidé d'activer les nouvelles technologies sur la page Favoris (shoucang.taobao.com/item_collect.htm) de nos favoris, tandis que d'autres pages continuent d'utiliser des solutions traditionnelles. Autrement dit, Nginx détermine le type de page de la demande et détermine si la demande doit être transmise à Node.js ou Java. Ainsi, la structure finale est devenue:
Plan de déploiement
La structure ci-dessus semble être bien, mais en fait, le nouveau problème attend toujours le front. Dans la structure traditionnelle, Nginx et Java sont déployés sur le même serveur. Nginx écoute le port 80 et communique avec Java en écoutant le port 7001 à un bit élevé. Maintenant que Node.js est introduit, un nouveau processus qui doit exécuter un port d'écoute est nécessaire. NEUT NODE.JS devrait-il être déployé sur la même machine avec Nginx + Java, ou Node.js être déployé sur un cluster séparé?
Comparons les caractéristiques des deux méthodes:
Les favoris de Taobao sont une application avec un PV moyen quotidien de dizaines de millions, ce qui a des exigences extrêmement élevées de stabilité (en fait, l'instabilité en ligne de tout produit est inacceptable). Si vous adoptez la même solution de déploiement de cluster, vous n'avez besoin de distribuer des fichiers qu'une seule fois et de redémarrer deux fois pour terminer la version. Dans le cas où vous devez revenir en arrière, vous n'avez besoin d'exploiter le package de base. En termes de performances, le même déploiement de cluster présente également certains avantages théoriques (bien que la bande passante de commutation et la latence de l'intranet soient très optimistes). Quant à la relation un-à-plusieurs ou plusieurs à un, il peut théoriquement être plus entièrement utilisé par le serveur, mais par rapport aux exigences de stabilité, ce point n'est pas si urgent à résoudre. Ainsi, dans la transformation des favoris, nous avons choisi la même solution de déploiement de cluster.
Niveaux de gris
Afin d'assurer une stabilité maximale, cette transformation n'a pas complètement supprimé le code de vitesse complètement. Il y a près de 100 serveurs dans le cluster d'applications. Nous utilisons le serveur comme granularité et introduisons progressivement le trafic. En d'autres termes, bien que les processus Java + Node.js fonctionnent sur tous les serveurs, s'il existe des règles de transfert correspondantes sur Nginx détermine si la demande d'obtention de la collection de bébé sur ce serveur sera traitée via Node.js. La configuration de Nginx est:
location = "/item_collect.htm" {proxy_pass http://127.0.0.1:6001; # Node.js Processus d'écoute Port}Seuls les serveurs qui ont ajouté cette règle Nginx permettra à Node.js de gérer la demande correspondante. Grâce à la configuration de Nginx, il est très pratique et rapide à augmenter et à réduire le trafic en niveaux de gris, et le coût est très faible. Si vous rencontrez des problèmes, vous pouvez faire reculer directement la configuration Nginx et revenir instantanément à la structure de pile technologique traditionnelle pour soulager le danger.
Lorsque nous avons sorti pour la première fois, nous n'avons activé cette règle que sur deux serveurs, ce qui signifie que moins de 2% du trafic en ligne est traité dans Node.js, et les demandes de trafic restant sont toujours rendues par vitesse. À l'avenir, le trafic sera progressivement augmenté en fonction de la situation, et enfin au cours de la troisième semaine, tous les serveurs seront activés. À ce stade, les pages de collecte de produits avec 100% de trafic dans l'environnement de production sont rendues par Node.js (vous pouvez vérifier le code source pour rechercher le mot-clé Node.js).
changement
Le processus de niveaux de gris n'est pas lisse. Avant de couper le débit en totalité, j'ai rencontré des problèmes, qu'ils soient grands ou petits. La majeure partie de l'entreprise est liée à des entreprises spécifiques, et ce qui vaut la peine d'être appris est un piège lié aux détails techniques.
Chèque de santé
Dans l'architecture traditionnelle, le système de planification d'équilibrage de charge lancera une demande get à chaque seconde à une URL spécifique sur le port 80 de chaque serveur et déterminera si le serveur fonctionne normalement en fonction de la question de savoir si le code d'état HTTP renvoyé est 200 . Si le délai d'attente après 1 est demandé ou que le code d'état HTTP n'est pas 200 , aucun trafic n'est introduit sur le serveur pour éviter les problèmes en ligne.
Le chemin d'accès à cette demande est nginx -> java -> nginx, ce qui signifie que tant que 200 est renvoyé, le nginx et le java de ce serveur sont dans un état sain. Après avoir introduit Node.js, ce chemin devient nginx -> node.js -> java -> node.js -> nginx. Le code correspondant est:
var http = require ('http'); app.get ('/ status.taobao', fonction (req, res) {http.get ({host: '127.1', port: 7001, chemin: '/status.taobao'}, fonction (res) {res.send (res.status.tatusde);}). Sur ('error', function (err) {logger.orror (err); re-of (404); });});Cependant, pendant le processus de test, il a été constaté que lorsque Node.js transmet de telles demandes, il a fallu plusieurs secondes, voire dix secondes pour obtenir le retour de Java une fois tous les six ou sept fois. Cela entraînera la pensée du système de planification d'équilibrage de charge qu'une anomalie s'est produite sur le serveur, puis coupe le trafic, mais en fait, le serveur peut fonctionner normalement. C'est évidemment un gros problème.
Après une recherche, j'ai constaté que par défaut, Node.js utilisera la classe HTTP Agent pour créer des connexions HTTP. Cette classe implémente un pool de connexion à socket. La limite supérieure par défaut du nombre de connexions pour chaque paire de ports hôte + est 5. En même temps, les demandes initiées par HTTP Agent incluent Connection: Keep-Alive par défaut, ce qui entraîne la connexion retournée non publiée dans le temps, et les demandes initiées ultérieurement ne peuvent être que la file d'attente.
Il existe trois solutions finales:
Désactiver HTTP Agent , c'est-à-dire Ajouter agent: false lors de l'appel de la méthode get , et le code final est:
var http = require ('http'); app.get ('/ status.taobao', fonction (req, res) {http.get ({hôte: '127.1', port: 7001, agent: false, chemin: '/status.taobao'}, fonction (res) {res.send (res.status.aror);}). sur ('error', fonction (err) {logger.error (err). res.send (404);});}); Définissez la limite supérieure du numéro de socket global d'objets http :
http.globalagent.maxsockets = 1000;
Lorsque la demande revient, elle est déconnectée et proactive:
http.get (options, fonction (res) {}). sur ("socket", fonction (socket) {socket.emit ("agentremove"); // écouter les événements de socket et répartir les événements AGentRemove dans le rappel});En pratique, nous avons choisi la première méthode. Après cet ajustement, aucun autre problème n'a été trouvé dans l'examen de santé.
combiner
La pratique de la combinaison de Node.js avec des scénarios commerciaux traditionnels vient de commencer, et il y a encore beaucoup de points d'optimisation à explorer en profondeur. Par exemple, une fois les applications Java entièrement centralisées, pouvez-vous passer le test du déploiement de cluster pour améliorer l'utilisation du serveur? Ou, les méthodes de libération et de recul peuvent-elles être plus flexibles et contrôlables? Tous les détails méritent une recherche plus approfondie.