使用 websocket 进行节点集群

Posted

技术标签:

【中文标题】使用 websocket 进行节点集群【英文标题】:Node clustering with websockets 【发布时间】:2016-07-12 07:01:29 【问题描述】:

我有一个节点 cluster,主节点在其中响应 http 请求。 服务器还监听 websocket 连接(通过 socket.io)。客户端通过所述 websocket 连接到服务器。现在客户端在各种游戏之间进行选择(每个节点进程处理一个游戏)。

我的问题如下:

我应该为每个节点进程打开一个新连接吗?如何告诉客户端他应该连接到确切的节点进程 X? (因为服务器可能会在其开启时处理传入的连接请求) 是否可以将套接字传递给节点进程,从而无需打开新连接? 如果我只使用一个连接(在主进程中)并将用户消息传递给相应的节点进程并将进程消息返回给用户,会有什么缺点? (我觉得在进程之间发送消息时,复制相当大的对象会花费很多CPU)

【问题讨论】:

【参考方案1】:

是否可以将套接字传递给节点进程,这样就没有 需要打开新连接吗?

您可以按照node.js doc here 中的说明将纯 TCP 套接字发送到另一个节点进程。基本思路是这样的:

const child = require('child_process').fork('child.js');
child.send('socket', socket);

然后,在 child.js 中,你会得到这个:

process.on('message', (m, socket) => 
  if (m === 'socket') 
    // you have a socket here
  
);

“套接字”消息标识符可以是您选择的任何消息名称 - 它并不特殊。 node.js 有代码,当您使用child.send() 并且您发送的数据被识别为套接字时,它使用特定于平台的进程间通信与其他进程共享该套接字。

但是,我相信这仅适用于除了 TCP 状态之外尚未建立任何本地状态的普通套接字。我自己没有尝试使用已建立的 webSocket 连接,但我认为它不起作用,因为一旦 webSocket 具有与其关联的更高级别的状态,而不仅仅是 TCP 套接字(例如加密密钥),就会出现问题,因为操作系统不会自动将该状态转移到新进程。

我应该为每个节点进程打开一个新连接吗?如何告诉 客户端,他应该连接到确切的节点进程 X? (因为 服务器可能会在其开启时处理传入的连接请求)

这可能是让 socket.io 连接到新进程的最简单方法。如果您确保您的新进程正在侦听一个唯一的端口号并且它支持 CORS,那么您可以使用主进程和客户端之间已有的 socket.io 连接,并在其上向客户端发送消息告诉客户端在哪里重新连接(什么端口号)。然后,客户端可以包含用于侦听该消息并与该新目的地建立连接的代码。

如果我只使用一个连接有什么缺点(在主 进程)并将用户消息传递给相应的节点进程 并将进程消息返回给用户? (感觉要花很多钱 CPU 之间发送消息时复制相当大的对象 进程)

缺点如您所想。您的主进程只需花费 CPU 能量作为双向转发数据包的中间人。这项额外的工作对您是否重要完全取决于上下文,并且必须通过衡量来确定。


这是我发现的更多信息。看来,如果在连接建立其初始 socket.io 状态之前,到达 master 的传入 socket.io 连接立即发送到集群子级,那么这个概念也适用于 socket.io 连接。

这里是 an article on sending a connection to another server 和实现代码。这似乎在连接时立即完成,因此它应该适用于以特定集群为目标的传入 socket.io 连接。这里的想法是对特定集群进程进行粘性分配,并且所有到达主节点的任何类型的传入连接都会在它们建立任何状态之前立即转移到集群子节点。

【讨论】:

The documentation 指出可以通过child_process.send 发送整个服务器。我不确定我们是否可以将 WebSocketServer 发送到另一个集群。此功能可能有助于避免因崩溃而重新连接整个连接。 @Tresdin - 您并没有真正发送“整个服务器”。您正在发送正在侦听传入连接的套接字,以便其他进程可以侦听这些传入连接。在典型安装中,通常没有单独的 WebSocketServer,因为传入的 webSocket 连接通常与常规 Web 服务器 HTTP 连接共享相同的端口(因此服务器)。而且,请记住,所有 socket.io 连接都以 HTTP 连接开始,然后通过升级过程协商将协议更改为 webSocket 协议。 @Tresdin - 但是,是的,您可以将侦听服务器套接字发送到另一个进程。 感谢您的澄清。我曾经认为没有办法挽救 ws 连接被崩溃的进程关闭。真是惊人的消息! “可能”对我来说已经足够好了。如果无法发送已建立的连接,我正在考虑提交问题,然后向ws 团队寻求官方方法。这个问题一定有解决办法。

以上是关于使用 websocket 进行节点集群的主要内容,如果未能解决你的问题,请参考以下文章

Websockets(ws) , NodeJs 集群,

webSocket 简单介绍

docker上带有javascript和nginx的websockets

如何编写一个 websocket 客户端

springboot websocket集群(stomp协议)连接时候传递参数

从 C# 程序连接基于 node.js 的 socket.io WebSocket 服务器