【问题标题】:node.js performance optimization and single threaded architecturenode.js 性能优化和单线程架构
【发布时间】:2016-09-06 20:10:50
【问题描述】:

我正在使用 express 运行 Node.js 应用程序,并希望开始提高其性能。定义了几条路线。让我们举一个基本的例子:

app.get('/users', function (req, res) {
    User.find({}).exec(function(err, users) {
        res.json(users);
    }
});

假设我们有 3 个客户端 A、B 和 C,他们尝试使用此路由。他们的请求以 A、B、C 的顺序到达服务器,中间相差 1 毫秒。

1.如果我正确理解了node.js架构,每一个请求都会立即处理,因为Users.find()是异步的,还有非阻塞代码?

让我们用一个同步调用来扩展这个例子:

 app.get('/users', function (req, res) {
        var parameters = getUserParameters();

        User.find({parameters}).exec(function(err, users) {
            res.json(users);
        }
    });

相同的请求,相同的顺序。 getUserParameters() 需要 50 毫秒才能完成。

2。 A 将进入路由回调函数并阻塞 node.js 线程 50 毫秒。 B 和 C 将无法进入该功能,必须等待。当 A 完成 getUsersParameters() 时,它将继续异步 User.find() 函数,B 现在将进入路由回调函数。 C 仍需再等待 50 毫秒。当B进入异步函数时,C的请求终于可以处理了。综合来看:C 需要等待 50 毫秒 A 完成,50 毫秒 B 完成,50 毫秒自己完成(为简单起见,我们忽略了异步函数的等待时间)?

现在假设我们还有一条路线,只有管理员可以访问,并且每分钟都会通过 crontab 调用。

app.get('/users', function (req, res) {  
    User.find({}).exec(function(err, users) {
        res.json(users);
    }
});

app.get('/admin-route', function (req, res) {
    blockingFunction(); // this function takes 2 seconds to complete
});

3.当请求 X 命中admin-route 并调用blockingFunction() 时,在 X 的请求之后立即调用 /users 的 A、B 和 C 是否必须等待 2 秒才能进入路由回调函数?

4.我们是否应该将每个自定义函数,即使它只需要 4 毫秒,都作为带有回调的异步函数?

【问题讨论】:

  • 与这个问题无关,但我听说 express 已经死了。
  • Node/JS 中的blockingFunction 是什么? Afaik,一切都是围绕事件循环建模的。

标签: node.js


【解决方案1】:

答案是“是”,第 3 条:阻塞意味着阻塞事件循环,这意味着任何 I/O(如处理 HTTP 请求)都将被阻塞。在这种情况下,应用在这 2 秒内似乎没有响应。

但是,您必须做一些非常疯狂的事情才能使同步代码花费 2 秒(或者非常繁重的计算,或者使用 fs 等模块提供的大量 *Sync() 方法)。如果您确实无法使该代码异步,则应考虑在单独的进程中运行它。

关于#4:如果您可以轻松地使其异步,您可能应该这样做。然而,仅仅让你的同步函数接受一个回调并不能奇迹般地使它异步。这取决于函数是否以及如何使其异步。

【讨论】:

    【解决方案2】:

    基本原则是任何锁定 CPU(例如长时间运行的 for 循环)或任何使用 I/O 或网络的东西都必须是异步的。您还可以考虑将 CPU 密集型逻辑从节点 JS 中移出,也许到一个 Java/Python 模块中,该模块公开一个节点 JS 可以调用的 WebService。

    顺便说一下,看看这个模块(可能还没有准备好生产)。介绍了NodeJS中多线程的概念:https://www.npmjs.com/package/webworker-threads

    【讨论】:

      【解决方案3】:

      #3 是的

      #4 Node.js 用于异步编程,因此最好遵循这种方法以避免性能意外

      同时,您可以使用 Node.js 的 cluster 模块来提高应用的性能和吞吐量。

      【讨论】:

        【解决方案4】:

        您可能需要先垂直扩展您的应用程序。查看 Node.js 集群模块。您可以通过在每个核心上生成工人来利用机器的所有核心。集群是在父节点进程下运行的类似工作人员池。工人是使用 child_processes 模块的 fork() 方法产生的。这意味着工作人员可以共享服务器句柄并使用进程间通信与父节点进程进行通信。

        var cluster = require('cluster')
        var http = require('http')
        var os = require('os')
        var numCPUs = os.cpus().length
        
        if (cluster.isMaster) {
            for (var i = 0; i < numCPUs; i++) {
                cluster.fork()
            }
        } else {
            // Define express routes and listen here
        }

        【讨论】:

          猜你喜欢
          • 2011-06-14
          • 1970-01-01
          • 2012-09-07
          • 2015-02-12
          • 2018-08-26
          • 2017-06-29
          • 2015-09-21
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多