Maison > interface Web > js tutoriel > le corps du texte

Utiliser Node.js avec Nginx pour implémenter network_node.js à charge élevée

WBOY
Libérer: 2016-05-16 15:52:32
original
1259 Les gens l'ont consulté

Lorsqu'il s'agit de créer des applications Web à haut débit, NginX et Node.js se marient naturellement. Ils sont tous conçus sur la base du modèle événementiel et peuvent facilement surmonter le goulot d'étranglement C10K des serveurs Web traditionnels tels qu'Apache. La configuration par défaut peut déjà atteindre une simultanéité élevée, mais si vous souhaitez atteindre plus de milliers de requêtes par seconde sur du matériel bon marché, il reste encore du travail à faire.

Cet article suppose que les lecteurs utilisent le HttpProxyModule de NginX pour agir comme proxy inverse pour le serveur node.js en amont. Nous présenterons le réglage de sysctl dans les systèmes Ubuntu 10.04 et supérieurs, ainsi que le réglage des applications node.js et NginX. Bien sûr, si vous utilisez un système Debian, vous pouvez également atteindre le même objectif, mais les méthodes de réglage sont différentes.

Réglage du réseau

Si vous ne comprenez pas d'abord les mécanismes de transmission sous-jacents de Nginx et Node.js et n'effectuez pas une optimisation ciblée, aussi détaillée que soit l'optimisation des deux, cela peut être en vain. Normalement, Nginx connecte le client et les applications en amont via des sockets TCP.

Notre système dispose de nombreux seuils et restrictions pour TCP, qui sont définis via les paramètres du noyau. Les valeurs par défaut de ces paramètres sont souvent définies à des fins générales et ne peuvent pas répondre aux exigences de trafic élevé et de courte durée de vie des serveurs Web.


Voici quelques paramètres candidats au réglage de TCP. Pour les rendre efficaces, vous pouvez les placer dans le fichier /etc/sysctl.conf ou les placer dans un nouveau fichier de configuration, tel que /etc/sysctl.d/99-tuning.conf, puis exécuter sysctl -p pour laissez le noyau les charger. Nous utilisons sysctl-cookbook pour effectuer ce travail physique.

Il convient de noter que les valeurs répertoriées ici sont sûres à utiliser, mais il est tout de même recommandé d'étudier la signification de chaque paramètre afin de choisir une valeur plus appropriée en fonction de votre charge, de votre matériel et de votre utilisation.

Copier le code Le code est le suivant :
net.ipv4.ip_local_port_range='1024 65000'
net.ipv4.tcp_tw_reuse='1'
net.ipv4.tcp_fin_timeout='15'
net.core.netdev_max_backlog='4096'
net.core.rmem_max='16777216'
net.core.somaxconn='4096'
net.core.wmem_max='16777216'
net.ipv4.tcp_max_syn_backlog='20480'
net.ipv4.tcp_max_tw_buckets='400000'
net.ipv4.tcp_no_metrics_save='1'
net.ipv4.tcp_rmem='4096 87380 16777216'
net.ipv4.tcp_syn_retries='2'
net.ipv4.tcp_synack_retries='2'
net.ipv4.tcp_wmem='4096 65536 16777216'
vm.min_free_kbytes='65536'

Soulignez-en quelques-uns importants.

Copier le code Le code est le suivant :
net.ipv4.ip_local_port_range

Afin de servir le client en aval pour l'application en amont, NginX doit ouvrir deux connexions TCP, une vers le client et une vers l'application. Lorsqu'un serveur reçoit de nombreuses connexions, les ports disponibles du système seront rapidement épuisés. En modifiant le paramètre net.ipv4.ip_local_port_range, vous pouvez augmenter la plage de ports disponibles. Si une telle erreur est trouvée dans /var/log/syslog : "possible SYN Flooding sur le port 80. Envoi de cookies", cela signifie que le système ne trouve pas de port disponible. L'augmentation du paramètre net.ipv4.ip_local_port_range peut réduire cette erreur.

Copier le code Le code est le suivant :
net.ipv4.tcp_tw_reuse

Lorsque le serveur doit basculer entre un grand nombre de connexions TCP, un grand nombre de connexions à l'état TIME_WAIT seront générées. TIME_WAIT signifie que la connexion elle-même est fermée, mais que les ressources n'ont pas été libérées. Définir net_ipv4_tcp_tw_reuse sur 1 permet au noyau d'essayer de recycler les connexions lorsque cela est sûr, ce qui est beaucoup moins cher que de rétablir de nouvelles connexions.

Copier le code Le code est le suivant :
net.ipv4.tcp_fin_timeout

Il s'agit du temps minimum qu'une connexion dans l'état TIME_WAIT doit attendre avant de recycler. Le rendre plus petit peut accélérer le recyclage.
Comment vérifier l'état de la connexion

Utilisez netstat :

Copier le code Le code est le suivant :
netstat -tan awk '{print $6}' | trier | uniq -c

ou utilisez ss :

Copier le code Le code est le suivant :
ss -s

NginX

À mesure que la charge sur le serveur Web augmente progressivement, nous commencerons à rencontrer d'étranges limitations de NginX. La connexion est interrompue et le noyau continue de signaler une inondation SYN. À l'heure actuelle, la charge moyenne et l'utilisation du processeur sont très faibles, et le serveur peut évidemment gérer plus de connexions, ce qui est vraiment frustrant.

Après enquête, il a été constaté qu'il existe de nombreuses connexions dans l'état TIME_WAIT. Voici le résultat de l'un des serveurs :

Copier le code Le code est le suivant :
ss -s
Total : 388 (noyau 541)
TCP : 47461 (estab 311, fermé 47135, orphelin 4, synrecv 0, timewait 47135/0), ports 33938

Transport IP total IPv6
*541 - - -
BRUT 0 0 0 0
UDP 13 10 3
TCP 326 325 1
INET 339 335 4
FRAG 0 0 0 0


Il y a 47 135 connexions TIME_WAIT ! De plus, on peut voir d'après ss qu'il s'agit toutes de connexions fermées. Cela indique que le serveur a consommé la plupart des ports disponibles et implique également que le serveur alloue de nouveaux ports pour chaque connexion. Le réglage du réseau a quelque peu aidé à résoudre le problème, mais il n'y avait toujours pas assez de ports.

Après des recherches plus approfondies, j'ai trouvé un document sur la commande uplink keepalive, qui se lit comme suit :

  • Définissez le nombre maximum de connexions persistantes inactives au serveur en amont. Ces connexions seront conservées dans le cache du processus de travail.

Intéressant. En théorie, cette configuration minimise le gaspillage de connexions en transmettant les requêtes via les connexions mises en cache. La documentation mentionne également que nous devons définir proxy_http_version sur "1.1" et effacer l'en-tête "Connexion". Après des recherches plus approfondies, j'ai trouvé que c'était une bonne idée, car HTTP/1.1 optimise considérablement l'utilisation des connexions TCP par rapport à HTTP1.0 et Nginx utilise HTTP/1.0 par défaut.

Après modification comme suggéré dans le document, notre fichier de configuration de liaison montante devient comme ceci :

Copier le code Le code est le suivant :
upstream backend_nodejs {
serveur nodejs-3:5016 max_fails=0 fail_timeout=10s;
serveur nodejs-4:5016 max_fails=0 fail_timeout=10s;
serveur nodejs-5:5016 max_fails=0 fail_timeout=10s;
serveur nodejs-6:5016 max_fails=0 fail_timeout=10s;
rester en vie 512;
>

J'ai également modifié les paramètres du proxy dans la section serveur comme suggéré. Dans le même temps, un proxy_next_upstream a été ajouté pour ignorer les serveurs défaillants, le keepalive_timeout du client a été ajusté et le journal d'accès a été désactivé. La configuration devient comme ceci :

Copier le code Le code est le suivant :
serveur {
écoute 80 ;
nom_serveur fast.gosquared.com;

client_max_body_size 16M;
keepalive_timeout 10;

emplacement / {
proxy_next_upstream délai d'attente d'erreur http_500 http_502 http_503 http_504;
proxy_set_header Connexion "";
​ proxy_http_version 1.1;
proxy_pass http://backend_nodejs;
>

access_log off;
error_log /dev/null crit;
>

Après avoir adopté la nouvelle configuration, j'ai constaté que les sockets occupés par les serveurs étaient réduits de 90%. Les requêtes peuvent désormais être transmises en utilisant beaucoup moins de connexions. La nouvelle sortie est la suivante :

Copier le code Le code est le suivant :
ss -s

Total : 558 (noyau 604)
TCP : 4675 (estab 485, fermé 4183, orphelin 0, synrecv 0, timewait 4183/0), ports 2768

Transport IP total IPv6
*604 - - -
BRUT 0 0 0 0
UDP 13 10 3
TCP4924911
INET 505 501 4

Node.js

Grâce à la conception basée sur les événements qui gère les E/S de manière asynchrone, Node.js peut gérer un grand nombre de connexions et de requêtes dès le départ. Bien qu'il existe d'autres méthodes de réglage, cet article se concentrera principalement sur l'aspect processus de node.js.

Le nœud est monothread et n'utilise pas automatiquement plusieurs cœurs. En d’autres termes, l’application ne peut pas obtenir automatiquement toutes les capacités du serveur.

Réaliser le clustering des processus Node

Nous pouvons modifier l'application pour qu'elle crée plusieurs threads et reçoive des données sur le même port, permettant ainsi à la charge de s'étendre sur plusieurs cœurs. Node dispose d'un module cluster qui fournit tous les outils nécessaires pour atteindre cet objectif, mais les ajouter à l'application nécessite beaucoup de travail manuel. Si vous utilisez express, eBay dispose d'un module appelé cluster2 qui peut être utilisé.

Empêcher le changement de contexte

Lors de l'exécution de plusieurs processus, vous devez vous assurer que chaque cœur de processeur n'est occupé que par un seul processus à la fois. De manière générale, si le CPU possède N cœurs, nous devons générer N-1 processus d’application. Cela garantit que chaque processus bénéficie d'une tranche de temps raisonnable, laissant un cœur libre pour que le planificateur du noyau puisse exécuter d'autres tâches. Nous devons également nous assurer qu'aucune autre tâche autre que Node.js n'est exécutée sur le serveur pour éviter les conflits de CPU.

Nous avons commis une erreur une fois et déployé deux applications node.js sur le serveur, puis chaque application a ouvert N-1 processus. En conséquence, ils se font concurrence pour le processeur, ce qui entraîne une forte augmentation de la charge du système. Bien que nos serveurs soient tous des machines à 8 cœurs, la surcharge de performances causée par le changement de contexte peut toujours être clairement ressentie. Le changement de contexte fait référence au phénomène par lequel le processeur suspend la tâche en cours afin d'effectuer d'autres tâches. Lors du changement, le noyau doit suspendre tout état du processus en cours, puis charger et exécuter un autre processus. Pour résoudre ce problème, nous avons réduit le nombre de processus démarrés par chaque application afin qu'elles puissent partager équitablement le CPU. En conséquence, la charge du système a été réduite :
.

2015628112206774.png (802×404)

Veuillez prêter attention à l'image ci-dessus pour voir comment la charge du système (ligne bleue) descend en dessous du nombre de cœurs de processeur (ligne rouge). Sur d'autres serveurs, nous avons constaté la même chose. Étant donné que la charge de travail totale reste la même, l'amélioration des performances dans le graphique ci-dessus ne peut être attribuée qu'à la réduction des changements de contexte.

Étiquettes associées:
source:php.cn
Déclaration de ce site Web
Le contenu de cet article est volontairement contribué par les internautes et les droits d'auteur appartiennent à l'auteur original. Ce site n'assume aucune responsabilité légale correspondante. Si vous trouvez un contenu suspecté de plagiat ou de contrefaçon, veuillez contacter admin@php.cn
Tutoriels populaires
Plus>
Derniers téléchargements
Plus>
effets Web
Code source du site Web
Matériel du site Web
Modèle frontal
À propos de nous Clause de non-responsabilité Sitemap
Site Web PHP chinois:Formation PHP en ligne sur le bien-être public,Aidez les apprenants PHP à grandir rapidement!