01 生命周期:函数计算的基本流程是如何执行的? 你好,我是静远。

看过上一节思维储备的内容之后,相信你对Serverless的认知已经越来越清晰了。它是一种服务设计的理念,只需关注业务逻辑的开发,无需关注环境运维和机器的管理,同时具备弹性、按需付费等特点。

FaaS(函数即服务)作为我推荐给你的第一个步入Serverless世界的技术,今天,我想跟你介绍一下它的基本流程,让你从整体上对FaaS有一个初步的了解,心中能够勾勒出函数计算开发、调试、部署和运行的轮廓。

这样,在你后续碰到某一个困惑,例如“函数上传到哪里去了?”“函数运行为什么超时?”等流程问题时,就能快速知道自己需要深入了解哪一块的知识点。

这节课,我就以“Hello Serverless”为例,选取百度智能云函数计算CFC作为操作平台,分别从用户使用与平台服务两个视角,梳理一遍 FaaS 执行的流程和原理,这其中包括函数创建、存储、执行等一个生命周期的始终,同时,我也会带你体验一次开发、运行函数计算的流程。

初次体验推荐用云厂商平台

一般初次接触Serverless,我推荐先去公有云厂商的云平台上跟着他们的教程来体验,从使用角度上能够有一些认识,再看开源的框架或者找一些资料深入研究。

为什么这么推荐呢?

首先,云厂商的函数计算平台为用户提供了多种运行环境(Python、Java、PHP、Node.js、Golang 等),可以满足不同技术栈的开发需求。你可以选择任何你擅长的语言来体验,避免了语言的切换成本。如果选择的是解释性语言,可以直接在云平台上开发、调试、部署,非常方便。这样,通过低成本的学习,你可以快速地理解Serverless的产品形态。

其次,如果你自己要部署一套开源的框架,是要有机器资源的,而云厂商一般都会提供免费的额度。拿函数计算来说,像百度智能云、阿里云、华为云,每个月都有大概100万额度的调用次数,以及40万GB-秒的内存资源使用,基本上足够我们体验了。腾讯云做了一些调整,新人前3个月有一定的免费额度。当然,你在使用的时候,最好提前看一下云厂商的使用说明,避免多花冤枉钱。

最后,你也可以比较方便地通过云厂商提供的各类API/SDK、触发器集成、开发工具来了解整个Serverless的生态和解决方案。这也正是我们常说的“遇到新事物,先看看别人是怎么干的”,也是学习的一条捷径。

了解了大致的体验方式和流程之后,下面我们就要从用户角度来看函数计算是如何使用的了。

从用户视角看函数计算的生命周期

函数整个生命周期会经过“开发设置”“打包上传”“事件绑定与触发”“弹性执行”“实例销毁”五个过程。下面这张图片,就展示了用户视角下的函数计算的过程。我们一起来体验一下。

图片

第一步,需要你编写相应的函数代码。我们以 Python3.6 为例,撰写一个“Hello Serverless”的Demo,函数运行时选择 Python3.6,执行内存选择 128MB,超时时间选择 3s,并发度设置为1。下图展示的就是我们创建好的函数信息概览。

图片

然后,我们点击编辑函数,进入在线编辑模式,编写Demo案例代码。你也可以下载到本地进行代码开发。 /# -/- coding: utf-8 -/-  def handler(event, context):    return “Hello Serverless”

编写完成之后,你还需要指定函数执行的入口,例如:填写 “index.handler”,就是指调用主程序文件 index.py 中定义的 handler 方法。当有事件触发函数执行时,就会先从handler方法开始执行。

第二步,需要将代码上传到函数计算平台上。你可以直接在界面提交并保存你的代码,也可以将代码打包成 zip 文件。上传的方式包括函数计算API/SDK、前端界面上传,还可以通过命令行工具 CLI 上传。

第三步,执行你刚刚上传的函数。通常可以利用 API/SDK 调用,或者在前端界面手动点击来执行函数,另外,你也可以通过各种触发器来触发函数的执行。

你可能会对触发器感到陌生,这里我简单说一下。

FaaS可以通过事件触发器打通众多的上下游服务,当触发源服务发出请求时,函数就会响应运行,作出处理和反馈。以 HTTP 触发器为例,当用户访问 HTTP 触发器的 URL 时,会向指定的云函数发出HTTP处理请求,随后平台会启动一个函数实例来对请求进行处理。

我们继续操作函数helloServerless,从平台中选择创建一个HTTP触发器,将URL路径设定为“/hello/serverless”,选择“GET”方式作为HTTP的请求方法。

图片

创建完触发器后,函数计算平台会帮助你生成一个可访问的URL地址,你就可以通过这个URL地址进行触发函数的执行了。如果你是要上生产环境,最好能增加身份验证,以确保服务的安全可靠。

图片

第四步,当函数执行完毕,函数计算平台会返回函数的执行结果。通常可以通过日志或者请求返回的信息来查看函数的执行结果。 curl https://$HTTP_TRIGGER_URL/hello/serverless /#输出结果 Hello Serverless

经过上面的步骤,你已经完成了一个“Hello Serverless”的小Demo。对于用户而言,只需要关注开发的代码本身,而不需要去关注环境的部署和维护。看到这里,你可能会有疑问,执行结果和传统代码执行没有区别,为什么要选择 FaaS 呢?

其实,FaaS最大的特点在于弹性扩缩容和缩容至0的能力,当你没有调用函数,FaaS是没有任何实例在计费的。也就是说,当你创建上传函数后,并没有产生计费,只有当你产生调用量才会开始计费。当流量达到一个阈值的时候,系统自动进行扩容。当流量变小时,系统会自动进行缩容。

另外,一般云厂商的 FaaS 都会有一定的免费额度,如果你的应用是基于事件触发或者流量的波峰波谷比较明显,那么 FaaS 绝对是你的明智之选。

从平台视角看函数计算的执行过程

前面我们已经从开发者的角度了解了函数计算的生命周期,但我相信你肯定不会只满足于表面的使用。 那么,函数计算内部具体是如何实现的呢?

简单来说,事件的请求,首先会到达路由服务,路由服务在缓存Cache中查看是否有准备就绪的实例。如果有就绪的实例,也就是热启动,直接使用该实例执行函数即可。如果没有就绪的实例,就会进入冷启动过程。函数计算引擎会启动容器的初始化流程,做一些准备工作:下载函数的代码包或者镜像、准备网络环境、加载运行时Runtime,进而执行函数,并将实例信息放入到Cache中,下次请求再过来的时候,就进入热启动流程。

执行完毕之后,实例会保留一定时间(通常是1-2分钟),随后被回收。

以上是正常的执行流量,当流量突增到一定阈值的时候,函数计算服务会快速扩容实例来满足提升的并发量。而空闲的实例太多的时候,也会缩容实例。

到这里你肯定会有疑问,很多新名词好像很陌生,冷启动、热启动、运行时等等。下面我将带你从开发态和运行态两个视角来梳理函数计算的生命周期,便于你理解它们的含义。

函数计算的开发态

当我们上传代码到FaaS平台后,后端服务会将代码包上传到对象存储中,并将函数相关信息,包括函数代码链接、Runtime信息、运行内存、超时时间等信息存储起来。

当我们再次修改函数相关信息,或者在线编写函数代码的时候,FaaS平台会将存储好的代码和附属信息读取出来,展示在界面上,供你修改。

这里需要注意的是,目前各大云厂商还只支持解释性语言的在线编译和调试,对于编译型语言,你还得下载到本地进行开发。所幸,目前有的云厂商(如阿里云)已经发布了端云联调能力的工具,从一定程度上来说,也便于你快速本地开发、调试和发布。后面的章节中,我也会跟你详细介绍这个技术的实现。

图片

函数计算的运行态

那在你上传好代码之后,FaaS平台是如何执行函数代码的呢?我们还是以“Hello Serverless”为例来说明。

在开头,我们已经创建了一个函数、编写了相应的代码,并保存到了云厂商的平台上。

我们再次回到 HTTP 触发器的方式执行来讲解。当事件请求访问触发器的URL时,请求会被路由到相关函数实例,依据是否是第一次请求,会分为冷启动和热启动两种情况;根据流量的大小,会进行动态的扩缩容

我将这个过程抽象成下面的函数计算架构示意图,通过这个示意图,我们来依次看一下“Hello Serverless”云函数是怎么执行的。

图片

流量转发:热启动和冷启动

首先,当HTTP事件请求到来之时,流量转发服务负责接收转发请求,也就是图中的Route服务。当Route接收到请求后,首先就要在自己的缓存Cache里查看是否已经存在当前Hello Serverless函数和实例的对应信息。

如果有,那么根据存储的信息,直接在实例池(instance pool)中获取执行实例,这时请求就以热启动方式被执行。具体什么是热启动呢?就是当你的函数执行完成后,容器实例会保留1-2min的时间,如果此时触发执行函数,那么无需新增实例和执行函数 runtime 的挂载,直接复用。因此它的响应速度要快得多。

如果找不到相关的信息呢?那么就会通过一个类似激活器(如Activator)的组件,来创建并申请一个实例,执行本次请求,接着,将实例的相关信息存储到Route的缓存中,这就是冷启动的执行过程

在冷启动过程中会有哪些操作呢?一般来说,包括实例调度和容器创建、下载并解压代码、准备函数执行环境、挂载用户代码、VPC网络准备、初始化运行时和用户代码,这一系列过程结束后,函数才开始执行。所以冷启动的消耗时间受到很多因素的影响,主要包括:

  • 不同语言的冷启动时间不同:一般 GoLang、Python的速度较快,而Java的速度相对较慢一些。
  • 代码包大小:下载解压代码的过程在冷启动过程中比较耗时,一般体积越大,耗时越多。
  • 容器创建速度和VPC网络的准备:这个过程的耗时往往取决于云服务商,不同平台的速度也是不一样的。

当然,各云厂商对于冷启动也在不断地优化,推出了预留实例、通过缓存加快代码下载速度、VPC代理和IP隧道技术等方式来解决冷启动问题。你也可以通过一些方式来自行解决,例如:

  • 精简代码包,减少掉一些不必要的配置和依赖。
  • 预热请求的方式来确保代码实例常驻在容器池中,比如用定时器触发代码实例进行一个非常快的空响应。
  • 选择冷启动时间较少语言,尽量避免使用 Java 等启动较慢的语言运行时。
  • 尽量选择较大的内存:函数的内存越大,冷启动速度越快。- 后面的冷启动章节,我会详细地跟你聊一聊这一块的技术要点和一线实战经验。

动态扩缩容

那么什么时候需要扩容和缩容呢?当我们首次通过HTTP触发器请求的时候,此时由于函数实例池里面没有已经加载好的Pod,需要进行一个从0到1的容器扩容过程。

此时,还需要将Hello Serverless的包从对象存储中加载到容器中运行起来。当执行结果返回后,一般FaaS平台会将函数实例保留一段时间再进行销毁。如果被保留的时间段内有请求再次进来,那么就可以直接复用,不需要扩容。但如果此时并发超过我们前面设置的1次请求,函数计算引擎监听到相关指标后,就会自动扩容。

当然,我这里举的情况比较极端了,通常的函数计算引擎会根据设定的监控阈值,提前就要扩容了。

扩缩容算法包含Node级别和Pod级别的扩缩容。Node和Pod一般会监控自定义的指标,如果指标有变化,会进行相应的扩缩容操作。

例如 ,Kubernetes 中的 HPA 扩缩容算法,通过安装一个 metrics-server 的监控组件,提供 HPA 和基础资源监控的能力。对CPU和Memory等指标进行监控,保证其维持在可控的范围内。这里先卖个小关子,函数计算的扩所容是否可以通过Kubernetes的HPA来直接进行,需不需要改动?可以先思考一下,我们在扩缩容一节中会详细跟你来探讨。

而Node级别的扩缩容,一般会根据Node的整体使用率,来判断Node数量是否需要扩容。一旦需要扩缩容,就会向Scheduler发送扩缩容请求,Scheduler调用相关接口执行扩容操作。

函数实例释放

最后,我还是要提一句,运行也是有始有终的。当函数执行完毕,并且在 1~2min 内没有再次执行时,FaaS 平台就会回收该实例。

各云厂商回收时间各不相同,这里注意一下就行,以便我们将来基于云平台开发的时候,可以提前优化函数,确保请求在热请求的情况下执行。

Runtime

通过之前的步骤,你已经可以获得一个函数实例来执行你编写的函数Hello Serverless了。下面我们来重点看一下函数执行的关键底座:Runtime。Runtime 是为函数提供运行框架,并真正执行函数的进程。

云厂商一般将不同语言的执行环境打包为基础镜像。容器镜像包含多层镜像,第一层基础镜像为 ubuntu、alpine之类的文件系统;第二层镜像为代码的依赖库,如Python 代码需要使用 pip 库 , Node.js 代码需要使用 npm 库。也有的函数计算引擎,直接支持Docker镜像来运行。

我们以上述“Hello Serverless”的运行语言Python3为例来说明runtime的执行过程。Python3-runtime通常会开放一个handler的接口给开发者实现具体的业务逻辑。当一次请求到来之时,Python的运行时会通过动态加载的方式对你刚才定义的文件方法进行调用。

这里需要注意的是,对于编译型语言,需要引入FaaS平台提供的代码库,基于一套现成的框架来开发业务逻辑代码,不过思路一样,只是运行的方式不一样罢了。

具体的的实现过程,我会在运行时一节中跟你细聊。

小结

最后我们来小结一下。今天,我通过一个“Hello Serverless”的例子,带你了解了函数计算在不同视角下的运作过程。

从用户视角,通过四个步骤的实操,我们可以了解到作为一个业务开发人员,需要重点关心的部分是开发设置、打包上传、事件绑定与触发以及函数上线后的按需付费。对于函数如何执行、如何扩缩容、如何销毁等一系列函数计算引擎去做的事情,可以让平台运维人员更多的关注。

从平台视角,基于开发态,我们可以清晰地了解到函数计算控制面做的事情在于提供给业务人员一个好的操作平台;基于运行态,我们从整体上对运行期各环节的协作有了一定的了解。

一方面,事件初次请求时,函数计算平台有一个从0到1的扩容过程,随着流量的增加,平台会继续扩容以确保请求的正常执行。随着请求的减少,平台会通过释放实例来缩容。

另一方面,真正支持函数执行的运行时,也有着不同的实现方法,主要来源于语言本身特性的不一样。

图片

通过今天的介绍,相信你对函数计算有了一个整体上的了解,已经摸到了这个领域的大门了。

接下来的课程,我也会详细地把本节提到的这些技术要点和你一一道来。

思考题

好了,这节课到这里也就结束了,最后我给你留了一个问题。

FaaS提高了开发人员的生产效率,使得产品能够快速地推向市场进行试错,你是否接触过FaaS,哪些业务已经在使用了,有遇到过什么问题么?

欢迎在留言区写下你的思考和答案,我们一起交流讨论。感谢你的阅读,也欢迎你把这篇文章分享给更多的朋友一起交流进步。

参考资料

https://learn.lianglianglee.com/%e4%b8%93%e6%a0%8f/Serverless%e8%bf%9b%e9%98%b6%e5%ae%9e%e6%88%98%e8%af%be/01%20%e7%94%9f%e5%91%bd%e5%91%a8%e6%9c%9f%ef%bc%9a%e5%87%bd%e6%95%b0%e8%ae%a1%e7%ae%97%e7%9a%84%e5%9f%ba%e6%9c%ac%e6%b5%81%e7%a8%8b%e6%98%af%e5%a6%82%e4%bd%95%e6%89%a7%e8%a1%8c%e7%9a%84%ef%bc%9f.md