2012-04-13 11 views
14

Jestem nowy w redis pub/sub. Mam system czatu w systemie, który przypomina komunikator. Więc chciałbym użyć redis pub/sub. Po zbadaniu próbek większość z nich została zaprojektowana w oparciu o chat room. W moim systemie będę mieć wiele pokojów rozmów między użytkownikami takimi jak;Jak zaprojektować redis pub/sub dla systemu wiadomości błyskawicznych?

A:B 
A:C 
D:C 
E:F 

Linie powyżej to pokoje. I zaimplementowałem serwer z node.js jak poniżej;

var store = redis.createClient(); 
var pub = redis.createClient(); 
io.sockets.on('connection', function (socket) { 
    var sub = redis.createClient(); 

    sub.on("message", function(pattern, data){ 
      data = JSON.parse(data); 
     socket.send(JSON.stringify({ type: "chat", key: pattern, nick: data.nickname, message: data.text })) 
     } 
    }); 

    socket.on('message', function (messageData) { 
     store.incr("messageNextId", function(e, messageId) { 
     var room = "" 
     var from = messageData.clientId > socket.nickname ? socket.nickname : messageData.clientId; 
     var to = messageData.clientId < socket.nickname ? socket.nickname : messageData.clientId; 
      room = from + ":" + to; 

     var message = { id: messageId, nickname: socket.nickname, text: messageData.text }; 
     store.rpush("rooms:" + room, JSON.stringify(message), function(e, r) { 
      pub.publish(room, JSON.stringify(message)) 
     }); 
    }); 
}); 

Jak widać, tworzę nowego subskrybenta redis dla każdego połączenia. W innych pokojach rozmów abonenta klient redis jest tworzony globalnie. I istnieją tylko trzy połączenia przez cały czas, co rozwiązuje ich problem, ponieważ kiedy wydawca publikuje komunikat, wszyscy podłączeni klienci powinni go otrzymać. Ale mam tu przymus. Chcę otworzyć sesję czatu między dwoma użytkownikami i tylko ci użytkownicy powinni być subskrybentami. Powyższy kod działa tak, jak chciałbym, ale nie wiem, czy jest w porządku, aby redis utworzył nowego klienta abonenta dla każdego połączenia.

Byłoby miło usłyszeć twoje sugestie. Z góry dziękuję.

Odpowiedz

20

Jak zawsze, należy porównywać takie rzeczy do własnego użytku - nie można udzielać ogólnych porad. Konieczne może być zwiększenie maksymalnej liczby otwartych plików w systemie, w całym systemie lub dla użytkownika redis. Dotyczy to oczywiście również użytkownika, który uruchamia serwer WWW.

To powiedziawszy, powinieneś upewnić się, że subskrybujesz ponownie subskrybenta subskrypcji, gdy użytkownik opuszcza, socket.on('disconnect') i quit(). Być może zainteresuje Cię również to, że socket.io ma backend redis, który wykorzystuje redis pub/sub, a także ma koncepcję pokoi, więc możesz zaoszczędzić sobie trochę kłopotów z wykorzystaniem tego, ponieważ jesteś już zależny od gniazda .io.

Edit: Po szybkiej kontroli, otrzymuję komunikat o błędzie z Redis po 991 abonentów:

Ready check failed: Error: Error: ERR max number of clients reached 

Oto z domyślnego redis.conf:

# Set the max number of connected clients at the same time. By default 
# this limit is set to 10000 clients, however if the Redis server is not 
# able ot configure the process file limit to allow for the specified limit 
# the max number of allowed clients is set to the current file limit 
# minus 32 (as Redis reserves a few file descriptors for internal uses). 
# 
# Once the limit is reached Redis will close all the new connections sending 
# an error 'max number of clients reached'. 
# 
# maxclients 10000 

mojego systemu (Ubuntu 11.11) ma domyślny limit nofile wynoszący 1024, więc mój szybki test powinien zakończyć się niepowodzeniem po 992 połączonych klientach, co wydaje się tuż po teście (mam też jednego klienta dla wydawcy). Moja propozycja dla ciebie jest, aby kontrolować swój limit nofile (w moim systemie to w /etc/security/limits.{conf,d/*} i twoi Redis maxclients ustawienie, a następnie punkt odniesienia, wzorzec, Benchmark!

+0

Dziękuję za szczegółową odpowiedź. Wiedziałem, że socket.io ma pojęcia pokoju ale nie zdawałem sobie sprawy z tego, że używam pub/sub za kulisami, spróbuję tego i na pewno rozpocznę testy porównawcze, obecnie staram się znaleźć dobry punkt wyjścia. sugestie: –

+0

@ AliErsöz: Świetnie. Jeśli dowiesz się, że moja odpowiedź była zadowalająca, rozważ zaakceptowanie jej jako poprawnej odpowiedzi, klikając duży znacznik wyboru w lewym górnym rogu. –

Powiązane problemy