SORU
11 Mayıs 2012, Cuma


Node.js Soket.ıo, Redis pub/sub yüksek hacimli, düşük gecikme zorluklar

Socket.io/node.js ve redis pub/conjoining gerçek zamanlı web yayın sistemi çoklu taşıma işleyebilir sunucu olayları ile tahrik oluşturmak için bir girişim alt, üç yaklaşım gibi görünüyor

  1. <>'createClient' bir redis bağlantı ve kanal için abone olun. p Yuvada.ıo istemci bağlantı, bir yuva içine müşteri katıl.ıo oda. Bu redis.("mesaj", ...) olay, çağrı ıo.yuva.(oda).(ilgili odadaki tüm müşterilerine dağıtmak için"olay", veri). yayarlar How to reuse redis connection in socket.io? gibi

  2. <>'createClient' bir redis bağlantı. p Yuvada.ıo istemci bağlantı, bir yuva içine müşteri katıl.ilgili redis için ıo oda ve abone kanal(lar). Redis vardır.("mesaj", ...) mesaj alındığında istemci bağlantı kapatma içinde çağrı müşteri.(özel istemci olayı başlatmak için"olay", veri). yayarlar Examples in using RedisStore in socket.io cevabı gibi

  3. Yuvaya RedisStore pişmiş kullanın.ıo ve 'yayın' "" socketio-spec protokolü. aşağıdaki Redis kanal gönderme tek

1 numara tüm istemciler için bir kez alt ve ilişkili Redis olay işleme sağlar. 2 numaralı Redis pub/sub içine daha doğrudan bir kanca bulunmaktadır. 3 numara daha kolaydır, ama ileti olaylar üzerinde az kontrole sahiptir.

Ancak, benim testlerde, 1'den fazla bağlı müşteri ile beklenmedik bir şekilde düşük performans sergiler. Söz konusu sunucu olayları 1,000 mesajları redis bir kanal için mümkün olduğunca çabuk, mümkün olduğunca hızlı bir şekilde dağıtılacak yayınlanmaktadır. Performansa bağlı istemciler (soket.zamanlamaları ile ölçülür ıo-istemci zaman günlük temel analiz için Redis bir liste halinde).

Tahmin ne seçeneği, mesajı alır server 1,, sonra sırayla tüm bağlı istemcilerin yazar. Seçenek 2, server her ileti birden çok kez (abonelik müşteri başına bir kez) alır ve ilgili istemci için yazar. Her iki durumda da, sunucu tüm bağlı istemcilerin Tebliğ olana kadar ikinci bir ileti olay yok. Durumu açıkça yükselen eşzamanlılık ile şiddetlenir.

Bu yığınlar yetenekleri ve algılanan bilgelik ile oran gibi görünüyor. İnanmak istiyorum ama zorlanıyorum.

Bu senaryo (mesaj yüksek hacimli düşük gecikme dağılımı) sadece bu araçları seçeneği (henüz?), değil. ya bir numara eksik muyum?

CEVAP
13 HAZİRAN 2012, ÇARŞAMBA


Bu makul bir soru olduğunu ve kısa bir süre önce araştırdım sanıyordum. Biraz zaman bazı yararlı ipuçları elde etmek mümkün olabilir bu örnekler bulmak için harcadım.

Örnekler

Yalındır örnekler ile başlamak istiyorum:

Işık örnek tek bir sayfa (Matt tarafından node_redis gibi bir şey ile redis-düğüm-istemci değiştirmek için isteyeceksiniz İlköğretim not:

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

Belgeler

Orada belgeleri bir ton var, ve API doktor her zaman alaka tartmak gerekir, bu yüzden hızla yığın bu tür değişiyor.

İlgili Sorular

Sadece birkaç ilgili soru, bu yığın üzerinde sıcak bir konu

Önemli ipuçları (ymmv)

Kapatmak ya da yuva havuzu, verimli bağları kullanın, gecikmeli monitör ve iş (tüm dinleyicilere iki kez yayımlamaya gerek yok yani) çoğaltarak değil emin optimize.

Bunu Paylaş:
  • Google+
  • E-Posta
Etiketler:

YORUMLAR

SPONSOR VİDEO

Rastgele Yazarlar

  • Helen Bradley

    Helen Bradle

    4 Mart 2008
  • MatheusDosGames

    MatheusDosGa

    28 Aralık 2011
  • PaulGBelliveau

    PaulGBellive

    5 Mart 2009