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.

14 KiB

02 | 原理通过一个案例理解FaaS的运行逻辑

你好我是秦粤。上一讲我们介绍了什么是Serverless从概念的角度我们已经对Serverless有了一个深入的了解那从应用角度来看Serverless对于开发者究竟有什么魔力呢这一讲我准备通过快速部署纯FaaS的Serverless应用给你讲一讲FaaS应用背后的运行原理。

为了让你更好地体验Serverless带来的变革这节课我们以Serverless版本的"Hello World"实操例子进行展示。鉴于我的熟悉程度,我选择了阿里云,当然,你也可以选择你熟悉的云服务商(我在专栏的最后一课还会讲到如何解除云服务商的限制,混合使用多云运营商服务等等)。

另外,需要注意的是,如果你是跟着我一步步实操练习的,那么开通云服务可能会产生少量费用,遇到充值提示你要自行考虑一下。当然,如果你不着急体验,我觉得看我的视频演示也已经足够了。

我们从上面的演示也看到了会用Serverless这个目标我觉得不难实现但这不是我们这节课的终极目的。今天我就想带着你打开这个FaaS "Hello World"应用的引擎盖来看看它内部到底是如何运行的。为什么要急着给你讲原理呢因为如果你不理解原理的话后面在应用Serverless化的时候就无从下手了。

FaaS是怎么运行的

现在大家都觉得Serverless是个新东西是个新风口刚才在演示的视频里你也能看到它确实很方便。但你也不用把它想得多复杂运行应用的那套逻辑还没有变化Serverless只是用技术手段帮我们屏蔽了复杂性这点它和其他的云技术没有任何差别。

你可以想想在Serverless出现之前我们要部署这样一个"Hello World"应用得何等繁琐。首先为了运行我们的应用我们要在服务端构建代码的运行环境我们要购买虚拟机服务初始化虚拟机运行环境安装我们需要的应用运行环境尽量和本地开发环境保持一致紧接着为了让用户能够访问我们刚刚启动的应用我们需要购买域名用虚拟机IP注册域名配置Nginx启动Nginx最后我们还需要上传应用代码启动应用。

你可以闭上眼睛想想是不是我说的这样当然为了方便你理解我还画了张图。前面5步都准备好了用户在第6步才能成功访问到我们的应用。

与上面传统流程形成鲜明对比的是我们刚刚的Serverless部署只需要简单的3步而且目前这样操作下来没有产生任何费用。上一课我们讲过**Serverless是对服务端运维体系的极端抽象。**注意这句话里面有个关键词“抽象”我没有用“革新”“颠覆”之类的词语也就是说用户HTTP数据请求的全链路并没有质的改变Serverless只是将全链路的模型简化了。

具体来说之前我们需要在服务端构建代码的运行环境而FaaS应用将这一步抽象为函数服务之前我们需要负载均衡和反向代理而FaaS应用将这一步抽象为HTTP函数触发器之前我们需要上传代码和启动应用而FaaS应用将这一步抽象为函数代码。

触发器、函数服务……咦,是不是发现开始出现了一些陌生名词?不用着急,还是对照着上面这张图,我给你再串下"Hello World"这个纯FaaS应用的数据请求链条。理解了这些链条你自然就理解了这几个新名词的背景了。

咱们先从图的右边开始看图上我标注了次序。当用户第一次访问HTTP函数触发器时函数触发器就会Hold住用户的HTTP请求并产生一个HTTP Request事件通知函数服务。

紧接着函数服务就会检查有没有闲置的函数实例如果没有函数实例就去函数代码仓库中拉取你的代码初始化并启动一个函数实例执行这个函数传入这个HTTP Request对象作为函数的参数执行函数。

再进一步函数执行的结果HTTP Response返回函数触发器函数触发器再将结果返回给等待的用户客户端。

如果你还记得的话我们刚刚的视频演示你可以看到我们的纯FaaS "Hello World"应用例子中默认创建了3个服务。

第一个"GreetingServiceGreetingFunctionhttpTrigger"函数触发器,函数触发器是所有请求的统一入口,当请求发生时,它会触发事件通知函数服务,并且等待函数服务执行返回后,将结果返回给等待的请求。

第二个"GreetingService"函数服务,当函数触发器通知的“事件”到来,它会查看当前有没有闲置的函数实例,如果有则调用函数实例处理;如果没有,则会创建函数实例,等实例创建完毕后,再调用函数实例处理事件。

第三个"GreetingServiceGreetingFunction"函数代码,“函数服务”在第一次实例化函数时,就会从这个代码仓库中拉取代码,并构建函数实例。

理解了FaaS应用调用链路我想你可能会问“真够复杂折腾来折腾去怎么感觉它的这套简化逻辑很像以前新浪的SAE或者Heroku那样的NoOps应用托管PaaS平台”不知道你是不是有这样的问题反正我当时第一次接触Serverless时就有类似的疑问。

其实FaaS与应用托管PaaS平台对比**最大的区别在于资源利用率,**这也是FaaS最大的创新点。FaaS的应用实例可以缩容到0而应用托管PaaS平台则至少要维持1台服务器或容器。

你注意看的话,在上面"Hello World"例子中函数在第一次调用之前实际的服务器占用为0。因为直到用户第一次HTTP数据请求过来时函数服务才被HTTP事件触发启动函数实例。也就是说没有用户请求时函数服务没有任何的函数实例也就不占用任何的服务器资源。而应用托管PaaS平台创建应用实例的过程通常需要几十秒为了保证你的服务可用性必须一直维持着至少一台服务器运行你的应用实例。

打个比方的话FaaS就有点像我们的声控灯有人的时候它可以很快亮起来没人的时候又可以关着。对比传统的需要人手动开关的灯声控灯最大的优势肯定就是省电了。但你想想能省电的前提是有人的时候声控灯能够找到比较好的方式快速亮起来。

FaaS也是这样它优势背后的关键点是可以极速启动。那它是怎么做的呢要理解极速启动背后的逻辑这里我就要引入冷启动的概念了。

FaaS为什么可以极速启动

冷启动本来是PC上的概念它是指关闭电源后PC再启动仍然需要重新加载BIOS表也就是从硬件驱动开始启动因此启动速度很慢。

现在的云服务商,线上物理服务器断电重启几乎是不太可能的。**FaaS中的冷启动是指从调用函数开始到函数实例准备完成的整个过程。**冷启动我们关注的是启动时间启动时间越短我们对资源的利用率就越高。现在的云服务商基于不同的语言特性冷启动平均耗时基本在100700毫秒之间。得益于Google的JavaScript引擎Just In Time特性Node.js在冷启动方面速度是最快的。

100700毫秒的冷启动时间我不知道你听到这个数据的时候是不是震惊了一下。

下面这张图是FaaS应用冷启动的过程。其中蓝色部分是云服务商负责的红色部分由你负责而函数代码初始化一人一半。也就是说蓝色部分在冷启动时候的耗时你不用关心而红色部分就是你的函数耗时。至于资源调度是要做什么你可以先忽略我后面会提到。

例如从刚才演示视频的云服务控制台我们可以看到,"Hello World"的单次函数耗时是0.0125 CU-S也就是说耗时12.5毫秒实际我们抓数据包来看除去建立连接的时间我们整个HTTPS请求到完全返回结果需要100毫秒。我们负责的红色部分耗时是12.5毫秒也就是说云服务商负责的蓝色部分耗时是87.5毫秒。

注意FaaS服务从0开始启动并执行完一个函数只需要100毫秒。这也是为什么FaaS敢缩容到0的主要原因。通常我们打开一个网页有个关键指标响应时间在1秒以内都算优秀。这么一对比100毫秒的启动时间对于网页的秒开率影响真的极小。

而且可以肯定的是,云服务商还会不停地优化自己负责的部分,毕竟启动速度越快对资源的利用率就越高,例如冷启动过程中耗时比较长的是下载函数代码。所以一旦你更新代码,云服务商就会偷偷开始调度资源,下载你的代码构建函数实例的镜像。请求第一次访问时,云服务商就可以利用构建好的缓存镜像,直接跳过冷启动的下载函数代码步骤,从镜像启动容器,这个也叫预热冷启动。所以如果我们有些业务场景对响应时间比较敏感,我们就可以通过预热冷启动或预留实例策略[1],加速或绕过冷启动时间。

了解了冷启动的概念我们再看看为什么FaaS可以极速启动而应用托管平台PaaS不行

首先应用托管平台PaaS为了适应用户的多样性必须支持多语言兼容还要提供传统后台服务例如MySQL、Redis。

这也意味着应用托管平台PaaS在初始化环境时有大量依赖和多语言版本需要兼容而且兼容多种用户的应用代码往往也会增加应用构建过程的时间。所以通常应用托管平台PaaS无法抽象出轻量的可复用的层级只能选择服务器或容器方案从操作系统层开始构建应用实例。

FaaS设计之初就牺牲了用户的可控性和应用场景来简化代码模型并且通过分层结构进一步提升资源的利用率。学到这里我们得来看看隐藏在FaaS冷启动中最重要的革新技术分层结构。

FaaS是怎么分层的

你的FaaS实例执行时就如上图所示至少是3层结构容器、运行时Runtime、具体函数代码。

容器你可以理解为操作系统OS。代码要运行总需要和硬件打交道容器就是模拟出内核和硬件信息让你的代码和Runtime可以在里面运行。容器的信息包括内存大小、OS版本、CPU信息、环境变量等等。目前的FaaS实现方案中容器方案可能是Docker容器、VM虚拟机甚至Sandbox沙盒环境。

运行时Runtime [2]就是你的函数执行时的上下文context。Runtime的信息包括代码运行的语言和版本例如Node.js v10Python3.6可调用对象例如aliyun SDK系统信息例如环境变量等等。

关于FaaS的3层结构你可以这么想象容器层就像是Windows操作系统Runtime就像是Windows里面的播放器暴风影音你的代码就像是放在U盘里的电影。

这样分层有什么好处呢容器层适用性更广云服务商可以预热大量的容器实例将物理服务器的计算资源碎片化。Runtime的实例适用性较低可以少量预热容器和Runtime固定后下载你的代码就可以执行了。通过分层我们可以做到资源统筹优化这样就能让你的代码快速低成本地被执行。

理解了分层我们再回想一下FaaS分层对应冷启动的过程其实你就不难理解云服务商负责的就是容器和Runtime的准备阶段了。而开发者自己负责的则是函数执行阶段。一旦容器&Runtime启动后就会维持一段时间这段时间内的这个函数实例就可以直接处理用户数据请求。当一段时间内没有用户请求事件发生各个云服务商维持实例的时间和策略不同则会销毁这个函数实例。

具体你可以看下下面这张图,以辅助你理解。

总结

这一讲我带你体验了只需要三步就能快速部署纯FaaS的Web应用上线我们也打开了FaaS引擎盖介绍了FaaS的内部运行机制。现在我们就来总结一下这节课的关键点。

  1. 纯FaaS应用调用链路由函数触发器、函数服务和函数代码三部分组成它们分别替代了传统服务端运维的负载均衡&反向代理,服务器&应用运行环境,应用代码部署。
  2. 对比传统应用托管PaaS平台FaaS应用最大的不同就是FaaS应用可以缩容到0在事件到来时极速启动Node.js的函数甚至可以做到100ms启动并执行。
  3. FaaS在设计上牺牲了用户的可控性和应用场景来简化代码模型并且通过分层结构进一步提升资源的利用率这也是为什么FaaS冷启动时间能这么短的主要原因。关于FaaS的3层结构你可以这么想象容器层就像是Windows操作系统Runtime就像是Windows里面的播放器暴风影音你的代码就像是放在U盘里的电影。

作业

最后给你留个作业吧。我知道整个原理你听起来肯定还不是那么好理解实践是检验真理的唯一标准如果你有时间并且方便的话可以试着自己动手Run一个FaaS的Hello World例子然后思考其中的原理。

当然,如果今天这节课让你有所收获,也欢迎你把它分享给更多的朋友。

参考资料

1
2