【问题标题】:I'm receiving duplicate messages in my clustered node.js/socket.io/redis pub/sub application我在集群 node.js/socket.io/redis pub/sub 应用程序中收到重复消息
【发布时间】:2012-01-11 21:22:22
【问题描述】:

我正在使用 Node.js、带有 Redisstore 的 Socket.io、来自 Socket.io 的集群和 Redis。

我有一个发布/订阅应用程序,它只在一个 Node.js 节点上运行良好。但是,当它承受重负载时,由于 Node.js 不是为多核机器编写的,因此只会最大化服务器的一个核心。

正如您在下面看到的,我现在使用的是 Learnboost 的 Cluster 模块,也就是制作 Socket.io 的人。

但是,当我启动 4 个工作进程时,每个进入并订阅的浏览器客户端都会获得在 Redis 中发布的每条消息的 4 个副本。如果有 3 个工作进程,则有 3 个副本。

我猜我需要以某种方式将 redis pub/sub 功能移动到 cluster.js 文件中。

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>

【问题讨论】:

    标签: node.js redis socket.io


    【解决方案1】:

    我一直在与 cluster 和 socket.io 作斗争。每次我使用集群功能(虽然我使用内置的 Nodejs 集群)我都会遇到很多性能问题和 socket.io 问题。

    在尝试对此进行研究时,我一直在研究 socket.io git 上的错误报告和类似内容,任何使用集群或外部负载平衡器到其服务器的人似乎都遇到了 socket.io 的问题。

    似乎会产生“客户端不握手客户端应该重新连接”的问题,如果您增加详细日志记录,您将看到该问题。每当 socket.io 在集群中运行时,这就会出现很多,所以我认为它会恢复到这个状态。即,客户端每次建立新连接时都会连接到 socket.io 集群中的随机实例(授权时会执行多个 http/socket/flash 连接,并且在轮询新数据时会一直执行更多连接)。

    现在我已经恢复为一次只使用 1 个 socket.io 进程,这可能是一个错误,但也可能是构建 socket.io 的一个缺点。

    补充:我以后解决这个问题的方法是为集群内的每个socket.io实例分配一个唯一的端口,然后在客户端缓存端口选择。

    【讨论】:

      【解决方案2】:

      原来这不是 Node.js/Socket.io 的问题,我只是以完全错误的方式处理它。

      我不仅从 Node/Socket 堆栈外发布到 Redis 服务器,而且还直接订阅了 Redis 频道。在发布/订阅情况的两端,我绕过了“后端带有 Redis 存储的 Socket.io 集群”。

      所以,我创建了一个小应用程序(使用 Node.js/Socket.io/Express),它从我的 Rails 应用程序中获取消息,并使用 socket.io-announce 模块将它们“通知”到 Socket.io 房间。现在,通过使用 Socket.io 路由魔法,每个节点工作人员只能获取和发送消息到直接连接到它们的浏览器。换句话说,由于 pub 和 sub 都发生在 Node.js/Socket.io 堆栈中,因此不再有重复的消息。

      清理完我的代码后,我会在某个地方的 github 上放一个示例。

      【讨论】:

      猜你喜欢
      • 2012-08-12
      • 1970-01-01
      • 2021-11-24
      • 1970-01-01
      • 2019-05-17
      • 2021-05-04
      • 2012-05-20
      • 2012-04-27
      相关资源
      最近更新 更多