NodeJS如何处理多核并发?

时间:2015-07-11 07:14:07

标签: node.js concurrency

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

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

我一直在搜索互联网,但似乎没有人关心这一点。任何人都可以解释NodeJS的集群架构师吗?非常感谢

加上:
只是为了澄清,我使用快递,它不像在不同的端口上运行多个实例,它实际上是在同一个端口上侦听,但每个CPU上有一个进程竞争处理请求......

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

1 个答案:

答案 0 :(得分:0)

您问题的核心是:

  

NodeJS将不得不像其他多线程架构师那样面对传统的并发问题,例如,写入不受写保护的同一对象?

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

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

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

当然,node是一个用C编写的程序,可以很容易地在C语言中扩展,npm上的模块可以实现线程,互斥和共享内存。如果您故意选择违反node.js / javascript设计理念,那么您有责任确保没有任何问题。

补充答案:

  

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

首先,让我澄清你所犯的错误观念。这不是real single-threaded application的问题。这是伪代码中的单线程应用程序:

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中都没有异步单线程程序可以免于此。

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

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