极客时间之Serverless入门

开篇词 | 说来说去,到底Serverless要解决什么问题?

问题一:说来说去,到底 Serverless 要解决什么问题?

拿自己部署一套博客来说吧,常见的 Node.js MVC 架构,需要购买云服务商的Linux 虚拟机、RDS 关系型数据库,做得好的话还要购买 Redis 缓存、负载均衡、CDN 等等。再专业一点,可能还会考虑容灾和备份,这么算下来一年最小开销都在 1 万元左右。但如果你用 Serverless 的话,这个成本可以直接降到 1000 元以下。

Serverless 是对运维体系的极端抽象,就像 iPhone 当年颠覆诺基亚一样,它给应用开发和部署提供了一个极简模型。这种高度抽象的模型,可以让一个零运维经验的人,几分钟就部署一个 Web 应用上线,并对外提供服务。也就是说,你根本不需要再学习怎么在 Linux 上装 Web 服务器,怎么配置负载均衡等等这些繁琐的偏运维方向的工作。

一句话总结就是它可以帮你省钱、省力气。

问题二:为什么阿里巴巴、腾讯这样的公司都在关注 Serverless?

首先,Serverless 可以有效降低企业中中长尾应用的运营成本。中长尾应用就是那些每天大部分时间都没有流量或者有很少流量的应用。企业在落地微服务架构后,一些边缘的微服务被调用的概率其实很低。而这个时候,我们往往又很难通过人工来控制中长尾应用,因为这里面不少应用还是被强依赖的,不可以直接下线处理。Serverless 之前,这些中长尾应用至少要独占 1 台虚拟机。现在有了 Serverless 的极速冷启动特性,企业就可以节省这部分开销。

其次,Serverless 可以提高研发效能。我们专栏会讲到 Serverless 应用架构的设计,其中,SFF(Serverless For Frontend)可以让前端同学自行负责数据接口的编排,微服务BaaS 化则让我们的后端同学更加关注领域设计。

最后我想说 Serverless 作为一门新兴技术,未来的想象空间很大。我看到有创业公司用FaaS 来做基础设施编排和云服务编排;也有外包公司利用 Serverless 应用架构的快速迭代能力,提升开发效率,降低出错率,还可以给自己沉淀领域的解决方案;还有包括风险投资方也在逐渐开始关注 Serverless 领域,毕竟这也是一个新的风口。

问题三:Serverless 对前端工程师来说会有什么机遇?为什么我们要学习 Serverless?

相对其他工种而言,Serverless 给前端工程师带来的机遇更大,它能让前端工程师也享受到云服务的红利。如果说 Node.js 语言的出现解放了一波前端工程师的生产力,那Node.js+Serverless 又可以进一步激发前端工程师的创造力。

image

01|定义:到底什么是Serverless?

Serverless 能解决什么问题?

Server 这里指服务端,它是 Serverless 解决问题的边界;而 less 我们可以理解为较少关心,它是 Serverless 解决问题的目的。组合在一起就是“较少关心服务端”。

什么是服务端?

我们正常部署的SpringBoot项目就可以看做服务端。

服务端运维发展史,从 full 到 less

Serverfull 就是服务端运维全由我们自己负责,Serverless 则是服务端运维较少由我们自己负责,大多数的运维工作交给自动化工具负责。

史前时代,Serverfull
小程(程序员)不用关心任何部署运维相关的事情。小程每次发布新的应用,都会打电话给小服,让小服部署上线最新的代码。小服要管理好迭代版本的发布,分支合并,将应用上线,遇到问题回滚。如果线上出了故障,还要抓取线上的日志发给小程解决。

这个时代研发和运维隔离,服务端运维都交给小服(运维)一个人,纯人力处理,也就是Serverfull。
农耕时代,DevOps
做一套运维控制台 OpsConsole,将部署上线和日志抓取的工作让小程自己处理。

这个时代就是研发兼运维 DevOps,小程兼任了小服的部分工作。小服将部分服务端运维的工作工具化了,自己可以去做更加专业的事情。
工业时代
小服又基于小程的开发流程,OpsConsole 系统再进一步,帮小程做了一套代码自动化发布的流水线:代码扫描 - 测试 - 灰度验证 - 上线。现在的小程连 OpsConsole 都不用登陆操作,只要将最新的代码合并到 Git 仓库指定的 develop 分支,剩下的就都由流水线自动化处理发布上线了。

这个时代研发不需要运维了,免运维 NoOps。小服的服务端运维工作全部自动化了。小程也变回到最初,只需要关心自己的应用业务就可以了。我们不难看出,在服务端运维的发展历史中,对于小服来说,小程的角色存在感越来越弱,需要小程参与的事情越来越少,都由自动化工具替代了。这就是“Serverless”。
未来
实现了免运维 NoOps,并不意味着小服要失业了,而是小服要转型。转型去做更底层的服务,做基础架构的建设,提供更加智能、更加节省资源、更加周到的服务。小程则可以完全不被运维的事情困扰,放心大胆地依赖 Serverless 服务,专注做好自己的业务,提升用户体验,思考业务价值。

免运维 NoOps 并不是说服务端运维就不存在了,而是通过全知全能的服务,覆盖研发部署需要的所有需求,让研发同学小程对它的感知越来越少。另外,NoOps 是理想状态,因为我们只能无限逼近 NoOps,所以这个单词是 less,不可能是 ServerLeast 或者 ServerZero。

Serverless 为什么难准确定义?

服务端免运维,要解决的就是将小服的工作彻底透明化。研发同学只关心业务逻辑,不用关心部署运维和线上的各种问题。要实现这个终态,就意味着需要对整个互联网服务端的运维工作进行极端抽象。

那越抽象的东西,其实越难定义,因为蕴含的信息量太大了,这就是 Serverless 很难准确定义的根本原因。Serverless 对 Web 服务开发的革命之一,就是极度简化了服务端运维模型,使一个零经验的新手,也能快速搭建一套低成本、高性能的服务端应用。

到底什么是 Serverless?

Serverless 的含义有这样两种

  1. 第一种:狭义 Serverless(最常见)= Serverless computing 架构 = FaaS 架构 =Trigger(事件驱动)+ FaaS(函数即服务)+ BaaS(后端即服务,持久化或第三方服务)= FaaS + BaaS
  2. 第二种:广义 Serverless = 服务端免运维 = 具备 Serverless 特性的云服务

FaaS(Function as a Service) 就是函数即服务,BaaS(Backend as aService) 就是后端即服务。XaaS(X as a Service) 就是 X 即服务,这是云服务商喜欢使用的一种命名方式,比如我们熟悉的 SaaS、PaaS、IaaS 都是这样。

FAAS

先说 FaaS,函数即服务,它还有个名字叫作 Serverless Computing,它可以让我们随时随地创建、使用、销毁一个函数。

通常函数的使用过程:它需要先从代码加载到内存,也就是实例化,然后被其它函数调用时执行。在 FaaS 中也是一样的,函数需要实例化,然后被触发器 Trigger 或者被其他的函数调用。二者最大的区别就是在 Runtime,也就是函数的上下文,函数执行时的语境。

FaaS 的 Runtime 是预先设置好的,Runtime 里面加载的函数和资源都是云服务商提供的,我们可以使用却无法控制。你可以理解为 FaaS 的 Runtime 是临时的,函数调用完后,这个临时 Runtime 和函数一起销毁。

FaaS 的函数调用完后,云服务商会销毁实例,回收资源,所以 FaaS 推荐无状态的函数。简单解释一下,就是说一个函数只要参数固定,返回的结果也必须是固定的。

MVC 架构里面,一个 HTTP 的数据请求,就会对应一个 Control 函数,我们完全可以用 FaaS 函数来代替 Control 函数。在HTTP 的数据请求量大的时候,FaaS 函数会自动扩容多实例同时运行;在 HTTP 的数据请求量小时,又会自动缩容;当没有 HTTP 数据请求时,还会缩容到 0 实例,节省开支。

Runtime 不可控,FaaS 函数无状态,函数的实例又不停地扩容缩容,那我需要持久化存储一些数据怎么办,MVC 里面的 Model 层怎么解决?

BAAS

BaaS 其实是一个集合,是指具备高可用性和弹性,而且免运维的后端服务。说简单点,就是专门支撑 FaaS 的服务。FaaS 就像高铁的车头,如果我们的后端服务还是老旧的绿皮火车车厢,那肯定是要散架的。而 BaaS 就是专门为 FaaS 准备的高铁车厢。

MVC 架构中的 Model 层,就需要我们用 BaaS 来解决。Model 层我们以 MySQL 为例,后端服务最好是将 FaaS 操作的数据库的命令,封装成 HTTP 的 OpenAPI,提供给 FaaS调用,自己控制这个 API 的请求频率以及限流降级。这个后端服务本身则可以通过连接池、MySQL 集群等方式去优化。

基于 Serverless 架构,我们完全可以把传统的 MVC 架构转换为 BaaS+View+FaaS 的组合,重构或实现。

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

极客时间演示视频

以阿里云为例,函数计算 FC,创建一个SpringBoot类型的应用,关联一个代码仓库,这里我使用gitee(码云),后续push了代码就会自动部署。

这里可以查看项目访问路径

FaaS 是怎么运行的?

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

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

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

当用户第一次访问 HTTP 函数触发器时,函数触发器就会 Hold 住用户的 HTTP 请求,并产生一个 HTTP Request 事件通知函数服务。

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

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

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

FaaS 为什么可以极速启动?

FaaS 中的冷启动是指从调用函数开始到函数实例准备完成的整个过程。

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

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

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

FaaS 是怎么分层的?

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

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

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

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

03 | 原理:FaaS的两种进程模型及应用场景

FaaS 进程模型

两种运行模式

  • 用完即毁型:函数实例准备好后,执行完函数就直接结束。这是 FaaS 最纯正的用法。
  • 常驻进程型:函数实例准备好后,执行完函数不结束,而是返回继续等待下一次函数被调用。这里需要注意,即使 FaaS 是常驻进程型,如果一段时间没有事件触发,函数实例还是会被云服务商销毁。

从可控性和改造成本角度来看 Web 服务,服务端部署方案最适合的还是托管平台 PaaS 或者自己搭服务跑在 IaaS 上。正如我上一讲所说,使用 FaaS 就必须在 FaaS 的条件限制内使用,最佳的做法应该是一开始就选用 FaaS 开发。

数据编排

BFF(Backend For Frontend) 层充当了中间胶水层的角色,粘合前后端。未经加工的数据,我们称为元数据 Raw Data,对于普通用户来说元数据几乎不可读。所以我们需要将有用的数据组合起来,并且加工数据,让数据具备价值。对于数据的组合和加工,我们称之为数据编排。

BFF(Backend For Frontend) : 将后端数据和后端接口编排,适配成前端需要的数据结构,提供给前端使用。

因为 BFF 层只是做无状态的数据编排,所以我们完全可以用 FaaS 用完即毁型模型替换掉BFF 层的 Node.js 应用,也就是最近圈子里老说的那个新名词 SFF(Serverless ForFrontend)。

另外,除了我们自己的后端应用数据接口,互联网上还有大量的数据供我们使用,比如疫情期间,你要爬取下各个地区的疫情数据、天气数据,这些工作,也都可以放到 FaaS 上轻松搞定。

服务编排

服务编排和数据编排很像,主要区别是对云服务商提供的各种服务进行组合和加工。

以发送验证码邮件为例,我们可以用一个用完即毁型 FaaS 函数,调用云服务商的 SDK 发送邮件,再用一个常驻进程型 FaaS 函数生成随机字符串验证码,生成后记录这个验证码,并且调用发送邮件的 FaaS 将验证码发给用户邮箱。用户验证时,我们再调用常驻进程型 FaaS 的方法校验验证码是否正确。

04 | 原理:FaaS应用如何才能快速扩缩容?

纵向扩缩容与横向扩缩容

扩缩容我们可以选择纵向扩缩容和横向扩缩容,纵向扩缩容就是提升单机性能,价格上升曲线陡峭,我们通常要慎重选择;横向扩缩容就是提升机器数量,价格上升平稳,也是我们常用的默认扩缩容方式。

Stateful VS Stateless

在网络拓扑图中,Stateful 是存数据的节点;Stateless 是处理数据的节点,不负责保存数据。只有 Stateless 节点才能任意扩缩容,Stateful 节点因为是保存我们的重要数据,所以我们要谨慎对待。如果我们的网络拓扑节点想自由扩缩容,则需要将这个节点的数据操作外移到专门的 Stateful 节点。

后端应用 BaaS 化

我们的 FaaS 访问 Stateful 节点,那我们就希望 Stateful 节点对 FaaS 提供数据接口,而不是单纯的数据库指令,因为数据库连接会增加 FaaS 的额外开支。另外为了方便后端工程师开发,我们需要将 Stateful 节点 BaaS 化,BaaS 化的内容,我们将在后续的课程中展开。

05 | 后端BaaS化(上):NoOps的微服务

微服务的概念

它就是将一个复杂的大型应用拆解成职责单一的小功能模块,各模块之间数据模型相互独立,模块采用 API 接口暴露自己对外提供的服务,然后再通过这些API 接口组合成大型应用。这个小功能模块,就是微服务。

微服务 10 要素

API、服务调用、服务发现;日志、链路追踪;容灾性、监控、扩缩容;发布管道;鉴权。这跟我们要做的 BaaS 化高度重合,我们可以借助微服务来实现我们的 BaaS 化。

解耦数据库

通过额外进程让数据库与副本直接通过消息队列进行同步,所以对于微服务应用来说,只需要关注自身独享的数据库就可以了。微服务通过数据库解耦,将后端应用变成 Stateless 的了,但对后端应用本身而言,数据库还是 Stateful 的。

06 | 后端BaaS化(中):业务逻辑的拆与合

  1. 如何拆解 BaaS 应用,我们学习了微服务的重要拆解思想 DDD:通过对业务分层抽象,分析定义出领域模型,用领域模型驱动我们设计系统,最终将复杂的业务模型拆解为独立运维的领域模型。另外我也介绍了另一种更适合初创企业的拆分思路:动态网络演进。
  2. 拆解完之后,我们就要考虑合并。这里我们介绍了代码编排以外的另一种编排方式:事件流编排,它就是通过一个个事件顺序将我们的微服务或 FaaS 串联起来。
  3. 为了解决拆解后,微服务之间的信任问题。我们先了解了 FaaS 触发器的安全方案:数字签名。还借鉴了微服务的鉴权做法 JWT,将用户鉴权加密信息放在客户端,让鉴权服务变成 Stateless。最后,为了让微服务又快又稳地发布版本,我们借鉴了微服务的发布管道:打造自动灰度流水线。

07 | 后端BaaS化(下):Container Serverless

FaaS 和 BaaS 依赖的底层实现容器 Docker。Docker 也是一种虚拟化技术,它的核心理念是:build、ship、run。通过将我们的应用代码和应用依赖的函数库、二进制包,打包在一起的方式,解决应用开发环境和运行环境的一致性问题。我们可以借助 Docker 容器维持我们的应用实例,来解决初始化慢的问题。

FaaS 的扩缩容逻辑是通过用户配置的“函数初始化入口”,以及固定的“初始化超时时间”配合“单实例并发度”来实现的。而我们在容器 Docker,其实可以采用实时监控配合扩容水位,来做到更加弹性的扩缩容策略。

08 | 搭建私有Serverless(一):K8s和云原生CNCF

K8s 是用于自动部署、扩展和管理容器化应用程序的开源系统。云原生其实就是一套通用的云服务商解决方案。

K8s 的运行原理:K8s Master 节点和 Worker 节点。其中,Master 节点,负责我们整个 K8s 集群的运作状态;Worker 节点则是具体运行我们容器的地方。

09 | 搭建私有Serverless(二):基于K8s的Serverless

Service Mesh 通过 Pod 给我们的应用容器注入了一个伴生容器 Sidecar,配合控制面板来接管我们应用和微服务的网络流量,从而实现网络流量的连接、保护、控制和观测。

Istio,它是基于 K8s 组件实现的 ServiceMesh。我们在 Istio 的基础上又搭建了 Knative,它也是基于 K8s 组件实现的一套Serverless 方案。

总结来说就是,Service Mesh 是一种微服务网络通讯方案,它通过 Sidecar 和控制面板接管了上层的网络通讯,可以让上层开发者无感知地使用网络通讯。我们可以复用 ServiceMesh 的网络通讯能力,部署 Serverless 架构。通过 Service Mesh、Serverless 组件和K8s 集群复杂且精密地配合,支撑我们部署的应用 Serverless 化。

10 | 经验:Serverless架构应该如何选型?

我们在云上创建好 K8s 集群,使用 K8s 集群就跟我们本地使用是一样的,而且很多云服务商还提供“一键部署”让我们快速安装 K8s 组件。最后我们就可以将 Knative 的应用部署上云了。

然而我们虽然可以用 Knative 解决 Container Serverless 的云服务商锁,但却无法解决云服务商用 FaaS 构建起的新壁垒。每个云服务商 FaaS 的 Runtime 都不一样,我们的函数代码要兼容多个云服务商部署,要写很多额外的代码,处理兼容性的问题。

11 | 经验:Serverless开发最佳实践

FaaS 的最佳使用场景:事件响应和 Serverless 应用。事件响应无疑就是 FaaS 的最佳使用场景;而Serverless 应用则需要我们在云服务商提供的 FaaS 服务上,利用我们专栏前面学习到的知识和原理,挑战将完整的应用完全 Serverless 化。

posted @ 2024-01-13 23:11  strongmore  阅读(61)  评论(0编辑  收藏  举报