web-dev-qa-db-fra.com

Le processeur NodeJS atteint 100%, un processeur à la fois

J'ai écrit un serveur proxy SOCKS5 dans NodeJS. J'utilise les bibliothèques natives net et dgram pour ouvrir TCP et les sockets UDP.

Cela fonctionne bien pour environ 2 jours et tous les processeurs sont à environ 30% max. Après 2 jours sans redémarrage, un processeur atteint 100%. Après cela, tous les processeurs se relaient et restent à 100%, un processeur à la fois.

 CPU Spikes

Voici un graphique sur 7 jours des pointes du processeur:  enter image description here

J'utilise Cluster pour créer des instances telles que:

for (let i = 0; i < Os.cpus().length; i++) {
  Cluster.fork();
}

C'est la sortie de strace alors que le cpu est à 100%:

% time     seconds  usecs/call     calls    errors syscall
------ ----------- ----------- --------- --------- ----------------
99.76    0.294432          79      3733           epoll_pwait
 0.10    0.000299           0      3724        24 futex
 0.08    0.000250           0      3459        15 rt_sigreturn
 0.03    0.000087           0      8699           write
 0.01    0.000023           0       190       190 connect
 0.01    0.000017           0      3212        38 read
 0.00    0.000014           0       420           close
 0.00    0.000008           0       612       180 recvmsg
 0.00    0.000000           0        34           mmap
 0.00    0.000000           0        16           ioctl
 0.00    0.000000           0       190           socket
 0.00    0.000000           0       111           sendmsg
 0.00    0.000000           0       190           bind
 0.00    0.000000           0       482           getsockname
 0.00    0.000000           0       218           getpeername
 0.00    0.000000           0       238           setsockopt
 0.00    0.000000           0       432           getsockopt
 0.00    0.000000           0      3259       104 epoll_ctl
------ ----------- ----------- --------- --------- ----------------
100.00    0.295130                 29219       551 total

Et le résultat du profil de noeud (poids lourd):

[Bottom up (heavy) profile]:
Note: percentage shows a share of a particular caller in the total
amount of its parent calls.
Callers occupying less than 1.0% are not shown.

 ticks parent  name
1722861   81.0%  syscall

  28897    1.4%  UNKNOWN

Comme je n’utilise que les bibliothèques natives, la plupart de mon code s’exécute en C++ et non en JS. Donc, tout débogage que je dois faire est dans le moteur v8. Voici un résumé du profileur de noeud (pour la langue):

 [Summary]:
   ticks  total  nonlib   name
   92087    4.3%    4.5%  JavaScript
 1937348   91.1%   94.1%  C++
   15594    0.7%    0.8%  GC
   68976    3.2%          Shared libraries
   28897    1.4%          Unaccounted

Je soupçonnais que cela pourrait être le ramasse-miettes qui courait. Mais j'ai augmenté la taille du tas de Node et la mémoire semble être à portée de main. Je ne sais pas vraiment comment le déboguer car chaque itération prend environ 2 jours.

Quelqu'un a eu un problème similaire et a réussi à le déboguer? Je peux utiliser toute l'aide que je peux obtenir.

12
Koray Gocmen

Il y a quelques mois, nous nous sommes rendu compte qu'un autre service qui fonctionnait sur la même boîte que celle qui gardait une trace des sockets ouverts était à l'origine du problème. Ce service était une version plus ancienne et après un certain temps, il augmentait la capacité du processeur lors du suivi des sockets. La mise à niveau du service vers la dernière version a résolu les problèmes de l'unité centrale.

Leçon apprise: Parfois, ce n'est pas vous, ce sont eux

0
Koray Gocmen

Dans votre question, il n'y a pas assez d'informations pour reproduire votre cas. Des choses comme OS, la version de Node.js, l’implémentation de votre code, etc. peuvent être la cause d’un tel comportement.

Il existe une liste des meilleures pratiques pouvant résoudre ou éviter un tel problème:

  1. Utilisation pm2 en tant que superviseur de votre application Node.js.
  2. Débogage de votre application Node.js en production. Pour ça:
    • vérifiez votre connexion ssh au serveur de produit
    • liez votre port de débogage à localhost avec ssh -N -L 9229:127.0.0.1:9229 root@your-remove-Host
    • lancer le débogage avec la commande kill -SIGUSR1 <nodejs pid>
    • ouvrez chrome://inspect dans votre Chrome ou utilisez un autre débogueur pour Node.js
  3. Avant de commencer la production, faites:
1
galkin