并发会导致 Socket.io + Nodejs 失败
will concurrency cause Socket.io + Nodejs fail
好吧,我正在开发一款需要真实交流的游戏,所以我在其中使用了 socket.io,所以我目前正在尝试处理游戏断开连接,我担心在我处理时可能会同时发出另一个事件断开连接使游戏冻结。我知道 nodejs 是单线程的,但是如果我 运行 我的服务器是一个多容器怎么办?我知道我应该使用负载平衡,以便某个套接字的请求转到同一个实例,但这可能会导致并发事件在用户断开连接时发出?那么如何处理这个问题,或者我在后端缩放 socket.io 时错过了什么?
我想到的一个解决方案是我可以通过 gameId 平衡请求,这样在同一个游戏中的用户最终会加入我服务器的同一个实例,但我不知道这样的事情是否适用
在这种情况下,是的,从事件循环的角度来看,节点是 'single threaded',因此您的所有请求都会在它们进入时排队。
这意味着如果您使用 socket.io 作为 'game',那么每个发送到服务器的消息都会一个接一个地同步执行。话虽如此,Node 在这里非常高效,但在重负载或长/阻塞脚本下可能会使服务器崩溃。
幸运的是,您可以使用 PM2 等工具轻松地对节点进行集群,这样您就可以在 VM 上使用每个 'core' 并在所有节点之间进行负载平衡。
但是.. 如果我们需要维护状态,这会让我们陷入困境,因为 PM2 实际上会在每个 'core' 上生成您的应用程序的新版本它不能在每个实例之间进行对话,这意味着会话是运行 实例之间不共享,存储在每个 VM 上的文件也不能在其他实例之间访问。
这意味着,要大规模扩展节点/socket.io,您需要分解应用程序的几个部分,这将需要一些额外的服务,因此您的堆栈可能看起来像
- 节点服务器(这可以是带有 LB infront 或容器的多个 VM)
- Redis 服务器(这是您将存储会话信息和 socket.io 数据的地方)
现在,有很多方法可以构建它,但举个例子,一种方法可能是
(假设您将使用 pm2 进行集群)
- 游戏节点应用程序 - 2 个虚拟机 @ 2 个 vcpu 运行 PM2(将是游戏的 4 运行 个实例)
- Socket.io 服务器 - 2 个虚拟机 @ 2 个 vcpu 运行 PM2(将是 socket.io 服务器的 4 运行 个实例)
- Redis 服务器(根据负载,您可能希望有 2 个单独的实例,一个用于会话和游戏项目,另一个用于管理 socket.io)
- 用于存储图像的对象存储(S3 或其他对象存储)
- 可选 CDN
有了 Socket.io,您肯定会想要使用 redis。socket.io NPM。这将允许您将 socket.io 扩展到多个记录,socket.io 的 redis 包管理连接的客户端,因此即使用户连接到另一个套接字服务器,他们仍然能够发出和接收消息
不确定您现在在哪里托管,但有许多服务可用,并且根据您想要管理的数量,您可能希望查看来自数字海洋的 'apps' 等服务。它基本上是一个 'CAAS' 服务,您可以在 GIT 中拥有 socket.io 服务器,然后将其部署到 运行 容器中,DO 将处理您的每个之间的平衡运行 'APPs',因此您可以根据需要按需扩展 运行 个实例。虽然它不是最便宜的,并且从带宽等角度来看有一些缺点,但如果您知道允许您按比例放大和缩小等的尖峰,它会很好。
好吧,我正在开发一款需要真实交流的游戏,所以我在其中使用了 socket.io,所以我目前正在尝试处理游戏断开连接,我担心在我处理时可能会同时发出另一个事件断开连接使游戏冻结。我知道 nodejs 是单线程的,但是如果我 运行 我的服务器是一个多容器怎么办?我知道我应该使用负载平衡,以便某个套接字的请求转到同一个实例,但这可能会导致并发事件在用户断开连接时发出?那么如何处理这个问题,或者我在后端缩放 socket.io 时错过了什么?
我想到的一个解决方案是我可以通过 gameId 平衡请求,这样在同一个游戏中的用户最终会加入我服务器的同一个实例,但我不知道这样的事情是否适用
在这种情况下,是的,从事件循环的角度来看,节点是 'single threaded',因此您的所有请求都会在它们进入时排队。
这意味着如果您使用 socket.io 作为 'game',那么每个发送到服务器的消息都会一个接一个地同步执行。话虽如此,Node 在这里非常高效,但在重负载或长/阻塞脚本下可能会使服务器崩溃。
幸运的是,您可以使用 PM2 等工具轻松地对节点进行集群,这样您就可以在 VM 上使用每个 'core' 并在所有节点之间进行负载平衡。
但是.. 如果我们需要维护状态,这会让我们陷入困境,因为 PM2 实际上会在每个 'core' 上生成您的应用程序的新版本它不能在每个实例之间进行对话,这意味着会话是运行 实例之间不共享,存储在每个 VM 上的文件也不能在其他实例之间访问。
这意味着,要大规模扩展节点/socket.io,您需要分解应用程序的几个部分,这将需要一些额外的服务,因此您的堆栈可能看起来像
- 节点服务器(这可以是带有 LB infront 或容器的多个 VM)
- Redis 服务器(这是您将存储会话信息和 socket.io 数据的地方)
现在,有很多方法可以构建它,但举个例子,一种方法可能是 (假设您将使用 pm2 进行集群)
- 游戏节点应用程序 - 2 个虚拟机 @ 2 个 vcpu 运行 PM2(将是游戏的 4 运行 个实例)
- Socket.io 服务器 - 2 个虚拟机 @ 2 个 vcpu 运行 PM2(将是 socket.io 服务器的 4 运行 个实例)
- Redis 服务器(根据负载,您可能希望有 2 个单独的实例,一个用于会话和游戏项目,另一个用于管理 socket.io)
- 用于存储图像的对象存储(S3 或其他对象存储)
- 可选 CDN
有了 Socket.io,您肯定会想要使用 redis。socket.io NPM。这将允许您将 socket.io 扩展到多个记录,socket.io 的 redis 包管理连接的客户端,因此即使用户连接到另一个套接字服务器,他们仍然能够发出和接收消息
不确定您现在在哪里托管,但有许多服务可用,并且根据您想要管理的数量,您可能希望查看来自数字海洋的 'apps' 等服务。它基本上是一个 'CAAS' 服务,您可以在 GIT 中拥有 socket.io 服务器,然后将其部署到 运行 容器中,DO 将处理您的每个之间的平衡运行 'APPs',因此您可以根据需要按需扩展 运行 个实例。虽然它不是最便宜的,并且从带宽等角度来看有一些缺点,但如果您知道允许您按比例放大和缩小等的尖峰,它会很好。