本篇文章并不是教你怎么用阿里云、谷歌云等等云框架的FaaS服务,而是教你如何从0开始打造一个自己的FaaS服务。
受限于人力及成本原因,现在的FaaS服务基本上可以说是“大厂玩物”,而网上鲜有相关代码的实现,因此我才打算写一篇文章,和大家分享如何从0开始打造一个Nodejs的FaaS服务。
本篇文章中的项目tiny-node-faas已经上线并开源至GitHub,欢迎各位使用。
访问链接:http://www.shadowingszy.top/tiny-node-faas/index.html
源码地址:https://github.com/shadowings-zy/tiny-node-faas
Serverless,直译就是无服务器,是指构建和运行不需要服务器管理的应用程序的概念。Serverless能够按需提供后端服务,用户可以直接编写和部署代码,而不必担心底层基础架构。
简单来说,如何判断一个服务是不是Serverless的呢?如果你在开发这个服务的时候,完全不知道“服务器多少”、“容器环境”等等和基础架构相关的东西的时候,那么这个服务就是Serverless的。
FaaS是Function as a Service的缩写,可以简单理解为功能服务化。FaaS提供了一种服务碎片化的软件架构范式。FaaS可以让研发只需要关注业务代码逻辑,不再关注技术架构。
举个例子吧,如果我们要使用koa框架写一个hello world服务,我们得这样写:
const Koa = require('koa');
const app = new Koa();
const handler = async (ctx) => {
ctx.body = 'hello world'
}
app.use(handler);
app.listen(8080,() => {
console.log('8080端口已启动')
});
而如果使用FaaS服务,我们只需要关注下面这部分,其余的工作,比如服务创建、冷启动、负载均衡等等都由FaaS的提供方做了。
const handler = async (ctx) => {
ctx.body = 'hello world'
}
之所以做Nodejs的FaaS服务,是因为有越来越多的开发者,以及越来越多的后台服务,选择使用Nodejs。
这其中当然有Nodejs本身“单线程异步非阻塞”的特性带给我们的简单直接的编程体验,也有一部分原因在于“前端全栈化”趋势会促使一部分前端工程师写后端代码逻辑。
而更值得关注的是,由于技术方向不同,不少前端开发工程师对运维、服务器的相关知识比较薄弱,因此为他们提供一个Nodejs的FaaS服务,能让其从运维中脱离出来,使开发者更聚焦于业务代码逻辑,是非常有前景的事情。
“如何实现Nodejs的FaaS服务”,这个问题可以换成下面这个问题:
如何才能在Nodejs中新建一个sandbox并在这个sandbox中执行指定的代码,并拿到返回值呢?
Nodejs实际上已经提供了这样一个模块——vm模块,下面是文档:
https://nodejs.org/api/vm.html
使用起来也很简单:
const vm = require('vm');
const code = 'console.log("hello world!")'
const sandbox = {
console };
vm.createContext(sandbox);
const data = vm.runInNewContext(code, sandbox);
通过vm模块,我们就能在一个新的sandbox中执行JavaScript代码并拿到返回值了
如图所示,tiny-node-faas由四部分组成:
1、管理平台前端
2、函数管理功能
3、函数存储功能
4、函数执行功能
2、3、4三者则是FaaS服务中最重要的三个组成部分。
const vm = require('vm')
const runFunction = async (code) => {
let timer = null
const result = await new Promise((resolve, reject) => {
const sandbox = {
require,
console
}
try {
timer = setTimeout(() => {
reject(new Error('Execute function time out'))
}, 10000)
vm.createContext(sandbox)
const data = vm.runInNewContext(code, sandbox)
resolve(data)
} catch (error) {
reject(error)
}
}).catch((err) => {
return err instanceof Error ? err : new Error(err.stack)
})
if (timer) {
clearTimeout(timer)
timer = null
}
return result
}
上面代码中的runFunction
方法就是最核心的执行FaaS函数的方法,我们只需要传入code,即需要运行的代码,这个方法就会新建一个sandbox并运行代码,然后会将运行结果返回出来。