sql >> データベース >  >> NoSQL >> Redis

Node.js、Socket.io、Redis pub / subの大容量、低遅延の問題

    これは理にかなった質問だと思い、しばらく前に少し調べてみました。役立つヒントをいくつか見つけられるかもしれない例を探すのに少し時間を費やしました。

    簡単な例から始めるのが好きです:

    • lightimサンプルコード
    • Node.js + Redis Pub / Sub+socket.ioデモ

    軽いサンプルは1ページです(redis-node-clientをMatt Ranneyのnode_redisのようなものに置き換えたいことに注意してください:

    /*
     * 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");
    

    ドキュメント

    そこにはたくさんのドキュメントがあり、APIはこのタイプのスタックで急速に変化しているため、各ドキュメントの時間的関連性を比較検討する必要があります。

    • ノードアクティビティストリーム
    • クラウドファウンドリの例
    • redispubsubをノード化する方法
    • redisレイテンシ
    • 非同期通信にPub/Subを使用するredisクックブック
    • LinkedInの一般的なヒント
    • ノードredisバインディング
    • googlegroupsnodejsの質問

    関連する質問

    関連するいくつかの質問ですが、これはスタックのホットトピックです:

    • node.jsのチャットサーバーのRedispub/ sub
    • インスタントメッセージングシステム用にredispub/ subを設計するにはどうすればよいですか?

    注目すべきヒント(ymmv)

    ソケットプーリングをオフまたは最適化し、効率的なバインディングを使用し、レイテンシを監視し、作業を重複させないようにします(つまり、すべてのリスナーに2回公開する必要はありません)。




    1. <URL>へのWebSocket接続に失敗しました:WebSocketハンドシェイク中のエラー:予期しない応答コード:521

    2. KEYSをRedisで使用しないようにアドバイスされているのはなぜですか?

    3. redisリストの変更をリッスンする

    4. マングーススキーマの移行を適切に処理するにはどうすればよいですか?