const computecluster = require('compute-cluster'); // allocate a compute cluster var cc = new computecluster({ module: './worker.js' }); // run work in parallel cc.enqueue({ input: "foo" }, function (error, result) { console.log("foo done", result); }); cc.enqueue({ input: "bar" }, function (error, result) { console.log("bar done", result); });
fileworker.js 中响应了 message 事件,对传入的请求进行处理:
process.on('message', function(m) { var output; // do lots of work here, and we don't care that we're blocking the // main thread because this process is intended to do one thing at a time. var output = doComputationWorkSync(m.input); process.send(output); });
无需更改调用代码,compute-cluster 模块就可以和现有的异步API整合起来,这样就能以最小的代码量换来真正的多核并行处理。
我们从四个方面来看看这个方案的表现。
多核并行能力:子进程使用了全部的核心。
响应能力:由于核心管理进程只负责启动子进程和传递消息,大部分时间里它都是空闲的,可以处理更多的交互请求。
即使机器的负载压力很大,我们仍然可以利用操作系统的调度器来提高核心管理进程的优先级。
简单性:使用了异步API来隐藏了具体实现的细节,我们可以轻易地将该模块整合到现在项目中,甚至连调用代码无需作改变。
现在我们来看看,能不能找一个方法,即使负载突然激增,系统的效率也不会异常下降。
当然,最佳目标仍然是,即使压力激增,系统依然能高效运行,并处理尽量多的请求。
为了帮助实现优秀的方案,compute-cluster 不仅仅只是管理子进程和传递消息,它还管理了其他信息。
它记录了当前运行的子进程数,以及每个子进程完成的平均时间。
有了这些记录,我们可以在子进程开启之前预测它大概需要多少时间。
据此,再加上用户设置的参数(max_request_time),我们可以不经过处理,直接就关闭那些可能超时的请求。
这个特性让你可以很容易根据用户体验来确定你的代码。比如说,“用户登录的时候不应该等待超过10秒。”这大概等价于将 max_request_time 设置为7秒(需要考虑网络传输时间)。
我们在对 Persona 服务进行压力测试后,得到的结果很让人满意。
在压力极高的情况下,我们依然能为已认证的用户提供服务,还阻止了一部分未认证的用户,并显示了相关的错误信息。
您可能感兴趣的文章: