这篇文章是早期写的存在很多问题,请忽略
好吧我承认我是标题党,但这种方法确实解决了node的CPU密集型计算时造成服务无法响应或响应过慢问题,其实我讲的的是Faas的serverless简单使用,基于某云平台进行讲解。
写在前面:
大家都知道node.js基于EventLoop,本质上就是对异步进行排队运算,所以这就面临一个问题,如果大量计算放入了队列中运算,后面就要等前面运行完,严重导致队列堆积导致请求超时之类的问题。但目前很多人用线程来解决,我觉得这样不好,会增加代码复杂度,并且如果有海量运算的话也没办法开无数多的线程(爆机器问题(所以有线程池)和大于逻辑核的无意义)。那我们有没有不增加复杂度,来解决这个问题呢?的确有,Faas框架来实现的serverless就能将CPU密集计算问题迎刃而解(原因文末说明)。最早是亚马逊的lambda,当目前国内也有类似实现,那我就选择国内某云的函数计算来验证是否解决CPU密集计算问题,同时会对利用某云函数计算的使用进行一次详解(本来是写了具体云平台,但为了避免广告嫌疑改某云)。
首先我们要创建一个函数计算的服务和方法
当然我们要先选择某云的产品列表的“函数计算”来创建服务 一般选择白板函数就好 我们用著名的斐波那契来模拟CPU密集型吧 代码奉上
module.exports.handler = function(event, context, callback) {
let req = JSON.parse(event);
//为什么是40,因为每个函数计算时间不能超过3秒
let num = req.queryParameters.num>0?
req.queryParameters.num:
Math.ceil(Math.random()*40);
//由于这个直接作为页面数据,所以api网关需要状态码和页面显示信息
callback(null,{
body:`num is ${num},fibo is ${fibo(num)}`,
statusCode:200}
);
};
function fibo(num)
{
if(num<2){return 1;}
return fibo(num-1)+fibo(num-2);
}
接下来创建对应的Api网关
由于函数计算的方法可以互相调用和触发调用,api网关的作用就是为了通过用户访问网关触发函数计算的方法调用
当然我们要先选择某云的产品列表的“api网关”来创建网关服务 创建分组后,走如下图步骤 安全认证的作用是只让自己的手机App或自己的SDK用启用的,我们希望每个用户都能访问,改成无认证就好 接下来定义自己给别人访问的url,同时可以将自己域名绑定到自己的分组,实现通过自己域名访问 这里的要点就是选择函数服务,然后填入函数计算当时创建的服务名和方法名就好。 最后发布上线就好,当然你还可以在外面的api试调先调用试试。
对比一下自己本机开的服务进行压测
本机代码
var http = require('http');
var url = require('url');
function fibo(num)
{
if(num<2){return 1;}
return fibo(num-1)+fibo(num-2);
}
http.createServer(function(req, res){
res.writeHead(200, {'Content-Type': 'text/plain'});
var params = url.parse(req.url, true).query;
let num = params.num>0?params.num:Math.ceil(Math.random()*40);
res.end(`num is ${num},fibo is ${fibo(num)}`);
}).listen(3000);
压测结果
某云函数计算压测结果(我认为出现计算超时丢包是正确的,但也印证该云平台没有根据我想要的及时伸缩): 本机压测结果(已被CPU密集计算阻塞):
原因
由于函数计算会在访问量大的时候进行动态伸缩(其实就是加实例和机器,但只对需要的函数伸缩不像Paas要对整个平台伸缩造成浪费)所以在CPU密集时,它会为了保持及时的响应速度,进行进行伸缩,不至于CPU密集会导致无法访问或访问过慢。
最后
如果使用此某云实现的Serverless,那么建议使用该云推出开发工具,因为能更快用自己的IDE进行编码和开发,本人使用web页面,纯粹是为了更好展现功能。原文地址:https://github.com/zy445566/myBlog/tree/master/20171214serverless
好不容易发个科普性水贴啊啊啊😯
这种“曲线救国”的策略是没人用的。
有空去写这么一个云平台的人也是蛋疼。
有那个空去学习/使用那个云平台,但不如花点时间,多学习其他语言。
让nodejs做它擅长的事,不擅长的交给其他语言去做。
serverless拿来做CPU密集计算? 允许我懵逼一会…
node已经支持多线程了啊: napajs.
@axetroy 我的重点不在某个云平台上。 而是证明Faas架构下可以解决node的CPU密集运算的问题。而且我觉得Faas一定是未来的趋势。而真正可伸缩Faas开源框架的出现只是时间问题。 侧重点是在未来可能任何语言的性能问题都会被大量缩小,语言未来的重点肯定会集中在体验和开发速度方面。 当然我也可能是个傻逼,时间会证明一切。
@XiaozhongLiu 我上面说了,并不觉得多线程是个好的解决方案。 而且我觉得充分利用单机性能会被弱化, 因为我更倾向利用海量渣渣实例(比如一台中或小型级开海量渣渣实例)来支持性能。 虽然现在很多公司也是这么干的😂
这样通信的成本大于 cpu消耗的成本
这个方法的前提依旧是完整的计算过程也并没有非常的耗时,如果真的是一个复杂的长时间的 cpu 密集型运算,分散到无数个实例不能缓解单个计算响应慢甚至由此导致的 OOM 的问题,而如果对计算本身进行拆分,又要自己做一套数据同步 所以归根结底,还是要去衡量合适的语言来去做合适的事
@hyj1991 这些计算的异构处理,faas平台已经帮你做掉了. 你唯一关心的就是,输入和输出.
其实按照楼主的观点,肯本没必要用faas这种目前还没有很好的案例和实施复杂的东西. 直接用RESTful把cpu密集计算切出去然后用java或者c实现下不就得了?
faas也不是用来干这个的. 而且如果这是高频接口,这样的收费可能反而更贵.
@178220709 我就是这个意思,rest 处理是一种方式,就算认死 node ,也可以尝试下写扩展来做
@hyj1991 理论上是计算本身拆分,拆分成小函数,只要调用这些小函数就能实现计算动态伸缩分摊。 只不过目前至少现在的云平台做的还不够好,就算真这样拆分理论上现有的云平台未必能够实现。
@zy445566 计算本身的拆分我觉得不大可能平台自动给你做掉,这属于业务逻辑部分还是得要你自己去控制的,这样做了其实和楼上提到的 rest 的方案复杂度没差多少,而且逻辑拆分过于零散了还不易于后期的维护升级
@178220709 对的,现有的Faas云服务现在其实还差的很远。 也没有很好的案例,同时实现技术上也是千差万别,没有成立协会统一标准。 但我觉得以后未必就不行
@hyj1991 嗯嗯,毕竟缺点是必然存在的,没有东西是十全十美的
。。。。。。。。。。。。。。我宁愿跨进程调用c程序都比这个看着方便。。。
@alsotang 哈哈,看起来是有点恶心😄😄😄 其实是有工具的,用工具会方便很多,我只是方便讲解所以用了页面。 @JacksonTian 应该很熟悉工具
我在去年的 沪JS 上演示过,基于 API Gateway 和 函数计算,搭建无服务器应用。