1. Serverless 综述
1.1 专业术语
BFF:Backend For Frontend,服务于前端的后端。
SOC:Separation of concerns,关注点分离。
RPC:Remote Procedure Call,远程过程调用。
DSL:Domain Specific Language,领域特定语言。
SSR:Server Side Rendering,服务端渲染。
IaaS:Infrastructure as a Service,基础设施即服务。
PaaS:Platform as a Service,平台即服务。
SaaS:Software as a Service,软件即服务。
CDN :Content Delivery Network,内容分发网络。
OSS:Object Storage Service,对象存储服务。
RDS:Relational Database Service,关系型数据库服务。
MQS:Message Queue Service,消息队列服务。
AIoT:Artificial Intelligence & Internet of Things,AI(人工智能) IoT(物联网),人工智能物联网。
CNCF:Cloud Native Computing Foundation,云原生计算基金会,该组织的主要职责是推广标准化的云原生技术。目前全球主要的云计算供应商,包括 Amazon、Google、Microsoft、阿里巴巴、华为等在内的数百家公司已加入了该组织。CNCF 目前已包含 Kubernetes 、Prometheus、gRPC 等1000 余个开源项目。
Amazon EC2:Amazon Elastic Compute Cloud,亚马逊弹性计算云,是一个让使用者可以租用云端电脑运行所需应用的系统。
ECS:Elastic Compute Service,弹性计算服务,是阿里云提供的最基础的云计算服务,是基于虚拟化技术后的计算单元,使用 ECS 云服务器可以像用水电一样便捷,拿来即用。
GAE:Google App Engine,是 Google 管理的数据中心中用于 WEB 应用程序的开发和托管的平台。GAE 其实是一种 Applicationless(无应用),从本质上来说它是一个 PaaS。
Infrastructure Engineer:基础设施研发工程师,致力于提供更易于使用的计算资源,并使得计算资源的利用就像水电煤的使用那样便利。
Application Engineer:应用研发工程师,专注于业务研发,以便更快、更好、更容易地开发出让用户满意的产品。
1.2 什么是 Serverless
CNCF 定义的云原生技术:有利于各组织在公有云、私有云和混合云等新型动态环境中,构建和运行可弹性扩展的应用。云原生的代表技术包括容器、服务网格、微服务、不可变基础设施和声明式 API。
Serverless 是云原生下的一个重要方向。CNCF 发布的 Serverless 白皮书探讨了关于 Serverless 的理念、定义及其价值,即 Serverless 指的是无论在应用的构建环节还是运行环节,都无须对服务器进行维护和管理。
Serverless 帮助我们屏蔽了服务器、操作系统、系统软件等概念,让我们无须关心服务器的负载情况、部署节点等技术细节,能更聚焦于实现业务逻辑。
Serverless 的核心特性是按用量付费(Pay As You Go)和弹性计算(Elastic Compute)。
Serverless 计算平台应该包含以下一种或两种能力:
1)FaaS(Functions as a Service,函数即服务):提供基于事件驱动的计算服务,开发者以函数片段的方式来管理应用代码,这些函数通过事件或 HTTP 请求来触发。和传统应用相比,其以更细粒度的函数方式来进行部署,这样计算资源就可以实现更精细的调度和管理,且这些操作都将自动化完成,无须开发者参与。例如 Amazon AWS Lambda、Google Cloud Functions、Microsoft Azure Functions、IBM OpenWhisk、阿里云 Function Compute 都属于 FaaS。
2)BaaS(Backend as a Service,后端即服务):可以用来替换应用程序中的一些核心能力,且直接通过 API 的方式提供的第三方服务。由于这些服务自身实现了自动扩容/缩容的能力,因此开发者无须了解与服务器相关的信息。例如 GitHub Pages、CDN、OSS、RDS、MQS 都属于 BaaS。
1.3 Serverless 与前端架构
前端架构从出现到现在的演化大致可分为6个阶段,即静态内容展示、可交互页面、Web 2.0、单页面应用、前后端分离和基于 Serverless 的前后端分离。
1.3.1 基于 BFF 与微服务的前后端架构
在 BFF 架构的普及之下,前端需要面临 3 个新的问题:
1)增加的 Node.js 应用,带来了更多的运维成本;
2)中长尾应用导致 Node.js 应用的计算资源长期闲置;
3)大量类似的基础服务(如身份认证、权限管理、消息推送等能力)需要在多个 Node.js 应用中实现。
1.3.2 基于 Serverless 的 BFF 架构
基于 Serverless 的 BFF 降低了前端在服务器运维上的成本,能够快速地完成函数的部署,通过按需计费的方式,解决了计算资源浪费而最终造成的服务器费用问题。
1.4 Serverless 应用场景
1.4.1 适合 Serverless 场景业务的具体特征
1)状态可以通过 BaaS 存储至数据库或其他持久化的服务中。因为函数自身是无状态的,无法直接在函数中保存这些数据。
2)每个函数都是可以独立工作的,其相互间应该尽量没有依赖,或依赖较小。由于计费系统是按单个函数进行统计的,如果出现大量函数的联动调用,计算资源费用就会上升。
3)函数长期处于无负载的状态,或负载波动不可预测且十分剧烈。在长期无负载的状态下,可以自动缩容到零个实例,可以大幅度地降低成本;不可预测的剧烈波动,也可以使得自动扩容/缩容的能力得以最大化地发挥。
4)业务是基于事件驱动的,每一个函数能通过事件触发,这些事件包括 HTTP 请求、数据库修改、定时事件等。
5)对冷启动时间没有强烈的性能要求。当缩容到零个实例后,新的请求需要重新初始化容器,可能导致毫秒至秒级的延迟。
1.4.2 适合 Serverless 改造的团队的研发模式和理念特征
1)业务是快速变化的,需要研发人员提高应用程序的变更速度和频率。
2)希望能够降低服务器的运维成本,减少运维人员及相应的开支。
3)希望能够降低服务器的机器成本,减少服务器的数量及相应的开支。
4)希望提高生产力,并能承受使用尚未成熟的技术所带来的风险。
1.4.3 服务端的应用场景
1)多媒体处理
基于 Serverless 的视频转码服务架构:
2)数据库变更捕获
基于 Serverless 的自动翻译架构:
3)处理IoT请求
基于 Serverless 的 IoT 数据采集架构:
4)聊天机器人
基于 Serverless 的聊天机器人架构:
5)计划任务
基于 Serverless 的计划任务:
6)通用后端服务
基于 Serverless 的后端服务架构:
1.4.4 前端的应用场景
1)Web 应用
以实现一个单页面应用的服务端为例,通常有两部分功能:应用入口页面和 Web API。基于弹性计算的 FaaS 架构可以更好地适应这一场景。入口页面直接通过网关返回,Web API 也可以更灵活地实现。每个 API 可以独立评估,从而更准确地预估服务器的负载情况,这些服务可以根据自己的负载情况自动扩容/缩容从而独立计费,这使得对服务器资源的管理和利用更加精细化。
2)SSR 应用
它让用户在首次访问时,由服务端渲染页面;在后续的交互中,通过 SPA 的方式完成渲染。它既通过客户端渲染,保障了良好的页面交互体验;又通过服务端渲染,让页面首次打开的速度得以提升。
基于 FaaS 来提供 SSR 输出,可以更方便地使用服务端计算资源。将每个函数绑定到一个 URL,当用户请求这个 URL 时,该函数将返回一个对应的 SSR 页面。我们只需要完成函数的编写并发布即可,剩下的运维工作都将由平台完成。
基于 Serverless 的 SSR 架构:
这种按函数来返回页面的方式,可以更灵活地实现组装。我们可以将页面切分为多个区域,每个区域由特定的函数生成。当用户打开页面时,可以优先请求并加载某一区域的页面代码。同时,这些不同区域的模块可以灵活地复用到不同的页面中,也可以根据不同的更新频率来缓存这些区域,从而进一步提高服务的性能。
3)移动客户端应用
使用 Serverless 架构,可以通过 BaaS 更轻松地集成和使用对应的服务端能力。另外,将原有服务端的业务逻辑通过 FaaS 实现,可以有效地提升服务端业务逻辑的开发效率。研发人员无须在开发移动客户端应用的同时,关注服务端的可用性等问题,将精力更加聚焦在移动客户端应用自身的开发中,加快 App 的迭代速度。
4)小程序
目前微信及支付宝等小程序平台均已提供了相应的 Serverless 云计算服务,包括 FaaS 及 BaaS 两大功能。研发人员通过 FaaS 编写Web API,并通过 BaaS 来使用必要的云计算服务(如数据库服务、文件存储服务等),以完成小程序的后端开发工作,这使得小程序研发人员的服务端研发成本大幅降低。
1.5 Serverless 与服务端技术
1.5.1 应用分层架构
在传统的企业应用架构中,通常只有一个应用,所有的业务代码都在同一个系统中组织,即单体应用程序(Monolith Application,简称单体应用)。
经典的3层架构:
通过在传统分层架构的应用上使用 Serverless 技术,可以有效地降低应用的整体研发成本。
1)将传统架构中的用户登录、权限验证等通用功能从业务代码中抽取出来,用 BaaS 取代,可以降低研发成本、降低代码的复杂度,提高代码的可测试性。通过直接从逻辑层调用相应的 BaaS 服务,减少了非业务代码在不同层之间的来回传递,使得代码逻辑更加清晰、简单。
2)单体应用内部的耦合度往往极高,如果某个服务请求量较高导致了性能瓶颈,无法单独扩展该服务,而必须扩展整个应用,将导致较大的维护成本和资源浪费。通过 FaaS,可以针对特定的接口完成扩容。
从3层架构到 Serverless 架构:
1.5.2 微服务架构
微服务(Microservices)是一种软件架构风格,从分布式架构发展演变而来。它通过将一个大型单体应用程序切分为多个独立小型服务的方式来实现更轻量、可控的软件研发管理。这些服务通常按业务的功能模块进行划分,并独立进行研发和部署,运行在各自的服务器集群中,互不影响,服务间通过 RPC来实现相互通信。
基于微服务架构的应用,通常更适合也更容易被转换为 Serverless 架构。通过微服务到Serverless 的改造,我们可以用更细粒度的方式对资源进行管控;通过按用量计费的方式,可有效地降低企业的成本。
基于 Serverless 的微服务架构:
微服务架构与 Serverless 自身并不是取代关系。微服务架构指的是,一个完整的应用是通过多个服务组合而成的,这些服务可以选择不同的技术来实现。而 Serverless 指的是一种计算资源的调度,即通过函数的方式实现更灵活的资源调度。所以,即使在 Serverless模式下,也同样能够应用微服务架构。
在 Serverless 模式下,由于将原来的服务拆分成了成百上千个函数,因此这些函数应该如何更好地组织,正是目前 Serverless 所面临的问题之一。而通过微服务的理念,我们可以更有效地组织和管理 Serverless 中的函数。
1.5.3 云计算
云计算,是通过将计算资源“虚拟化”,让用户无须了解计算资源背后的细节,也不必具备相应的专业知识,就能直接使用。与传统的物理机部署方式相比,云计算服务通常具备随用随取、易于扩展的优势,并且因为其按需使用、多人共享的特性,企业能更轻松地节省使用计算资源的费用。
目前云计算按服务模式分类,通常被划分为三大类:IaaS、PaaS、SaaS。
Serverless 将是一种更自然的使用计算资源的方式,将可能成为下一代云计算的服务模式。
1.5.4 容器化
与虚拟机相比,容器化有轻量化、易于配置、快速扩展、易于迁移等优点。
容器化技术进一步将操作系统进行了虚拟化,通过 Linux的 Control Groups 和 Namespace 两大特性,实现了对系统资源(主要是 CPU 和内存)的隔离,提供了能使不同容器独立且安全运行的环境。
容器化技术的明星产品 Docker,是一个开源的应用容器,可以让研发人员将应用程序通过构建,打包成一个 Docker 镜像文件,然后通过容器编排(通常为 Kubernetes)技术部署。通过 Docker 部署应用,我们可以极大地降低应用程序的部署成本。
FaaS在容器化的基础之上,进一步将应用框架实现了虚拟化。FaaS 是对容器化技技术的进一步封装,它对Dockfile 文件也进行了屏蔽,由 FaaS 的提供商进行维护。
1.5.5 NoOps
软件行业在精益生产哲学思想的基础上,提出了适用于软件行业自身的生产管理理念,即持续集成(Continuous Integration,CI)、持续交付(Continuous Delivery,CD)和持续部署(Continuous Deployment)。
持续集成主要指的是研发人员在提交任意代码后,系统将立刻进行打包构建和自动化测试;持续交付是紧接在持续集成之后的流程,旨在让应用快速达到可运行的状态;持续部署则是在持续交付的基础上,把最后的部署流程进行了自动化。
基于持续集成、持续交付和持续部署的理念,诞生了 DevOps 的软件开发模式。DevOps 是Development 与 Operations 的组合,表示作为软件研发人员,同时负责开发和运维工作。
NoOps 是 DevOps 的下一阶段,在 DevOps 的模式下,我们仍然需要编写用于构建和发布的脚本,并手动执行它们,然后监控线上负载情况,根据负载进行扩容或缩容操作。而在 NoOps 的理念下,这一切都交给了云计算供应商。
NoOps 仅仅是一种理念,基于 Serverless 架构的研发方式,正是 NoOps 理念的实践方式。
1.6 Serverless 与前端技术
1.6.1 BFF
BFF 主要通过在前端和后端之间增加一个“胶水层”(由对应的客户端负责编写),实现对客户端所需要的 API 的聚合和裁剪,从而解决前后端分离之后所带来的协作问题。
BFF 层只关注两件事情,即聚合和裁剪。聚合指的是根据客户端当前页面所需要的数据,合并不同的微服务,最终提供一个统一的接口,以避免客户端多次发送请求来获取数据;裁剪指的是基于聚合后的接口,将接口中的字段转换为客户端需要的格式,并移除那些客户端中不需要的字段,这样可以避免在客户端中的格式转换,减少不必要的数据传输。
可以看出,BFF 具备以下优势:
1)接口可灵活装配,客户端需要的数据可调用对应的微服务获取,格式也可在服务端完成转换。
2)可降低沟通成本。服务端的开发者无须了解客户端所需的数据接口,就可以开发服务。
3)有利于客户端的性能优化。通过接口的聚合,减少了客户端向服务端请求的次数,同时减少了数据的传输量。
4)有利于提升客户端的安全性,减少数据的暴露。
通过将 BFF 的 Node.js 应用迁移至 FaaS 服务,将有效提高 BFF 的研发和运维效率。
1.6.2 Node.js
基于 Node.js 的 Serverless 应用能够轻松地开发服务端应用程序,并且实现应用的快速部署、低成本运维。
1.6.3 TypeScript
由于 FaaS 将应用进一步拆分成了函数,因此不太容易出现代码规模较大的情况。在云服务供应商提供的 FaaS 产品上,很少看到有原生工具支持 TypeScript,原因有二:一来,复杂度没有达到采用 TypeScript 的价值;二来,FaaS 自身并不提倡构建复杂函数,函数应该尽量保持简单,以便易于维护。
1.6.4 GraphQL
GraphQL 是一种查询语言,对 API 中的数据提供了一套易于理解的完整描述,使得客户端能够准确地获得自身需要的数据,而没有任何冗余。
GraphQL 的定位与 BFF 类似,只是 GraphQL 通过框架实现了所有资源具备聚合能力,而 BFF 是由研发人员通过代码实现聚合能力的。
对 GraphQL 服务来说,只需要提供一个端点(EndPoint)即可,客户端的所有查询语句,都通过这个端点来请求数据。由于所有请求都被聚合在了一个接口中,对这个接口的流量判断是极其困难的,通过 Serverless 来实现这个接口,可解决此问题。
1.6.5 NoBackend
NoBackend 希望以前端驱动的设计过程来实现一个产品的构建。这个概念和“大中台,小前台”的理念十分相似,通过将大量的服务端业务抽象为通用能力,不同产品线,统一由中台提供基础能力,从而实现在前台产品构建的过程中只需要关注产品自身的功能,而不受后端技术的制约。
随着 NoBackend 思想的不断发展,逐渐演化成 BaaS 的核心理念。