生产环境中的NodeJS和Socket.io:如何处理状态

3
在开发环境中,我有一个单独的nodejs进程,它在给定端口上监听socket.io。一旦客户端连接,就需要维护状态。nodejs脚本对文件进行一些处理,并通过sockets发送处理状态。这类似于一个可能永远不会结束的批处理。
如果客户端关闭浏览器然后再次打开(在开发环境中),网页将简单地重新连接到套接字并获取该特定用户后台处理文件处理的当前状态。
为了每个用户都有一个单一的进程,并确保用户始终重新连接到他们启动的同一进程上,在同一端口上,我需要管理这些进程,并为每个用户预留端口。
如何建立这种情况的单个nodejs入口点,分叉进程并相应地路由套接字连接,使用例如Nginx、PM2和/或Nodejs集群。换句话说,在这种场景下,最好的生产架构是什么?
关于状态问题:
我持有的状态不仅仅是可以存储在数据库中的变量。我有连续的文件读取流,按照用户通过连接到该进程的sockets配置的顺序依次处理。该进程还连接到另一个服务器之间的套接字,并且必须保持连接。
2个回答

2
我建议将进程的pid暴露给路由脚本,并利用会话和cookie,将其与用户分配的pid一起保存到Redis DB中。因此,在连接时,您设置一个带有用户ID的日期时间哈希的cookie和会话(取决于是否将用户帐户与客户端关联),将其保存在用户cookie中,并将pid保存在会话中。然后,您可以将用户重定向到路由器中对应的进程分支。如果您需要参考代码,请查看此答案,并使用节点脚本作为代理。
const socketio = require('socket.io');
const redis = require('redis');

on.connect((req, res) => {
    let uid,
        pid,
        port;

    // if user does not have the cookie yet
    if (!req.cookies.uid) {
        uid = getNewUserID(req); // create uid from information from the request, set a cookie later
        pid = createWorker(uid); // generate new socket.io worker in cluster and return pid
        port = getSocketPort(pid); // get socket port from worker

        // save acquired variables to database
        redis.set(uid, [pid, port], function(err, reply) {
            if (err) throw err;
            console.log(reply);
        });
    };

    uid = req.cookies.uid; // get uid from request
    pid = getPid(uid); // get pid from redis

    socketio(getSocketPort(pid)); // connect client to port of correct worker
});

对于你的readstreams,你可以在相应的worker内部处理它们。 一个worker等于一个socket.io进程。


这可以使用Nginx反向代理完成吗?如何编写路由脚本?它是一个像Nginx反向代理一样运行的Node.js脚本吗? - Valdir
@Valdir NginX反向代理将客户端重定向到不同的服务和服务器,据我所知。在这种情况下,您只需重定向到集群中的分支即可。我更新了我的答案,并提供了一个示例脚本,以便您更好地理解我的答案。 - Tom M
是的,看起来是这条路径。 - Valdir

0

不要将您的状态保存在内存中。可以保存在数据库中(Redis 是一个很好的数据库选择,因为它基于内存且超级快),这样您就不必担心套接字重新连接到相同的进程甚至相同的服务器(如果您有多个带负载均衡的服务器)。


我需要连接到相同的进程,因为我需要能够播放/暂停/修改将在该特定进程上运行的用户的批处理过程。 - Valdir

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