【问题标题】:Using Redis as PubSub over Socket.io通过 Socket.io 使用 Redis 作为 PubSub
【发布时间】:2019-06-02 13:05:49
【问题描述】:

我正在创建一个聊天应用程序,使用户能够进行私人和群聊。计划为此应用使用以下技术:-

NodeJs + Socket.io + Redis + CouchDB(存储消息历史) + AngularJS

根据我最初的研究,使用 Redis 作为 PubSub 服务比使用 Socket.io 作为 pub-sub 更好。原因是如果不同的用户连接到不同的服务器实例,那么在这种情况下使用套接字会产生问题用户 1 发送的消息不会传递给用户 2(用户 1 连接到服务器 1,用户 2 连接到服务器 2)。

但如果我们使用 Redis,那么根据我的理解,我们必须创建新频道来启用私人聊天。它们是 Redis 中 10k 通道的限制。

我的怀疑是

  1. 是否需要每次创建新频道才能启用两个用户之间的私人聊天?
  2. 如果我需要创建单独的频道,那么实际上是否有 10K 频道的限制?
  3. 我需要一个使用 Redis 作为 pub/sub 和 socket.io 来启用私人聊天的工作示例。

问候, 维克拉姆

【问题讨论】:

    标签: node.js redis socket.io


    【解决方案1】:

    阅读下面的文章/博客文章后,使用 Redis 发布/订阅而不是 socket.io 发布/订阅将有助于可扩展性和更好的性能。

    https://github.com/sayar/RedisMVA/blob/master/module6_redis_pubsub/README.md

    https://github.com/rajaraodv/redispubsub

    此外,我还可以使用 redis 在私人聊天中创建快速 POC。这是代码:-

    var app = require('http').createServer(handler);
    app.listen(8088);
    var io = require('socket.io').listen(app);
    var redis = require('redis');
    var redis2 = require('socket.io-redis');
    io.adapter(redis2({ host: 'localhost', port: 6379 }));
    var fs = require('fs');
    
    function handler(req,res){
        fs.readFile(__dirname + '/index.html', function(err,data){
            if(err){
                res.writeHead(500);
                return res.end('Error loading index.html');
            }
            res.writeHead(200);
            console.log("Listening on port 8088");
            res.end(data);
        });
    }
    
    var store = redis.createClient();   
    var pub = redis.createClient();
    var sub = redis.createClient();
    sub.on("message", function (channel, data) {
            data = JSON.parse(data);
            console.log("Inside Redis_Sub: data from channel " + channel + ": " + (data.sendType));
            if (parseInt("sendToSelf".localeCompare(data.sendType)) === 0) {
                 io.emit(data.method, data.data);
            }else if (parseInt("sendToAllConnectedClients".localeCompare(data.sendType)) === 0) {
                 io.sockets.emit(data.method, data.data);
            }else if (parseInt("sendToAllClientsInRoom".localeCompare(data.sendType)) === 0) {
                io.sockets.in(channel).emit(data.method, data.data);
            }       
    
        });
    
    io.sockets.on('connection', function (socket) {
    
        sub.on("subscribe", function(channel, count) {
            console.log("Subscribed to " + channel + ". Now subscribed to " + count + " channel(s).");
        });
    
        socket.on("setUsername", function (data) {
            console.log("Got 'setUsername' from client, " + JSON.stringify(data));
            var reply = JSON.stringify({
                    method: 'message',
                    sendType: 'sendToSelf',
                    data: "You are now online"
                });     
        });
    
        socket.on("createRoom", function (data) {
            console.log("Got 'createRoom' from client , " + JSON.stringify(data));
            sub.subscribe(data.room);
            socket.join(data.room);     
    
            var reply = JSON.stringify({
                    method: 'message', 
                    sendType: 'sendToSelf',
                    data: "Share this room name with others to Join:" + data.room
                });
            pub.publish(data.room,reply);
    
    
        });
        socket.on("joinRooom", function (data) {
            console.log("Got 'joinRooom' from client , " + JSON.stringify(data));
            sub.subscribe(data.room);
            socket.join(data.room);     
    
        });
        socket.on("sendMessage", function (data) {
            console.log("Got 'sendMessage' from client , " + JSON.stringify(data));
            var reply = JSON.stringify({
                    method: 'message', 
                    sendType: 'sendToAllClientsInRoom',
                    data: data.user + ":" + data.msg 
                });
            pub.publish(data.room,reply);
    
        });
    
        socket.on('disconnect', function () {
            sub.quit();
            pub.publish("chatting","User is disconnected :" + socket.id);
        });
    
      });
    

    HTML 代码

    <html>
    <head>
        <title>Socket and Redis in Node.js</title>
        <script src="/socket.io/socket.io.js"></script>
        <script src="https://ajax.googleapis.com/ajax/libs/jquery/1.6.4/jquery.min.js"></script>
    </head>
    <body>
    <div id="username">
        <input type="text" name="usernameTxt" /> 
        <input type="button" name="setUsername" value="Set Username" />
    </div>
    <div id="createroom" style="display:none;">>
        <input type="text" name="roomNameTxt" /> 
        <input type="button" name="setRooomName" value="Set Room Name" />
        <input type="button" name="joinRooomName" value="Join" />
    </div>
    <div id="sendChat" style="display:none;">
        <input type="text" name="chatTxt" /> 
        <input type="button" name="sendBtn" value="Send" />
    </div>
    <br />
    <div id="content"></div>
    <script>    
        $(document).ready(function() {
            var username = "anonymous";
            var roomname = "anonymous";
            $('input[name=setUsername]').click(function(){
                if($('input[name=usernameTxt]').val() != ""){
                    username = $('input[name=usernameTxt]').val();
                    //var msg = {type:'setUsername',user:username};
                    socket.emit('setUsername',{user:username});
                }
                $('#username').slideUp("slow",function(){
                    $('#createroom').slideDown("slow");
                });
            });
            $('input[name=setRooomName]').click(function(){
                if($('input[name=roomNameTxt]').val() != ""){
                    roomname = $('input[name=roomNameTxt]').val();
                    socket.emit('createRoom',{user:username,room:roomname});
                }
                $('#createroom').slideUp("slow",function(){
                    $('#sendChat').slideDown("slow");
                });
            });
            $('input[name=joinRooomName]').click(function(){
                if($('input[name=roomNameTxt]').val() != ""){
                    roomname = $('input[name=roomNameTxt]').val();
                    socket.emit('joinRooom',{room:roomname});
                }
                $('#createroom').slideUp("slow",function(){
                    $('#sendChat').slideDown("slow");
                });
            });
    
            var socket = new io.connect('http://localhost:8088');
            var content = $('#content');
    
            socket.on('connect', function() {
                console.log("Connected");
            });
    
            socket.on('message', function(message){
                //alert('received msg=' + message);
                content.append(message + '<br />');
            }) ;
    
            socket.on('disconnect', function() {
                console.log('disconnected');
                content.html("<b>Disconnected!</b>");
            });
    
            $("input[name=sendBtn]").click(function(){
                var msg = {user:username,room:roomname,msg:$("input[name=chatTxt]").val()}
                socket.emit('sendMessage',msg);
                $("input[name=chatTxt]").val("");
            });
        });
    </script>
    </body>
    </html>
    

    【讨论】:

    • sub.on("message", function (channel, data) { 在这里做什么。这段代码中是否需要这个
    • 我看到你正在使用 socketio 房间。它会扩展到多个实例吗?
    • 为什么要创建store 变量?我看到它在:var store = redis.createClient();
    【解决方案2】:

    这就是所有基本的 redis pub/sub 代码。

    var redis = require("redis");
    
    var pub = redis.createClient();
    var sub = redis.createClient();
    
    sub.on("subscribe", function(channel, count) {
        console.log("Subscribed to " + channel + ". Now subscribed to " + count + " channel(s).");
    });
    
    sub.on("message", function(channel, message) {
        console.log("Message from channel " + channel + ": " + message);
    });
    
    sub.subscribe("tungns");
    
    setInterval(function() {
        var no = Math.floor(Math.random() * 100);
        pub.publish('tungns', 'Generated Chat random no ' + no);
    }, 5000);

    【讨论】:

      【解决方案3】:

      如果您需要动手创建一个简单的聊天应用程序,那么以下开发堆栈可以很好地协同工作:

      • Express.js (Node.js)
      • Redis
      • Socket.IO

      该应用程序包含一个聊天室,用户可以加入该聊天室并开始对话。 Socket.IO 负责在更新聊天计数/消息并使用 jQuery 在 UI 中刷新这些事件时发出事件。

      完整文章和源代码,请查看以下链接:https://scalegrid.io/blog/using-redis-with-node-js-and-socket-io/

      【讨论】:

        【解决方案4】:

        socket.io-redis 说:

        通过使用 socket.io-redis 适配器运行 socket.io,您可以在不同的进程或服务器中运行多个 socket.io 实例,这些实例都可以相互广播和发送事件。 所以以下任何命令:

        io.emit('hello', 'to all clients');
        io.to('room42').emit('hello', "to all clients in 'room42' room");
        
        io.on('connection', (socket) => {
          socket.broadcast.emit('hello', 'to all clients except sender');
          socket.to('room42').emit('hello', "to all clients in 'room42' room except sender");
        });
        

        将通过 Redis Pub/Sub 机制正确地向客户端广播。

        我猜

        io.to(socket.id).emit('hello', "to client which has same socket.id");
        
        

        会在不同的进程或服务器中发送私人消息。

        对了,我在做一个项目也需要私信。 希望提出任何其他建议。

        【讨论】:

          猜你喜欢
          • 2014-01-31
          • 2018-03-25
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2017-04-16
          相关资源
          最近更新 更多