Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/node.js/39.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/redis/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Node.js、Socket.io、Redis发布/次高容量、低延迟困难_Node.js_Redis_Socket.io_Publish Subscribe_Low Latency - Fatal编程技术网

Node.js、Socket.io、Redis发布/次高容量、低延迟困难

Node.js、Socket.io、Redis发布/次高容量、低延迟困难,node.js,redis,socket.io,publish-subscribe,low-latency,Node.js,Redis,Socket.io,Publish Subscribe,Low Latency,当结合socket.io/node.js和redis pub/sub试图创建一个由服务器事件驱动的实时web广播系统来处理多个传输时,似乎有三种方法: “createClient”创建redis连接并订阅频道。在socket.io客户端连接上,将客户端加入socket.io文件室。在redis.on(“message”,…)事件中,调用io.sockets.In(room).emit(“event”,data)以分发到相关文件室中的所有客户端。像 “createClient”是一个redis连接

当结合socket.io/node.js和redis pub/sub试图创建一个由服务器事件驱动的实时web广播系统来处理多个传输时,似乎有三种方法:

  • “createClient”创建redis连接并订阅频道。在socket.io客户端连接上,将客户端加入socket.io文件室。在redis.on(“message”,…)事件中,调用io.sockets.In(room).emit(“event”,data)以分发到相关文件室中的所有客户端。像

  • “createClient”是一个redis连接。在socket.io客户端连接上,将客户端加入socket.io室并订阅相关的redis频道。在客户端连接闭包中包含redis.on(“message”,…),并在收到消息调用client.emit(“event”,data)时在特定客户端上引发事件。我喜欢你的答案

  • 按照socketio规范协议,使用Redis中烘焙到socket.io中的Redistore,并从Redis中的单个“调度”通道进行“广播”

  • 1号允许为所有客户机处理一次Redis sub和相关事件。第2个提供了一个更直接的Redis发布/订阅链接。第3个更简单,但对消息传递事件几乎没有控制

    然而,在我的测试中,当连接的客户端超过1个时,所有客户端都表现出出乎意料的低性能。所讨论的服务器事件是尽快将1000条消息发布到redis通道,并尽快分发。性能是通过连接的客户端(基于socket.io的客户端,将时间戳记录到Redis列表中进行分析)的计时来衡量的

    我推测,在选项1中,服务器接收消息,然后依次将其写入所有连接的客户端。在选项2中,服务器多次接收每条消息(每个客户端订阅一次),并将其写入相关客户端。在任何一种情况下,服务器都不会到达第二个消息事件,直到它与所有连接的客户端通信。这种情况显然随着并发性的增加而恶化

    这似乎和人们所认为的堆栈能力的智慧不符。我想相信,但我在挣扎


    这种情况(高容量消息的低延迟分发)是否不是这些工具的一种选择(目前?),还是我错过了一个窍门?

    我认为这是一个合理的问题,不久前对其进行了简要研究。我花了一点时间寻找一些例子,你可以从中获得一些有用的提示

    例子 我喜欢从直截了当的例子开始:

    light示例是一个单独的页面(注意,您可能希望用Matt Ranney的以下内容替换redis node client:

    /*
     * Mclarens Bar: Redis based Instant Messaging
     * Nikhil Marathe - 22/04/2010
    
     * A simple example of an IM client implemented using
     * Redis PUB/SUB commands so that all the communication
     * is offloaded to Redis, and the node.js code only
     * handles command interpretation,presentation and subscribing.
     * 
     * Requires redis-node-client and a recent version of Redis
     *    http://code.google.com/p/redis
     *    http://github.com/fictorial/redis-node-client
     *
     * Start the server then telnet to port 8000
     * Register with NICK <nick>, use WHO to see others
     * Use TALKTO <nick> to initiate a chat. Send a message
     * using MSG <nick> <msg>. Note its important to do a
     * TALKTO so that both sides are listening. Use STOP <nick>
     * to stop talking to someone, and QUIT to exit.
     *
     * This code is in the public domain.
     */
    var redis = require('./redis-node-client/lib/redis-client');
    
    var sys = require('sys');
    var net = require('net');
    
    var server = net.createServer(function(stream) {
        var sub; // redis connection
        var pub;
        var registered = false;
        var nick = "";
    
        function channel(a,b) {
        return [a,b].sort().join(':');
        }
    
        function shareTable(other) {
        sys.debug(nick + ": Subscribing to "+channel(nick,other));
        sub.subscribeTo(channel(nick,other), function(channel, message) {
            var str = message.toString();
            var sender = str.slice(0, str.indexOf(':'));
            if( sender != nick )
            stream.write("[" + sender + "] " + str.substr(str.indexOf(':')+1) + "\n");
        });
        }
    
        function leaveTable(other) {
        sub.unsubscribeFrom(channel(nick,other), function(err) {
            stream.write("Stopped talking to " + other+ "\n");
        });
        }
    
        stream.addListener("connect", function() {
        sub = redis.createClient();
        pub = redis.createClient();
        });
    
        stream.addListener("data", function(data) {
        if( !registered ) {
            var msg = data.toString().match(/^NICK (\w*)/);
            if(msg) {
            stream.write("SERVER: Hi " + msg[1] + "\n");
            pub.sadd('mclarens:inside', msg[1], function(err) {
                if(err) {
                stream.end();
                }
                registered = true;
                nick = msg[1];
    // server messages
                sub.subscribeTo( nick + ":info", function(nick, message) {
                var m = message.toString().split(' ');
                var cmd = m[0];
                var who = m[1];
                if( cmd == "start" ) {
                    stream.write( who + " is now talking to you\n");
                    shareTable(who);
                }
                else if( cmd == "stop" ) {
                    stream.write( who + " stopped talking to you\n");
                    leaveTable(who);
                }
                });
            });
            }
            else {
            stream.write("Please register with NICK <nickname>\n");
            }
            return;
        }
    
        var fragments = data.toString().replace('\r\n', '').split(' ');
        switch(fragments[0]) {
        case 'TALKTO':
            pub.publish(fragments[1]+":info", "start " + nick, function(a,b) {
            });
            shareTable(fragments[1]);
            break;
        case 'MSG':
            pub.publish(channel(nick, fragments[1]),
                nick + ':' +fragments.slice(2).join(' '),
                  function(err, reply) {
                  if(err) {
                      stream.write("ERROR!");
                  }
                  });
            break;
        case 'WHO':
            pub.smembers('mclarens:inside', function(err, users) {
            stream.write("Online:\n" + users.join('\n') + "\n");
            });
            break;
        case 'STOP':
            leaveTable(fragments[1]);
            pub.publish(fragments[1]+":info", "stop " + nick, function() {});
            break;
        case 'QUIT':
            stream.end();
            break;
        }
        });
    
        stream.addListener("end", function() {
        pub.publish(nick, nick + " is offline");
        pub.srem('mclarens:inside', nick, function(err) {
            if(err) {
            sys.debug("Could not remove client");
            }
        });
        });
    });
    
    server.listen(8000, "localhost");
    
    /*
    *迈凯轮酒吧:基于Redis的即时通讯
    *Nikhil Marathe-22/04/2010
    *一个使用
    *Redis发布/订阅命令,以便所有通信
    *已卸载到Redis,并且仅限于node.js代码
    *处理命令解释、演示和订阅。
    * 
    *需要redis节点客户端和最新版本的redis
    *    http://code.google.com/p/redis
    *    http://github.com/fictorial/redis-node-client
    *
    *启动服务器,然后远程登录到端口8000
    *向NICK注册,使用WHO查看其他人
    *使用TALKTO启动聊天。发送消息
    *使用MSG.Note执行以下操作很重要
    *交谈,以便双方都在倾听。使用“停止”
    *停止与某人交谈,退出退出。
    *
    *此代码位于公共域中。
    */
    var redis=require('./redis node client/lib/redis client');
    var sys=需要('sys');
    var net=要求的(‘净额’);
    var server=net.createServer(函数(流){
    var sub;//redis连接
    var-pub;
    var注册=假;
    var nick=“”;
    功能通道(a、b){
    返回[a,b].sort().join(':');
    }
    功能共享表(其他){
    系统调试(尼克+”:订阅“+频道(尼克,其他));
    sub.subscribeTo(频道(尼克,其他)、功能(频道,消息){
    var str=message.toString();
    var sender=str.slice(0,str.indexOf(':');
    如果(发送方!=尼克)
    stream.write(“[”+sender+“]”“+str.substr(str.indexOf(“:”)+1)+“\n”);
    });
    }
    功能表(其他){
    sub.Unsubscribrom(频道(尼克、其他)、功能(错误){
    stream.write(“停止与“+other+”\n)”交谈);
    });
    }
    addListener(“连接”,函数(){
    sub=redis.createClient();
    pub=redis.createClient();
    });
    stream.addListener(“数据”),函数(数据){
    如果(!已注册){
    var msg=data.toString().match(/^NICK(\w*)/);
    如果(味精){
    stream.write(“服务器:Hi”+msg[1]+“\n”);
    pub.sadd('mclarens:inside',msg[1],函数(err){
    如果(错误){
    stream.end();
    }
    注册=真实;
    尼克=味精[1];
    //服务器消息
    sub.subscribeTo(尼克+“:信息”,函数(尼克,消息){
    var m=message.toString().split(“”);
    var cmd=m[0];
    var-who=m[1];
    如果(cmd==“开始”){
    stream.write(who+“正在与您通话\n”);
    可分享的(世卫组织);
    }
    否则如果(cmd==“停止”){
    stream.write(谁+“停止与您交谈\n”);
    可离职人员(世卫组织);
    }
    });
    });
    }
    否则{
    stream.write(“请向NICK注册”);
    }
    返回;
    }
    var fragments=data.toString().replace('\r\n','').split('');
    开关(片段[0]){
    “TALKTO”案例:
    发布(片段[1]+“:info”,“start”+nick,函数(a,b){
    });
    可共享(片段[1]);
    打破
    案例“MSG”:
    发布(频道(nick,fragments[1]),
    尼克+':'+片段。切片(2)。连接(“”),
    F