web-dev-qa-db-fra.com

Fuite de mémoire lors de l'émission de messages avec Socket.IO + Node.js + ZMQ

J'ai trois applications qui se parlent. Un serveur Websocket (1) qui accepte les connexions des navigateurs, analyse l’URL pour voir quelles données sont nécessaires, le transmet au client s’il en a la mémoire, s’il ne le demande pas à une autre application appelée "fetcher" (2). Fetcher reçoit ce travail, le demande à une simple API (3) qui renvoie des données JSON et le renvoie au serveur Websocker qui le publie sur les clients connectés. "Fetcher" commence alors à vérifier périodiquement s'il existe des mises à jour de cette URL/tâche et envoie les nouvelles données au serveur Websocket à mesure qu'elles se produisent.

J'utilise socket.io pour la communication client-websocket serveur. Le serveur Websocket et le récupérateur parlent viaZMQsockets.

Je charge le serveur Websocket de test avec 130 connexions . Le serveur Websocket publie 160 Ko de données sur 130 clients toutes les secondes. Au début, il utilise 170 Mo de RAM pour 130 connexions, mais il passe rapidement à 1 Go bien qu’il n’y ait pas de nouvelles connexions. Ensuite, les signaux de pulsation de socket.io commencent à échouer, entraînant la perte de connexions.

J'utilise Nodetime pour prendre des instantanés de tas. Juste après la connexion du 130e client, voici à quoi ressemble la mémoire:

enter image description here

346 Objets tampons avec total 44MB .

En quatre minutes, le nombre d'objets Buffer augmente considérablement (encore une fois, sans nouvelles connexions): il y en a 3012 avec une mémoire totale de 486MB . Après 10 minutes supplémentaires, il en reste 3535 avec une consommation de mémoire totale de 573MB .

J'ai utilisé le memwatch de Mozilla pour savoir quelle ligne ajoute à la mémoire, et cette fonction a été trouvée:

function notifyObservers(resourceId) {
  var data = resourceData[resourceId];
  io.sockets.in(resourceId).emit('data', data);
}

Si je commente ces lignes, l'utilisation de la mémoire reste la même, c'est une autre confirmation.

Des idées comment cela peut arriver? J'appelle cette fonction à l'intérieur de la méthode de socket d'abonné de ZMQ et je suspecte qu'elle a quelque chose à voir avec ça. C'est le code résultant si je supprime des fonctions et les fusionne en une:

// Receive new resource data
const resourceUpdatedSubscriber = zmq.socket('sub').connect('tcp://localhost:5433');
resourceUpdatedSubscriber.subscribe('');

resourceUpdatedSubscriber.on('message', function (data) {
  var resource = JSON.parse(data);

  resourceData[resource.id] = resource.data;

  io.sockets.in(resourceId).emit('data', resourceData[resource.id]);
});

Tout mon code (y compris le test de charge) est public et vous pouvez trouver ce serveur de socket Web ici: https://github.com/denizozger/node-socketio/blob/master/server.js Voir la ligne 138.

J'ai commencé à apprendre Javascript et Node.js il y a deux mois, donc tout commentaire est le bienvenu, merci d'avance!

45
Deniz Ozger

Les NodeJs peuvent utiliser l’API Windows Socket (qui inclut des fuites de mémoire, un ancien bogue connu) https://connect.Microsoft.com/VisualStudio/feedback/details/605621/winsock-c-program-causes-memory-leak

Le problème est que WSACleanup ne sera jamais appelé tant que vous n'avez pas arrêté les services réseau. (Mélanger ZMq ou Nodejs ne changera pas ce fait)

Maintenant, au fil du temps, vous verrouillerez davantage de pages de mémoire et vous remarquerez ainsi une augmentation lorsque la première page de mémoire est pleine.

1
danbo

peut-être essayer d'ajouter

var resourceData;

quelque part dans votre code parce que peut-être votre fuite de mémoire a à voir avec globals

en savoir plus sur les globals ici: https://Gist.github.com/hallettj/64478

0
Prozi