node.js - NodeJS如何处理多核并发?

标签 node.js concurrency

目前我正在开发一个由另一个java应用程序更新的数据库,但需要一个NodeJS应用程序来提供Restful API供网站使用。为了最大限度地提高 NodeJS 应用程序的性能,它被集群化并在多核处理器中运行。

但是,根据我的理解,集群 NodeJS 应用程序在每个 CPU 核心上都有自己的事件循环,如果是这样,这是否意味着对于集群架构师,NodeJS 将不得不像其他多线程架构师一样面对传统的并发问题,例如,写入未写保护的同一对象?或者更糟糕的是,因为它是同时运行的多进程,而不是一个进程中的线程被另一个进程阻塞...

我一直在互联网上搜索,但似乎根本没有人关心这一点。谁能解释一下NodeJS的集群架构?非常感谢

添加:
澄清一下,我使用的是express,它不像在不同端口上运行多个实例,它实际上是在监听同一个端口,但每个CPU上都有一个进程竞争处理请求......

我现在想知道的典型问题是:一个基于给定对象 B 更新对象 A 的请求(未完成),另一个使用给定对象 C 再次更新对象 A 的请求(在第一个请求之前完成)...然后结果将基于对象 B 而不是 C,因为第一个请求实际上在第二个请求之后完成。
这在真正的单线程应用程序中不会出现问题,因为第二个将始终在第一个请求后执行...

最佳答案

您问题的核心是:

NodeJS will have to face traditional concurrency issues like in other multi-threading architect, for example, writing to same object which is not writing protected?

答案是这种情况通常是不可能的,因为 Node.js 进程不共享内存。进程A中的ObjectA,ObjectB和ObjectC与进程B中的ObjectA,ObjectB和ObjectC不同。并且由于每个进程都是单线程,因此不会发生争用。这是您发现 Node.js 没有附带信号量或互斥模块的主要原因。另外,node.js 没有附带任何线程模块

这也解释了为什么“没人关心”。因为他们认为这不可能发生。

node.js 集群的问题之一是缓存。由于进程A中的ObjectA和进程B中的ObjectA是完全不同的对象,因此它们将具有完全不同的数据。传统的解决方案当然不是在应用程序中存储动态状态,而是将它们存储在数据库(或内存缓存)中。如果需要,还可以在代码中实现您自己的缓存/数据同步方案。毕竟,这就是数据库集群的工作原理。

当然,node 作为一个用 C 编写的程序,可以很容易地用 C 进行扩展,并且 npm 上有实现线程、互斥和共享内存的模块。如果您故意选择违背 node.js/javascript 设计理念,那么您有责任确保不会出现任何问题。

<小时/>

附加答案:

a request to update Object A base on given Object B(not finish), another request to update Object A again with given Object C (finish before first request)...then the result would base on Object B rather than C, because first request actually finishes after the second one. This will not be problem in real single-threaded application, because second one will always be executed after first request...

首先,让我澄清一下您的一个误解。这对于真正的单线程应用程序来说不是问题。这是伪代码中的单线程应用程序:

function main () {
    timeout = FOREVER
    readFd = []
    writeFd = []

    databaseSock1 = socket(DATABASE_IP,DATABASE_PORT)
    send(databaseSock1,UPDATE_OBJECT_B)

    databaseSock2 = socket(DATABASE_IP,DATABASE_PORT)
    send(databaseSock2,UPDATE_OPJECT_C)

    push(readFd,databaseSock1)
    push(readFd,databaseSock2)

    while(1) {
        event = select(readFD,writeFD,timeout)
        if (event) {
            for (i=0; i<length(readFD); i++) {
                if (readable(readFD[i]) {
                    data = read(readFD[i])

                    if (data == OBJECT_B_UPDATED) {
                        update(objectA,objectB)
                    }
                    if (data == OBJECT_C_UPDATED) {
                        update(objectA,objectC)
                    }
                }
            }
        }
    }
}

如您所见,上面的程序中没有线程,只是使用 select 系统调用进行异步 I/O。上面的程序可以很容易地直接翻译成单线程 C 或 Java 等(事实上,类似的东西是 JavaScript 事件循环的核心)。

但是,如果对 UPDATE_OBJECT_C 的响应在对 UPDATE_OBJECT_B 的响应之前到达,则最终状态将是 objectA 根据 objectB 而不是 objectC 的值进行更新。

任何语言中的异步单线程程序都无法避免这种情况,node.js 也不异常(exception)。

但请注意,您最终不会处于损坏状态(尽管您最终会处于意外状态)。多线程程序的情况会更糟,因为如果没有锁/信号量/互斥体,对 update(objectA,objectB) 的调用可能会被对 update(objectA,objectC) 和 objectA 的调用中断将会被损坏。这是您在单线程应用程序中不必担心的问题,在 Node.js 中也不必担心。

如果您需要严格的时间顺序更新,您仍然需要等待第一次更新完成,将第一次更新标记为无效或为第二次更新生成错误。通常,对于网络应用程序(例如 stackoverflow),会返回错误(例如,如果您尝试提交评论,而其他人已经更新了评论)。

关于node.js - NodeJS如何处理多核并发?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/31354509/

相关文章:

javascript - express 和 Jade : loop and create dynamic ids

javascript - Gatsby worker 错误 :

javascript - 你能用 Facebook 的 Flow 注释那些没有用 ES6 class 关键字定义的类吗?

java - 线程安全程序的方法

MySQL 事务和并发插入

javascript - Firebase - Geofire 和云功能。功能结束是否意味着不再有听众?

javascript - websocket php 与 Node js

spring-boot - 在 Spring 中按条件同步并发事务

java - 我可以用java代码解决数据库并发问题吗?

.net - MS Access数据库的自动压缩和修复