Je reçois des messages en double dans mon nœud cluster.js / socket.io / redis pub / subs application

StackOverflow https://stackoverflow.com/questions/8363242

  •  27-10-2019
  •  | 
  •  

Question

J'utilise Node.js, socket.io avec redisstore, cluster de Socket.io Guys et Redis.

J'ai une application pub / sous qui fonctionne bien sur un seul nœud Node.js. Mais, lorsqu'il est sous lourde charge, il est à maîtrise d'un seul noyau du serveur, car Node.js n'est pas écrit pour les machines multi-core.

Comme vous pouvez le voir ci-dessous, j'utilise maintenant le module de cluster de LearnBoost, les mêmes personnes qui fabriquent Socket.io.

Mais, lorsque je lance 4 processus de travail, chaque client de navigateur qui arrive et souscrit obtient 4 copies de chaque message publié dans Redis. S'il y a trois processus de travailleurs, il y en a trois exemplaires.

Je suppose que je dois déplacer le redis pub / subsannetality vers le fichier cluster.js d'une manière ou d'une autre.

Cluster.js

var cluster = require('./node_modules/cluster');

cluster('./app')
  .set('workers', 4)
  .use(cluster.logger('logs'))
  .use(cluster.stats())
  .use(cluster.pidfiles('pids'))
  .use(cluster.cli())
  .use(cluster.repl(8888))
  .listen(8000);

App.js

redis = require('redis'),
sys = require('sys');

var rc = redis.createClient();

var path = require('path')
  , connect = require('connect')
  , app = connect.createServer(connect.static(path.join(__dirname, '../')));

// require the new redis store
var sio = require('socket.io')
  , RedisStore = sio.RedisStore
  , io = sio.listen(app);

io.set('store', new RedisStore);io.sockets.on('connection', function(socket) {
    sys.log('ShowControl -- Socket connected: ' + socket.id);

    socket.on('channel', function(ch) {
        socket.join(ch)
        sys.log('ShowControl -- ' + socket.id + ' joined channel: ' + ch);
    });

    socket.on('disconnect', function() {
        console.log('ShowControll -- Socket disconnected: ' + socket.id);
    });
});

rc.psubscribe('showcontrol_*');

rc.on('pmessage', function(pat, ch, msg) {
    io.sockets.in(ch).emit('show_event', msg);
    sys.log('ShowControl -- Publish sent to channel: ' + ch);
});

// cluster compatiblity
if (!module.parent) {
  app.listen(process.argv[2] || 8081);
  console.log('Listening on ', app.address());
} else {
  module.exports = app;
}

client.html

<script src="http://localhost:8000/socket.io/socket.io.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.7.0/jquery.min.js"></script>
<script>
    var socket = io.connect('localhost:8000');
    socket.emit('channel', 'showcontrol_106');
    socket.on('show_event', function (msg) {
        console.log(msg);
        $("body").append('<br/>' + msg);
    });
</script>
Était-ce utile?

La solution 2

Il s'avère que ce n'est pas un problème avec Node.js / socket.io, je me procurciais tout à fait dans le mauvais sens.

Non seulement je publie dans le serveur Redis depuis l'extérieur de la pile de nœuds / socket, mais je suis toujours directement souscrit au canal redis. Aux deux extrémités de la situation pub / sous, je contourais le cluster "socket.io avec le magasin redis sur le back-end".

J'ai donc créé une petite application (avec Node.js / socket.io / express) qui a pris des messages de mon application Rails et les a «annoncés» dans une salle Socket.io à l'aide du module socket.io-announce. Maintenant, en utilisant la magie de routage socket.io, chaque travailleur de nœud n'obtiendrait et n'enverrait que des messages aux navigateurs qui leur sont connectés directement. En d'autres termes, plus de messages en double puisque le pub et le sous se sont produits dans la pile Node.js / socket.io.

Après avoir nettoyé mon code, je mettrai un exemple sur un github quelque part.

Autres conseils

J'ai lutté avec Cluster et Socket.io. Chaque fois que j'utilise la fonction de cluster (j'utilise le cluster NodeJS intégré), j'obtiens beaucoup de problèmes de performances et de problèmes avec socket.io.

Tout en essayant de rechercher cela, j'ai fouillé les rapports de bogues et similaires sur le socket.io git et toute personne utilisant des clusters ou des équilibreurs de charge externes à leurs serveurs semble avoir des problèmes avec socket.io.

Il semble produire le problème "le client du client et le client à la main doit reconnecter", ce que vous verrez si vous augmentez la journalisation verbale. Cela semble beaucoup chaque fois que Socket.io s'exécute dans un cluster, donc je pense que cela revient à cela. C'est-à-dire que le client est connecté à l'instance randomisée dans le cluster socket.io à chaque fois qu'il fait une nouvelle connexion (il fait plusieurs connexions HTTP / socket / flash lors de l'autorisation et plus tout le temps plus tard lors du sondage pour de nouvelles données).

Pour l'instant, je suis revenu uniquement en utilisant un processus Socket.io à la fois, cela pourrait être un bug, mais pourrait également être une lacune de la façon dont Socket.io est construit.

Ajouté: Ma façon de résoudre ce problème à l'avenir sera d'attribuer un port unique à chaque instance socket.io à l'intérieur du cluster, puis de secouer le port de cache côté client.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top