node.js性能优化和单线程架构

我运行一个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()是asynchronous的并且有非阻塞代码?

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

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

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

2. A将进入路由callback函数并阻塞node.js线程50毫秒。 B和C将不能进入该function,必须等待。 当A完成getUsersParameters() ,它将继续使用asynchronous的User.find()函数,B现在将进入路由callback函数。 C仍然需要等待50毫秒。 当B进入asynchronous函数时,可以最终处理C的请求。 总结一下:C必须等待A完成50毫秒,B完成50毫秒,完成50毫秒(为简单起见,我们忽略asynchronous函数的等待时间)?

现在假设我们还有一个路由,它只能由pipe理员访问,并且会通过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秒,直到它们甚至进入路由callback函数?

4.我们是否应该将每个自定义函数作为一个具有callback函数的asynchronous函数,即使只需要4毫秒?

答案是“是”,在#3:阻塞意味着阻塞事件循环,这意味着任何I / O(如处理HTTP请求)将被阻止。 在这种情况下,应用程序在2秒内看起来没有反应。

但是,你必须为同步代码花费2秒(非常繁重的计算,或者使用像fs这样的模块提供的许多*Sync()方法*Sync()来做相当多的事情。 如果你真的不能使代码asynchronous,你应该考虑在一个单独的进程中运行它。

关于#4:如果你可以很容易地使其asynchronous,你可能应该。 但是,只有让你的同步函数接受callback并不奇迹般地使其asynchronous。 这取决于函数的function,以及如何使其asynchronous。

基本原理是lockingCPU(例如长时间运行的循环)或任何使用I / O的networking,或者networking必须是asynchronous的。 你也可以考虑将CPU密集型逻辑从节点JS中移出,也许可以放到一个Java / Python模块中,这个模块公开了一个Web服务,JS可以调用哪个节点。

顺便说一下,看看这个模块(可能不是生产就绪)。 它在NodeJS中引入了multithreading的概念: https : //www.npmjs.com/package/webworker-threads

#3是的

#4 Node.js是用于asynchronous编程,因此很好地遵循这种方法来避免性能上的惊喜

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

您可能需要先垂直缩放您的应用程序。 查看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 }