2013-02-18 1 views
28

아주 간단한 질문입니다. 나는 백엔드로 nodejs를 사용하여 실시간 게임을 만들고 있는데 어느 것이 더 신뢰할 수 있고 어느 것이 더 효율적인지에 관한 정보가 있다면 궁금해하십니까?저는 코드 전체에서 Redis와 Socket.io를 많이 사용하고 있습니다. 그래서 나는 Socket.io의 Rooms을 사용해야하는지, 아니면 redis를 사용하여 더 좋을지 알고 싶습니다. 'pub-sub?무엇을 사용해야합니까? Socket.io 방 또는 Redis pub-sub?

업데이트 : 왜 redi pub/sub over socket.io 객실을 사용해야하는지 매우 중요한 이유가 있음을 깨달았습니다. 청취자에게 게시 할 때 Socket.io 실에서 (브라우저) 클라이언트는 메시지를 수신하고 실제로는 메시지를 수신하는 클라이언트 (서버에있는 서버)입니다. 이러한 이유로 각 클라이언트에 대한 정보를 모든 (서버) 클라이언트에 알리고 브라우저 클라이언트에 전달하기 전에 일부 처리를 수행하려는 경우 redis를 사용하는 것이 좋습니다. redis를 사용하면 이벤트를 실행하여 각 사용자의 개별 데이터를 생성 할 수 있습니다. 여기서 socket.io와 같이 모든 사용자의 고유 한 데이터를 한 번에 생성 한 다음 루프를 반복하여 개별 데이터를 보내면 거의 불가능합니다. 적어도 나를 위해, 방의 목적.

불행히도 내 목적을 위해 나는 지금 당장 redis에 붙어 있습니다.

업데이트 2 :

+2

재미있는 질문은 알고 싶습니다. 아마도이 게시물은 도움이 될 것입니다 : http://stackoverflow.com/questions/10167206/redis-pub-sub-or-socket-ios-broadcast – yuwang

+0

링크를 보내 주셔서 감사합니다, 그 마지막 게시물 좋은 지적합니다. socket.io를 사용하려면 (프로세스) 범위가 더 제한적일 수 있기 때문에 확장 성이 떨어질 수 있습니다. –

+1

누구나 그 차이점을 설명 할 수 있습니까? 세부 사항은 좋을 것이다. – user568109

답변

29

레디 스 펍/서브는 모든 클라이언트가있는 경우에 중대하다 .... 아래 답변을 참조하십시오 연결 만 2 레디 스를 사용하지만 여전히 개별 클라이언트 처리 할 수 ​​있도록 플러그인을 개발 종료 됨 redis에 직접 액세스. 노드 서버가 여러 개인 경우 다른 노드 서버에 메시지를 보낼 수 있습니다.

그러나 브라우저에 클라이언트가있는 경우 서버에서 클라이언트로 데이터를 보내려면 다른 것이 필요합니다.이 경우 socket.io가 좋습니다.

이제 Redis 저장소에서 socket.io를 사용하면 socket.io는 서버간에 메시지를 전파하기 위해 Redis pub/sub를 사용하고 서버는 클라이언트에 메시지를 전파합니다.

그래서 Redis 저장소로 구성된 socket.io를 사용하는 방은 아마도 가장 간단한 방법 일 것입니다.

+0

현재 나의 셋업에서는 socket.io와 redis pub-sub에 redisStore를 사용하고 있지만, 결과적으로 socket.io를 통해 연결하는 모든 클라이언트는 해당하는 redis 연결을 만들어야합니다. Socket.io 룸으로 전환하면 각 사용자별로 별도의 다시 연결을 사용하게됩니까? (필자는 가정합니다.) –

+2

RedisStore는 노드 인스턴스 당 총 3 개의 연결 (클라이언트)을 사용합니다. 클라이언트 연결 당 또는 방당 새 방을 생성하지 않고 정확한 방 자체로 디스패치합니다. –

+0

맞아요. 그래서 현재 각 클라이언트마다 하나의 redis 클라이언트 (socket.io onconnection 콜백 내부)를 사용하기 때문에 제 경우의 방을 사용하면 효율성이 크게 향상 될 것입니다. –

6

많은 pub-sub 클라이언트를 허용하는 노드 플러그인을 작성했지만 모든 단일 socketio 연결에서 새로운 연결 대신 2 개의 redis 연결 만 필요합니다. 일반적으로 작동해야합니다. 다른 사람이 사용할 수 있다고 생각했습니다. .

이 코드는 기본적으로이 예제에서 socket.io 클라이언트를 연결할 수 있고 항상 2 개의 연결 만 사용하지만 모든 클라이언트가 자신의 채널을 구독 할 수 있다고 가정합니다. 이 예에서 모든 클라이언트는 '달콤한 메시지!'라는 메시지를받습니다. 10 초 후. socket.io와

예 (레디 스 술집 서브 사용) :

var 
    RPubSubFactory = require('rpss.js'); 

var 
    redOne = redis.createClient(port, host), 
    redTwo = redis.createClient(port, host); 

var pSCFactory = new RPubSubFactory(redOne); 

io.sockets.on('connection', function(socket){ 
    var cps = pSCFactory.createClient(); 
    cps.onMessage(function(channel, message){ 
     socket.emit('message', message); 
    }); 
    io.sockets.on('disconnect', function(socket){ 
     // Dont actually need to unsub, because end() will cleanup all subs, 
     // but if you need to sometime during the connection lifetime, you can. 
     cps.unsubscribe('cool_channel'); 
     cps.end(); 
    }); 
    cps.subscribe('cool_channel') 
}); 

setTimeout(function(){ 
    redTwo.publish('cool_channel', 'sweet message!'); 
},10000); 

실제 플러그인 코드 :

var RPubSubFactory = function(){ 

    var 
     len,indx,tarr; 
    var 
     dbcom = false, 
     rPubSubIdCounter = 1, 
     clientLookup = {}, 
     globalSubscriptions = {}; 

    // public 
    this.createClient = function() 
    { 
     return new RPubSupClient(); 
    } 

    // private 
    var constructor = function(tdbcom) 
    { 
     dbcom = tdbcom; 
     dbcom.on("message", incommingMessage); 
    } 
    var incommingMessage = function(rawchannel, strMessage) 
    { 
     len = globalSubscriptions[rawchannel].length; 
     for(var i=0;i<len;i++){ 
      //console.log(globalSubscriptions[rawchannel][i]+' incomming on channel '+rawchannel); 
      clientLookup[globalSubscriptions[rawchannel][i]]._incommingMessage(rawchannel, strMessage); 
     } 
    } 

    // class 
    var RPubSupClient = function() 
    { 
     var 
      id = -1, 
      localSubscriptions = []; 

     this.id = -1; 
     this._incommingMessage = function(){}; 

     this.subscribe = function(channel) 
     { 
      //console.log('client '+id+' subscribing to '+channel); 
      if(!(channel in globalSubscriptions)){ 
       globalSubscriptions[channel] = [id]; 
       dbcom.subscribe(channel); 
      } 
      else if(globalSubscriptions[channel].indexOf(id) == -1){ 
       globalSubscriptions[channel].push(id); 
      } 
      if(localSubscriptions.indexOf(channel) == -1){ 
       localSubscriptions.push(channel); 
      } 
     } 
     this.unsubscribe = function(channel) 
     { 
      //console.log('client '+id+' unsubscribing to '+channel); 
      if(channel in globalSubscriptions) 
      { 
       indx = globalSubscriptions[channel].indexOf(id); 
       if(indx != -1){ 
        globalSubscriptions[channel].splice(indx, 1); 
        if(globalSubscriptions[channel].length == 0){ 
         delete globalSubscriptions[channel]; 
         dbcom.unsubscribe(channel); 
        } 
       } 
      } 
      indx = localSubscriptions.indexOf(channel); 
      if(indx != -1){ 
       localSubscriptions.splice(indx, 1); 
      } 
     } 
     this.onMessage = function(msgFn) 
     { 
      this._incommingMessage = msgFn; 
     } 
     this.end = function() 
     { 
      //console.log('end client id = '+id+' closing subscriptions='+localSubscriptions.join(',')); 
      tarr = localSubscriptions.slice(0); 
      len = tarr.length; 
      for(var i=0;i<len;i++){ 
       this.unsubscribe(tarr[i]); 
      } 
      localSubscriptions = []; 
      delete clientLookup[id]; 
     }   
     var constructor = function(){ 
      this.id = id = rPubSubIdCounter++; 
      clientLookup[id] = this; 
      //console.log('new client id = '+id); 
     }   
     constructor.apply(this, arguments); 
    }  
    constructor.apply(this, arguments); 
}; 

module.exports = RPubSubFactory; 

내가 주변 청소 만하고 내가 할 수있는만큼 효율성을 개선하기 위해 노력, 그러나 다른 속도 테스트를 한 후에, 나는 이것이 내가 얻을 수있는 가장 빠른 것이라고 결론을 내렸다.

최신 버전 : https://github.com/Jezternz/node-redis-pubsub

관련 문제