socket.io如何在多个服务器之间发送消息?

8

Socket.io API有向所有客户端发送消息的功能。

对于只有一个服务器和所有套接字在内存中的情况下,服务器可以向所有客户端发送消息,这很显然。但是,如果使用Redis来存储套接字的多个服务器呢?

假设客户端a连接到服务器y,客户端b连接到服务器z(并且有一个Redis盒子用于存储),并在一个服务器上执行socket.broadcast.emit,则另一个服务器上的客户端将接收此消息。 如何实现呢?

那些实际连接到其他服务器的客户端如何获取该消息?

  • 一个服务器是否“告诉”另一个服务器向其连接的客户端发送消息?
  • 服务器是否建立自己与客户端的连接来发送该消息?
2个回答

13

Socket.io默认使用MemoryStore,因此所有连接的客户端将存储在内存中,这使得无法(好吧,不是完全不行,稍后会详细讲解)向连接到另一个socket.io服务器的客户端发送和接收事件。

让所有socket.io服务器接收所有事件的一种方法是让所有服务器使用redis的发布-订阅机制。因此,可以使用发布到redis代替使用socket.emit。

redis_client = require('redis').createClient();
redis_client.publish('channelName', data);

所有的套接字服务器都通过redis订阅该频道,一旦收到消息,它们就会将其发送给连接到它们的客户端。

redis_sub = require('redis').createClient();
redis_sub.subscribe('channelName', 'moreChannels');

redis_sub.on("message", function (channel, message) {        
    socket.emit(channel, message);
});

复杂的事情!! 但是等等,事实证明你实际上不需要这种代码来实现目标。 Socket.io有RedisStore,它以更好的方式执行上面代码所要执行的操作,因此您可以编写适用于单个服务器的Socket.io代码,并通过redis传播到其他socket.io服务器。

总之,socket.io通过使用redis作为通道而不是内存在多个服务器之间发送消息。


完美,正是我所寻找的! - hackerhasid

1
有几种方法可以做到这一点。更多信息请参见此问题。关于Redis中pub/sub的工作原理的很好的解释在这里,Redis文档中。关于该范例如何工作的概述在这里,在维基百科上
引用Redis文档:
SUBSCRIBE、UNSUBSCRIBE和PUBLISH实现了发布/订阅消息范例,其中(引用维基百科)发送者(发布者)不会编程地将其消息发送给特定的接收者(订阅者)。相反,发布的消息被归类为通道,而不知道可能有哪些订阅者。订阅者对一个或多个通道表达兴趣,并且只接收感兴趣的消息,而不知道是否存在任何发布者。这种发布者和订阅者的解耦可以允许更大的可扩展性和更动态的网络拓扑结构。

2
我花了一些时间来解密这个答案如何回答我的问题,但在重新阅读带有此信息的文档后,我意识到背后发生的事情是,socket.io正在使用Redis pubsub来发布和订阅其他服务器客户端和其自己的消息。 - hackerhasid

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接