负载均衡:Node.js - Socket.io - Redis

4
我有3台运行NodeJs的服务器,它们通过Redis(1个主服务器,2个从服务器)相互关联。
我遇到的问题是,将系统运行在单个服务器上时工作正常,但当我将其扩展到3个NodeJS服务器时,它开始丢失消息并且系统变得不稳定。
我的负载均衡器不接受粘性会话。因此,每次来自客户端的请求到达时,它们可能会发送到不同的服务器。
我将所有NodeJS服务器都指向Redis主服务器。
看起来socket.io正在每个服务器上存储信息,并且没有与redis一起分发。
我使用的是socket.io V9,我怀疑我没有任何握手代码,这可能是原因吗?
我的配置socket.io的代码如下:
var express = require('express');
var io = require('socket.io');
var redis = require('socket.io/node_modules/redis');
var RedisStore = require('socket.io/lib/stores/redis');

var pub = redis.createClient("a port", "an ip");
var sub = redis.createClient("a port", "an ip");
var client = redis.createClient("a port", "an ip");
var events = require('./modules/eventHandler');

exports.createServer = function createServer() {
    var app = express();
    var server = app.listen(80);
    var socketIO = io.listen(server);

    socketIO.configure(function () {
        socketIO.set('store', new RedisStore({
            redisPub: pub,
            redisSub: sub,
            redisClient: client
        }));
        socketIO.set('resource', '/chat/socket.io');
        socketIO.set('log level', 0);
        socketIO.set('transports', [, 'htmlfile', 'xhr-polling', 'jsonp-polling']);
    });

    // attach event handlers
    events.attachHandlers(socketIO);

    // return server instance
    return server;
};

我正在考虑另一种实现方式(在socket.io没有粘性会话的情况下),就是在执行每个socket io请求之前捕获它们,并使用redis进行发布-订阅,以确保它们到达正确的node.js实例。您有什么想法吗? - Ricardo Daniel
我正在检查这个:https://github.com/nodejitsu/node-http-proxy,以便我可以首先检查到达的消息并将它们路由到正确的服务器。 - Ricardo Daniel
2个回答

2
Redis只会从主服务器同步到从服务器,不会从从服务器同步到主服务器。因此,如果您正在向您的三台机器中的所有机器写入数据,则只有命中主服务器的消息才会在所有三个服务器之间同步。这就是为什么看起来好像有些消息丢失了。
更多信息可以在这里找到。
只读从服务器:自Redis 2.6版本开始,从服务器支持默认启用的只读模式。该行为由redis.conf文件中的slave-read-only选项控制,并且可以使用CONFIG SET在运行时启用和禁用。只读从服务器将拒绝所有写入命令,因此不可能由于错误而向从服务器写入。这并不意味着该功能被构思为将从实例暴露给Internet或更普遍地暴露给存在不受信任的客户端的网络,因为仍然启用像DEBUG或CONFIG这样的管理命令。但是,可以通过redis.conf中的rename-command指令禁用只读实例的命令以提高安全性。您可能想知道为什么可以还原默认值并具有可以成为写操作目标的从实例。原因是,如果从服务器和主服务器重新同步,或者从服务器重新启动,则将丢弃这些写入内容,通常存在不重要的临时数据可以存储到从服务器中。例如,客户端可以从从实例中获取有关主服务器的可达性的信息以协调故障转移策略。

非常感谢您的回复Eli,但是目前从这3个实例中,我只使用了1个(主节点),我从未在其他节点上编写或读取过数据,我计划在将来对其进行扩展。所有运行在Node.js上的客户端都连接到主节点。您知道吗,Socket.io握手信息和连接是否也会同步? - Ricardo Daniel
我不明白。在问题中,你说当你只使用一台机器时一切都正常工作,但是当你切换到三台机器时停止工作了... - Eli
我的错误,我指的是3个Node.js服务器,而不是3个Redis服务器。 配置为:3个Node.js服务器指向1个Redis主服务器(另外2个从服务器现在没有被指向)。我修改了原来的问题以展示这种情况。 - Ricardo Daniel

0

我看到了这篇帖子:

在nodejs服务器和负载均衡器之间设置一个“代理”可能是个好主意。通过这种方式,即使没有粘性会话,也可以在负载均衡器中使用XHR-Polling。

使用http-proxy实现node.js负载均衡

使用nodejs-http-proxy,我可以有自定义的路由,例如在socket.io的“连接URL”上添加参数。

有人尝试过这种解决方案吗?


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接