You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

124 lines
16 KiB
Markdown

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

# 03 | 原理FaaS的两种进程模型及应用场景
你好我是秦粤。上一讲我们通过一个Node.js纯FaaS的Serverless应用给你介绍了Serverless引擎盖下的运作机制总结来说FaaS依赖分层调度和极速冷启动的特性在无事件时它居然可以缩容到0就像我们的声控灯一样有人的时候它可以亮起来没人的时候又可以自动关了。
听完了原理我估计你肯定会问FaaS这么好但是它的应用场景是什么呢今天我们就来一起看下。不过想要理解FaaS的应用场景我们就需要先理解FaaS的进程模型这也是除了冷启动之后的另外一个重要概念。
## FaaS进程模型
咱先回想一下上节课的FaaS的冷启动过程我们知道容器和Runtime准备阶段都是由云服务商负责的我们只需要关注具体的函数执行就可以了。而函数执行在FaaS里是由“函数服务”负责的当函数触发器通知“事件”到来时函数服务就会根据情况创建函数实例然后执行函数。当函数执行完之后函数实例也随之结束自己的使命FaaS应用缩容到0然后开始进入节能模式。
上面这套逻辑是我们上节课讲的,课后有同学就问,函数执行完之后实例能否不结束,让它继续等待下一次函数被调用呢?这样省去了每次都要冷启动的时间,响应时间不就可以更快了吗?
是的本身FaaS也考虑到了这种情况所以从运行函数实例的进程角度来看就有两种模型。我也画了张图方便你理解。
* 用完即毁型函数实例准备好后执行完函数就直接结束。这是FaaS最纯正的用法。
* 常驻进程型:函数实例准备好后,执行完函数不结束,而是返回继续等待下一次函数被调用。**这里需要注意即使FaaS是常驻进程型如果一段时间没有事件触发函数实例还是会被云服务商销毁。**
![](https://static001.geekbang.org/resource/image/84/20/84a81773202e2599474f9c9272a65d20.png "模型示意图")
这两个模型其实也对应两种不同的应用场景。我举个例子比如你要把我们第一讲中的“待办任务”应用部署上线还记得小程同学吧他完成了第一个版本他用Express.js\[1\] 框架开发的MVC架构View层他采用流行的React\[2\]并且使用了Ant Design Pro\[3\] React组件库Model数据库采用MongoDB。小程的第一个版本就是一个典型的传统Web服务。
从可控性和改造成本角度来看Web服务服务端部署方案最适合的还是托管平台PaaS或者自己搭服务跑在IaaS上。正如我上一讲所说使用FaaS就必须在FaaS的条件限制内使用最佳的做法应该是一开始就选用FaaS开发。
但是小程的运气比较好我们查了一下文档发现FaaS的Node.js的Runtime是支持Express的所以我们只需少量修改**小程的第一个版本就可以使用FaaS的常驻进程方案部署。**
这里我要做个对比。在之前假设没有FaaS我们要将应用部署到托管平台PaaS上启动Web服务时主进程初始化连接MongoDB初始化完成后持续监听服务器的80端口直到监听端口的句柄关闭或主进程接收到终止信号当80端口和客户端建立完TCP链接有HTTP请求过来服务器就会将请求转发给Web服务的主进程这时主进程会创建一个子进程来处理这个请求。
而在FaaS常驻进程型模式下首先我们要改造一下代码Node.js的Server对象采用FaaS Runtime提供的Server对象然后我们把监听端口改为监听HTTP事件启动Web服务时主进程初始化连接MongoDB初始化完成后持续监听HTTP事件直到被云服务商控制的父进程关闭回收。
当HTTP事件发生时我们的Web服务主进程跟之前一样创建一个子进程来处理这个请求事件。主进程就如我们上图中绘制的那个蓝色的圆点当HTTP事件发生时它创建的子进程就是蓝色弧形箭头当子进程处理完后就会被主进程回收。
在我看来常驻进程型就是为了传统MVC架构部署上FaaS专门设计的。数据库也可以使用原来的DB连接方式不过这样做会增加冷启动的时间我特意在图中用曲线代表时间增加从而导致第一次请求长延迟甚至失败。比较适合的做法是我们[\[第 1 课\]](https://time.geekbang.org/column/article/224559) 中讲Serverless架构时说的数据持久化采用BaaS服务。
那么我们能否用用完即毁型来部署小程的这个MVC架构的Web服务呢可以但是我不推荐你这样做因为用完即毁型对传统MVC改造的成本太大。
![](https://static001.geekbang.org/resource/image/2f/33/2f1c4643057d8fbcbec6f7514dd9cd33.png "模型示意图")
说到这里我们再将上面对比两个模型的示意图镜头再拉远一点加上HTTP触发器看看。其实从另外一个角度看触发器就是一个常驻进程型模型一直在等待只不过这个触发器是由云服务商处理罢了。
这里我再啰嗦强调下还是我们上一讲说的FaaS只是做了极端抽象云服务商通过技术手段帮助开发者屏蔽了细节让他们尽量只关注代码本身。
所以在用完即毁型中我们只要将MVC的Control层部署到函数执行就可以了。这也意味着我们要将我们的MVC架构的Control函数一个个拆解出来部署一个HTTP请求对应一个Control函数Control函数实例启动时连接MongoDB一个请求处理完后直接结束。你如果要提升Control函数的冷启动时间Model层同样要考虑BaaS化改造。这里你听着可能有点陌生没关系后面我会通过代码给你演示你到时候再理解也不迟。
现在理解了两种类型我们再来看看FaaS是怎么收费的以及常驻型进程这种模式是不是官方会多收费。云服务商FaaS函数服务的收费标准各不相同但他们都会提供一定的免费额度。我给你归纳下FaaS的收费标准主要有两个维度调用函数次数和函数耗时。
* 调用函数次数函数每次被事件触发计数器加一。例如我们Hello World例子的index.js文件的handler函数它每调用一次计数就加一。这种模式因为不占资源所以资源利用率高、收费低。
* 函数耗时说的是函数执行的运行时长它的计算单位是CU-S也就是CPU运行了多少秒。
例如我们上面“待办任务”改造的常驻进程型和用完即毁型,多数情况下其实他们两个的函数耗时是一样的。这里可能有些绕,需要给你解释一下。
常驻进程型改造后主要占用的是内存而FaaS收费的是CPU计算时间也就是说常驻进程的模式并不会持续收费。但常驻型应用的冷启动时间会增加所以我们要尽量避免冷启动避免冷启动通常又需要做一些额外的工作比如定时触发一下实例或者购买预留实例这地方就会增加额外的费用了。这样听起来是不是觉得常驻进程型改造MVC应用用起来很别扭是的我们前面也说了常驻进程模式就是为了传统MVC架构部署上FaaS专门设计的算是一种权宜之计吧。
用完即毁型改造后同样冷启动时间会增加但是冷启动时间是云服务商负责的。我们Control函数的执行时间和MVC部署在FaaS中Control的执行时间是一样的。每个请求都增加了冷启动时间响应时间会更长一些但我们不用考虑额外的成本。那学到这儿相信你也可以感觉到了用完即毁型也不太适合传统MVC架构的改造也是一种权宜之计但这是FaaS最纯正的用法肯定还是有它的用武之地的。
接下来,我们就继续把焦点放到用完即毁型上,来具体看看它可以用在哪些更加自然的场景里。
## 数据编排
我们做开发的多多少少都知道目前最成功最广泛的设计模式就是MVC模式。但随着前端MVVM框架越来越火前端View层逐渐前置发展成SPA单页应用后端Control和Model层逐渐下沉发展成面向服务编程的后端应用。
这种情况下前后端更加彻底地解耦了前端开发可以依赖Mock数据接口完全脱离后端限制而后端的同学则可以面向数据接口开发但这也产生了高网络I/O的数据网关层。
Node.js的异步非阻塞和JavaScript天然亲近前端工程师的特性自然地接过数据网关层。因此也诞生了Node.js的BFF层(Backend For Frontend),将后端数据和后端接口编排,适配成前端需要的数据结构,提供给前端使用。
我们的程序员好朋友小程也跟进了这个潮流将“待办任务”Web服务重构成了第二个版本。他将原先的应用拆解成了2个项目前端项目采用React+AntDesignPro+Umi.js\[4\] 的单页应用后端项目还是采用Express。我们本专栏的示例也采用这个技术架构一步一步教你在云上部署SPA+FaaS混合框架演进。
![](https://static001.geekbang.org/resource/image/dd/09/dd608f746a18d6172b7057f083ad2c09.png "BFF示意图")
如上图所示BFF层充当了中间胶水层的角色粘合前后端。未经加工的数据我们称为元数据Raw Data对于普通用户来说元数据几乎不可读。所以我们需要将有用的数据组合起来并且加工数据让数据具备价值。对于数据的组合和加工我们称之为**数据编排**。
BFF层通常是由善于处理高网络I/O的Node.js应用负责。传统的服务端运维Node.js应用还是比较重的需要我们购买虚拟机或者使用应用托管PaaS平台。
因为BFF层只是做无状态的数据编排所以我们完全可以用FaaS用完即毁型模型替换掉BFF层的Node.js应用也就是最近圈子里老说的那个新名词SFFServerless For Frontend
到这儿我们已经理解了BFF到SFF的演进过程现在我们再串下新的请求链路逻辑。前端的一个数据请求过来函数触发器触发我们的函数服务我们的函数启动后调用后端提供的元数据接口并将返回的元数据加工成前端需要的数据格式我们的FaaS函数完全就可以休息了。具体如下图所示。
![](https://static001.geekbang.org/resource/image/43/4b/43d5ae274d0169bbc0cc4aece791054b.png "SFF示意图")
另外除了我们自己的后端应用数据接口互联网上还有大量的数据供我们使用。比如疫情期间你要爬取下各个地区的疫情数据、天气数据这些工作也都可以放到FaaS上轻松搞定并且基本还能免费因为目前各大云服务商都提供了免费的额度这个我刚给你讲过了。
编排后端接口,编排互联网上的数据,这俩场景我想你也很容易想到。不过,我觉得,编排云服务商的各种服务才能让你真正体会到那种触电的感觉。我第一次体验之后,就对我同事说:“变天了,真的变天了,喊了这么多年的云计算时代真的来了。”
## 服务编排
**服务编排和数据编排很像,主要区别是对云服务商提供的各种服务进行组合和加工。**在FaaS出现之前就有服务编排的概念但服务编排受限于服务支持的SDK语言版本常见的情况是我们用yaml文件或命令行来编排服务。我们要使用这些服务或API都要通过自己熟悉的编程语言去找对应的SDK在自己的代码中加载SDK使用秘钥调用SDK方法进行编排。就和数据编排一样服务端运维部署成本非常高而且如果没有SDK则需要自己根据平台提供的接口或协议实现SDK。
现在有了FaaSFaaS拓展了我们可以使用SDK边界这是什么意思呢比如小程的“待办任务”Web服务需要发送验证码邮件我们可以用一个用完即毁型FaaS函数调用云服务商的SDK发送邮件再用一个常驻进程型FaaS函数生成随机字符串验证码生成后记录这个验证码并且调用发送邮件的FaaS将验证码发给用户邮箱用户验证时我们再调用常驻进程型FaaS的方法校验验证码是否正确。
我还是用阿里云来举例我们查阅阿里云的邮件服务文档发现它只支持Java、PHP和Python的SDK。我们一直都是在讲Node.js这里没有Node.js的SDK怎么办如果我们根据阿里云邮箱服务的文档自己开发Node.js的SDK那肯定是饶了弯路费了没用的力气。
因为我们发送邮件的用完即毁型FaaS函数功能很单一所以我们完全可以参考邮件服务的PHP文档就用PHP的SDK创建一个FaaS服务来发送邮件的。你会发现使用PHP邮件服务的成本居然如此之低。
你会看到在这个例子中我用了我并不太熟悉PHP语言编排了邮件发送服务。不知道你意识到没有这个也是FaaS一个亮点语言无关性。它意味着你的团队不再局限于单一的开发语言了你们可以利用Java、PHP、Python、Node.js各自的语言优势混合开发出复杂的应用。
FaaS服务编排被云服务商特别关注正是因为它具备的这种开放性。使用FaaS可以创造出各种各样复杂的服务编排场景而且还与语言无关这大大增加了云服务商各种服务的使用场景。当然这对开发者也提出了要求它要求开发者去更多地了解云服务商提供的各种服务。
甚至我还知道西雅图就有创业团队利用FaaS服务编排能力做了一套开源框架Pulumi\[5\],并且还拿到了融资。感兴趣的话,你可以去他们的官网看看。
## 总结
好,到这里,我们这节课的内容就讲完了。我再来总结一下这节课的关键点。
1. FaaS的进程模型有两种常驻进程型和用完即毁型。常驻进程型是为了适应传统MVC架构设计的它看起来并不自然如果你从现在开始玩FaaS的话我当然首选推荐用完即毁型它可以最大限度发挥FaaS的优势。
2. 追溯历史我给你梳理了前后端分离发展出的BFF然后BFF又可以被SFF替代。不管是内部的接口编排还是外部一些数据的编排FaaS都可以发挥出极大优势你看看我视频演示的例子就懂了。
3. 从数据编排再进一步我们可以利用FaaS和云服务商云服务的能力做到服务编排编排出更加强大的组合服务场景提升我们的研发效能。并且通过我这么长时间的体验我还想感叹说依赖云服务商的各种能力再通过FaaS编排开发一个项目时往往可以做到事半功倍。
## 作业
今天的作业和上一讲类似我视频中给你做了个简单的Demo你可以随便找个云平台去run一下试试百闻不如一见体验完之后你可以在留言区谈谈你的感想。另外如果今天这节课让你有所收获也欢迎你把它分享给更多的朋友。
我Demo中的代码地址[https://github.com/pusongyang/sls-send-email](https://github.com/pusongyang/sls-send-email)
## 参考资料
\[1\] Express是Node.js著名的Web服务框架<[https://expressjs.com/](https://expressjs.com/)\>。
\[2\] React 是Facebook开源的MVVM框架<[https://zh-hans.reactjs.org/](https://zh-hans.reactjs.org/)\>。
\[3\] AntDesignPro是蚂蚁开源的React组件库<[https://pro.ant.design/](https://pro.ant.design/)\>。
\[4\] Umi.js是蚂蚁开源的React企业级解决方案脚手架<[https://umijs.org/](https://umijs.org/)\>。
\[5\] Pulumi <[https://pulumi.io/](https://pulumi.io/)\>