gpt4 book ai didi

node.js - 通过多进程将套接字存储在Node.js中

转载 作者:太空宇宙 更新时间:2023-11-03 23:23:48 25 4
gpt4 key购买 nike

我有一个NodeJS TCP服务器,它将每个套接字连接存储在一个数组中,其中包含一些我需要与之关联的其他信息:

var clients = [];

net.createServer(sslOptions, function (_socket) {
_socket.name = 'someName';
_sockect.foo = 'bar';
clients.push(_socket);
}

服务器经常对阵列客户端进行迭代以获取一些业务逻辑。有时会触发条件,因此我需要断开其中一个套接字的连接:
if(condition) {
for(let x = 0; x < clients.length; x++) {
if(clients[x].name == 'someName') {
clients[x].disconnect();
clients.splice(x, 1);
return;
}
}
}

有两种让我担心的方法。如果我决定使用 PM2 clusters或任何其他Node.js进程管理器复制应用程序以实现负载平衡,那么不同的进程如何共享相同的阵列客户端?如果某个进程在迭代数组而其他进程正在删除索引时会发生什么情况,则可能存在竞争条件,最终可能导致错误的断开连接和删除。

解决方案当然是使用原子数据库之类的东西,但是我不知道如何将套接字存储在Mongo或Redis之类的东西中。

最佳答案

How can the different process share the same array clients?



他们没有。

两个node.js进程无法访问同一数组(它们位于单独的进程和单独的Java解释器中),因此在这方面没有机会进行直接数据共享或相应的竞争条件。

And what happens if a process is iterating the array while other is removing an index, there could be race conditions that can eventually lead to mistaken disconnections and deletion.



因为Javascript仅在一个线程中运行所有Javascript,所以您不能有多个Javascript都试图同时修改同一数组。如果要迭代数组并进行异步调用,则需要执行一些安全操作,因为在等待异步响应时数组可能会更改,但是例如在同步 for循环运行时,数组不能更改。

要了解如何处理多个node.js进程,您可以从socket.io服务器如何支持集群中学到很多东西,因为它有相同的基本问题需要解决。他们希望能够发送到所有连接的套接字(跨所有群集服务器)或任何特定的连接(无论消息起源于哪个服务器,以及所连接的客户端实际连接到的服务器)。

对于socket.io,他们基本上使用所有集群进程都可以访问的公共(public)中间存储(在这种情况下为redis数据存储)。由于redis是为多用户访问而设计的,因此客户端可以谨慎使用其API并避免出现竞争情况。然后,redis存储区用于存储有关每个已连接用户的元数据,以及用于指示服务器进程包含其当前连接的指示符。

要从任何群集服务器进程向特定用户发送消息,您需要从Redis存储中获取该用户的数据。如果用户正在连接到本地服务器进程(您正在从中进行查找的进程),那么您可以直接从元数据中获取其ID,然后在您自己的本地已连接客户端列表中查找它们,并将其发送到他们的 socket 。

如果它们连接到另一台服务器,则向该服务器发送一条消息,要求他们将消息中继到特定的套接字ID值。当该服务器接收到该消息时,它将在自己的与该进程连接的客户端列表中查找该ID,获取其套接字并向其发送消息。

当客户端与任何集群过程连接或断开连接时,会在Redis存储中添加或删除连接。请记住,由于套接字对象是特定进程的本地对象,因此您不会(也不能)将实际的套接字对象存储在redis存储区中。您仅将元数据存储在redis存储中,并存储在服务器ID中,因此任何查询redis存储的人都可以确定已连接的用户以及当前连接的服务器。通常,您将使用唯一的用户名或其他唯一的ID来表示每个用户,并且类似地,服务器将通过某种ID(可能是主机/端口号)来表示,该ID允许您连接到他们。

为了避免Redis存储中的竞争状况,您只需要使用良好的多用户数据管理实践,并在修改数据时使用正确的Redis API,就可以避免大多数问题。有关比赛条件的更多建议,可能需要您更详细地说明您要修改的内容。但是,大多数情况下,您只是在连接时添加了一个已连接的用户,在断开连接时就删除了一个已连接的用户,而使用正确的API进行操作时,这些操作都是原子操作。如果要获取用户列表然后对其进行操作,则在查询用户的时间与尝试实际发送给用户的时间之间断开连接时,您将具有潜在的竞争条件。为此,如果您在尝试向错误发送消息时恰好消失了这些错误,则只需要准备适当地处理它们即可。

每个单独的node.js进程将维护自己的套接字数组,这些套接字连接到自己的进程。由于node.js以单线程方式运行JS,并且该数组不与任何其他进程或线程共享,因此,如果代码编写正确,则仅在访问或维护该数组时就没有竞争条件的机会。

A solution, of course, is to use something like an atomic DB, but I don't know how can I store a socket in something like Mongo or Redis.



您无需在这些数据库中存储套接字。您存储套接字ID值和服务器ID值。服务器ID值(可以是主机/端口字符串)可用于连接到具有该套接字ID的连接的正确服务器。然后,接收服务器可以使用套接字ID在其自己的数组中查找用于其自身连接的实际套接字对象。

关于node.js - 通过多进程将套接字存储在Node.js中,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/46838612/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com