无服务器架构(Serverless Architectures)(上)

译注:html

  • 为了便于对照参考,“Serverless”、“BaaS” 等术语文中不作翻译。
  • 原文很长,这里分红上下两篇。翻译过程在 GitHub 上进行。

原文:https://martinfowler.com/articles/serverless.html
做者:Mike Roberts前端

无服务器架构(Serverless architectures)是指一个应用大量依赖第三方服务(后端即服务,Backend as a Service,简称“BaaS”),或者把代码交由托管的、短生命周期的容器中执行(函数即服务,Function as a Service,简称“FaaS”)。如今最知名的 FaaS 平台是 AWS Lambda。把这些技术和单页应用等相关概念相结合,这样的架构无需维护传统应用中永远保持在线的系统组件。Serverless 架构的长处是显著减小运维成本、复杂度、以及项目起步时间,劣势则在于更加依赖平台供应商和现阶段仍有待成熟的支持环境。git

引言

无服务器计算(Severless computing,简称 Serverless)如今是软件架构圈中的热门话题,三大云计算供应商(Amazon、Google 和 Microsoft)都在大力投入这个领域,涌现了不可胜数的相关书籍、开源框架、商业产品、技术大会。到底什么是 Serverless?它有什么长处/短处?我但愿经过本文对这些问题提供一些启发。github

开篇咱们先来看看 Serverless 是什么,以后我会尽我所能中立地谈谈它的优点和缺点。web

什么是 Serverless

就像软件行业中的不少趋势同样,Serverless 的界限并非特别清晰,尤为是它还涵盖了两个互相有重叠的概念:docker

  • Serverless 最先用于描述那些大部分或者彻底依赖于第三方(云端)应用或服务来管理服务器端逻辑和状态的应用,这些应用一般是富客户端应用(单页应用或者移动端 App),创建在云服务生态之上,包括数据库(Parse、Firebase)、帐号系统(Auth0、AWS Cognito)等。这些服务最先被称为 “(Mobile) Backend as a Service”,下文将对此简称为 “BaaS”。
  • Serverless 还能够指这种状况:应用的一部分服务端逻辑依然由开发者完成,可是和传统架构不一样,它运行在一个无状态的计算容器中,由事件驱动、生命周期很短(甚至只有一次调用)、彻底由第三方管理(感谢 ThoughtWorks 在他们最近的“技术观察”中对此所作的定义)。这种状况称为 Functions as a service / FaaS。AWS Lambda 是目前的热门 FaaS 实现之一,下文将对此简称为 “FaaS”。

【边栏注释:“Serverless” 术语的起源】数据库

本文将主要聚焦于 FaaS,不只仅由于它是 Serverless 中最新也最热门的领域,更重要的是它和咱们传统技术架构思路的显著不一样。后端

BaaS 和 FaaS 在运维层面有相似之处(都无需管理硬件资源),而且也常常配合使用。主流的云服务商都会提供一套“Serverless 全家桶”,囊括了 BaaS 和 FaaS 产品——例如 Amazon 的 Serverless 产品介绍,Google 的 Firebase 服务也紧密集成了 Google Cloud Functions。api

对小公司而言这两个领域也有交叉,Auth0 最初是一个 BaaS 产品,提供用户管理的各类服务,他们后来建立了配套的 FaaS 服务 Webtask,而且将此概念进一步延伸推出了 Extend,支持其余 BaaS 和 SaaS 公司可以轻松地在现有产品中加入 FaaS 能力。缓存

一些示例

界面驱动的应用(UI-driven applications)

咱们来设想一个传统的三层 C/S 架构,例如一个常见的电子商务应用(好比在线宠物商店),假设它服务端用 Java,客户端用 HTML/JavaScript:

在这个架构下客户端一般没什么功能,系统中的大部分逻辑——身份验证、页面导航、搜索、交易——都在服务端实现。

把它改形成 Serverless 架构的话会是这样:

这是张大幅简化的架构图,但仍是有至关多变化之处:

  1. 咱们移除了最初应用中的身份验证逻辑,换用一个第三方的 BaaS 服务。
  2. 另外一个 BaaS 示例:咱们容许客户端直接访问一部分数据库内容,这部分数据彻底由第三方托管(如 AWS Dynamo),这里咱们会用一些安全配置来管理客户端访问相应数据的权限。
  3. 前面两点已经隐含了很是重要的第三点:先前服务器端的部分逻辑已经转移到了客户端,如保持用户 Session、理解应用的 UX 结构(作页面导航)、获取数据并渲染出用户界面等等。客户端实际上已经在逐步演变为单页应用
  4. 还有一些任务须要保留在服务器上,好比繁重的计算任务或者须要访问大量数据的操做。这里以“搜索”为例,搜索功能能够从持续运行的服务端中拆分出来,以 FaaS 的方式实现,从 API 网关(后文作详细解释)接收请求返回响应。这个服务器端函数能够和客户端同样,从同一个数据库读取产品数据。
    咱们原始的服务器端是用 Java 写的,而 AWS Lambda(假定咱们用的这家 FaaS 平台)也支持 Java,那么原先的搜索代码略做修改就能实现这个搜索函数。
  5. 最后咱们还能够把“购买”功能改写为另外一个 FaaS 函数,出于安全考虑它须要在服务器端,而非客户端实现。它一样经由 API 网关暴露给外部使用。

消息驱动的应用(Message-driven applications)

再举一个后端数据处理服务的例子。假设你在作一个须要快速响应 UI 的用户中心应用,同时你又想捕捉记录全部的用户行为。设想一个在线广告系统,当用户点击了广告你须要马上跳转到广告目标,同时你还须要记录此次点击以便向广告客户收费(这个例子并不是虚构,个人一位前同事最近就在作这项重构)。

传统的架构会是这样:“广告服务器”同步响应用户的点击,同时发送一条消息给“点击处理应用”,异步地更新数据库(例如从客户的帐户里扣款)。

在 Serverless 架构下会是这样:

这里两个架构的差别比咱们上一个例子要小不少。咱们把一个长期保持在内存中待命的任务替换为托管在第三方平台上以事件驱动的 FaaS 函数。注意这个第三方平台提供了消息代理和 FaaS 执行环境,这两个紧密相关的系统。

解构 “Function as a Service”

咱们已经提到屡次 FaaS 的概念,如今来挖掘下它到底是什么含义。先来看看 Amazon 的 Lambda 产品简介

经过 AWS Lambda,无需配置或管理服务器(1)便可运行代码。您只需按消耗的计算时间付费 – 代码未运行时不产生费用。借助 Lambda,您几乎能够为任何类型的应用程序或后端服务(2)运行代码,并且所有无需管理。只需上传您的代码,Lambda 会处理运行(3)和扩展高可用性(4)代码所需的一切工做。您能够将您的代码设置为自动从其余 AWS 服务(5)触发,或者直接从任何 Web 或移动应用程序(6)调用。

  1. 本质上 FaaS 就是无需配置或管理你本身的服务器系统或者服务器应用便可运行后端代码,其中第二项——服务器应用——是个关键因素,使其区别于现今其余一些流行的架构趋势如容器或者 PaaS(Platform as a Service)。

回顾前面点击处理的例子,FaaS 替换掉了点击处理服务器(可能跑在一台物理服务器或者容器中,但绝对是一个独立的应用程序),它不须要服务器,也没有一个应用程序在持续运行。

  1. FaaS 不须要代码基于特定的库或框架,从语言或环境的层面来看 FaaS 就是一个普通的应用程序。例如 AWS Lambda 支持 JavaScript、Python 以及任意 JVM 语言(Java、Clojure、Scala 等),而且你的 FaaS 函数还能够调用任何一块儿部署的程序,也就是说实际上你能够用任何能编译为 Unix 程序的语言(稍后咱们会讲到 Apex)。FaaS 也有一些不容忽视的局限,尤为是牵涉到状态和执行时长问题,这些咱们稍后详谈。

再次回顾一下点击处理的例子——代码迁移到 FaaS 惟一须要修改的是 main 方法(启动)的部分,删掉便可,也许还会有一些上层消息处理的代码(实现消息监听界面),不过这极可能只是方法签名上的小改动。全部其余代码(好比那些访问数据库的)均可以原样用在 FaaS 中。

  1. 既然咱们没有服务器应用要执行,部署过程也和传统的方式截然不同——把代码上传到 FaaS 平台,平台搞定全部其余事情。具体而言咱们要作的就是上传新版的代码(zip 文件或者 jar 包)而后调用一个 API 来激活更新。
  2. 横向扩展是彻底自动化、弹性十足、由 FaaS 平台供应商管理的。若是你须要并行处理 100 个请求,不用作任何处理系统能够天然而然地支持。FaaS 的“运算容器”会在运行时按需启动执行函数,飞快地完成并结束。

回到咱们的点击处理应用,假设某个好日子咱们的客户点击广告的数量有平日的十倍之多,咱们的点击处理应用能承载得住么?咱们写的代码是否支持并行处理?支持的话,一个运行实例可以处理这么多点击量吗?若是环境容许多进程执行咱们能自动支持或者手动配置支持吗?以 FaaS 实现你的代码须要一开始就以并行执行为默认前提,但除此以外就没有其余要求了,平台会完成全部的伸缩性需求。

  1. FaaS 中的函数一般都由平台指定的一些事件触发。在 AWS 上有 S3(文件)更新、时间(定时任务)、消息总线(Kinesis)消息等,你的函数须要指定监听某个事件源。在点击处理器的例子中咱们有个假设是已经采用了支持 FaaS 订阅的消息代理,若是没有的话这部分也须要一些代码量。
  2. 大部分的 FaaS 平台都支持 HTTP 请求触发函数执行,一般都是以某种 API 网关的形式实现(如 AWS API GatewayWebtask)。咱们在宠物商店的例子中就以此来实现搜索和购买功能。

状态

当牵涉到本地(机器或者运行实例)状态时 FaaS 有个不能忽视的限制。简单点说就是你须要接受这么一个预设:函数调用中建立的全部中间状态或环境状态都不会影响以后的任何一次调用。这里的状态包括了内存数据和本地磁盘存储数据。从部署的角度换句话说就是 FaaS 函数都是无状态的(Stateless)

这对于应用架构有重大的影响,无独有偶,“Twelve-Factor App” 的概念也有如出一辙的要求

在此限制下的作法有多种,一般这个 FaaS 函数要么是自然无状态的——纯函数式地处理输入而且输出,要么使用数据库、跨应用缓存(如 Redis)或者网络文件系统(如 S3)来保存须要进一步处理的数据。

执行时长

FaaS 函数能够执行的时间一般都是受限的,目前 AWS Lambda 函数执行最长不能超过五分钟,不然会被强行终止。

这意味着某些须要长时间执行的任务须要调整实现方法才能用于 FaaS 平台,例如你可能须要把一个原先长时间执行的任务拆分红多个协做的 FaaS 函数来执行。

启动延迟

目前你的 FaaS 函数响应请求的时间会受到大量因素的影响,可能从 10 毫秒到 2 分钟不等。这听起来很糟糕,不过咱们来看看具体的状况,以 AWS Lambda 为例。

若是你的函数是 JavaScript 或者 Python 的,而且代码量不是很大(千行之内),执行的消耗一般在 10 到 100 毫秒之内,大函数可能偶尔会稍高一些。

若是你的函数实如今 JVM 上,会偶尔碰到 10 秒以上的 JVM 启动时间,不过这只会在两种状况下发生:

  • 你的函数调用触发比较稀少,两次调用间隔超过 10 分钟。
  • 流量突发峰值,好比一般每秒处理 10 个请求的任务在 10 秒内飙升到每秒 100 个。

前一种状况能够用个 hack 来解决:每五分钟 ping 一次给函数保持热身。

这些问题严重么?这要看你的应用类型和流量特征。我先前的团队有一个 Java 的异步消息处理 Lambda 应用天天处理数亿条消息,他们就彻底不担忧启动延迟的问题。若是你要写的是一个低延时的交易程序,目前而言确定不会考虑 FaaS 架构,不管你是用什么语言。

不论你是否定为你的应用会受此影响,都应该以生产环境级别的负载测试下实际性能状况。若是目前的状况还不能接受的话,能够几个月后再看看,由于这也是如今的 FaaS 平台供应商们主要集中精力在解决的问题。

API 网关

API Gateway

咱们前面还碰到过一个 FaaS 的概念:“API 网关”。API 网关是一个配置了路由的 HTTP 服务器,每一个路由对应一个 FaaS 函数,当 API 网关收到请求时它找到匹配请求的路由,调用相应的 FaaS 函数。一般 API 网关还会把请求参数转换成 FaaS 函数的调用参数。最后 API 网关把 FaaS 函数执行的结果返回给请求来源。

AWS 有本身的一套 API 网关,其余平台也大同小异。

除了纯粹的路由请求,API 网关还会负责身份认证、输入参数校验、响应代码映射等,你可能已经敏锐地意识到这是否合理,若是你有这个考虑的话,咱们待会儿就谈。

另外一个应用 API 网关加 FaaS 的场景是建立无服务器的 http 前端微服务,同时又具有了 FaaS 函数的伸缩性、管理便利等优点。

目前 API 网关的相关工具链还不成熟,尽管这是可行的但也要够大胆才能用。

工具链

前面关于工具链还不成熟的说法是指大致上 FaaS 无服务器架构平台的状况,也有例外,Auth0 Webtask 就很重视改善开发者体验,Tomasz Janczuk 在最近一届的 Serverless Conf 上作了精彩的展现。

无服务器应用的监控和调试仍是有点棘手,咱们会在本文将来的更新中进一步探讨这方面。

开源

无服务器 FaaS 的一个主要好处就是只须要近乎透明的运行时启动调度,因此这个领域不像 Docker 或者容器领域那么依赖开源实现。将来确定会有一些流行的 FaaS / API 网关平台实现能够跑在私有服务器或者开发者工做站上,IBM 的 OpenWhisk 就是一个这样的实现,不知道它是否能成为流行选择,接下来的时间里确定会有更多竞争者出现。

除了运行时的平台实现,仍是有很多开源工具用以辅助开发和部署的,例如 Serverless Framework 在 API 网关 + Lambda 的易用性上就比它的原创者 AWS 要好不少,这是一个 JS 为主的项目,若是你在写一个 JS 网关应用必定要去了解下。

再如 Apex——“轻松建立、部署及管理 AWS Lambda 函数”。Apex 有意思的一点是它容许你用 AWS 平台并不直接支持的语言来实现 Lambda 函数,好比 Go。

什么不是 Serverless

在前文中我定义了 “Serverless” 是两个概念的组合:“Backend as a Service” 和 “Function as a Service”,而且对后者的特性作了详细解释。

在咱们开始探讨它的好处和弊端以前,我想再花点儿时间在它的定义上,或者说:区分开那些容易和 Serverless 混淆的概念。我看到一些人(包括我本身最近)对此都有困惑,我想值得对此作个澄清。

对比 PaaS

既然 Serverless FaaS 这么像 12-Factor 应用,那不就是另外一种形式的 Platform as a Service 么?就像 Heroku?对此借用 Adrian Cockcroft 一句很是简明的话:

若是你的 PaaS 能在 20ms 内启动一个只运行半秒钟的实例,它就叫 Serverless。
Adrian Cockcroft

换句话说,大部分 PaaS 应用不会为了每一个请求都启动并结束整个应用,而 FaaS 就是这么作的。

好吧,然而假设我是个娴熟的 12-Factor 应用开发者,写代码的方式仍是没有区别对么?没错,可是你如何运维是有很大不一样的。鉴于咱们都是 DevOps 工程师咱们会在开发阶段就充分考虑运维,对吧?

FaaS 和 PaaS 在运维方面的关键区别是伸缩性(Scaling)。对于大多数 PaaS 平台而言你须要考虑如何伸缩,例如在 Heroku 上你要用到多少 Dyno 实例?对于 FaaS 应用这一步骤是彻底透明的。即使你将 PaaS 配置为自动伸缩,也没法精细到单个请求级别,除非你有一个很是明确稳定的流量曲线能够针对性地配置。因此 FaaS 应用在成本方面要高效得多。

既然如此,何须还用 PaaS?有不少缘由,最主要的因素应该是工具链成熟度。另外像Cloud Foundry 可以给混合云和私有云的开发提供一致体验,在写就本文的时候 FaaS 尚未这么成熟的平台。

对比容器

使用 Serverless FaaS 的好处之一是避免在操做系统层面管理应用程序进程。有一些 PaaS 平台如 Heroku 也提供了这样的特性;另外一种对进程的抽象是容器,这类技术的表明是 Docker。容器托管系统(Mesos、Kubernetes 等)把应用从系统级开发中抽象出来,这种作法日渐流行,甚至在此之上云服务商的容器平台(如 Amazon ECSEKSGoogle Cloud Engine)也像 Serverless FaaS 同样容许团队从管理主机中彻底解放出来。在这股容器大潮中,FaaS 是否还有优点?

概念上来讲前面对 PaaS 的论断仍旧适用于容器。Serverless FaaS 的伸缩性是彻底自动化、透明、良好组织的,而且自动进行资源监控和分配;而容器平台仍旧须要你对容量和集群进行管理。

另外我还得说容器技术也处在不够成熟和稳定的阶段,尽管它愈来愈接近了。固然这不是说 Serverless 就成熟了,但你终究须要在两个都属前沿的技术方向中作出选择。

还有个值得一提的是很多容器平台支持了自动伸缩的容器集群,Kubernetes 有内建的 Horizontal Pod Autoscaling 功能,AWS Fargate 则承诺会有“Serverless 容器”。

总的来讲 Serverless FaaS 和托管容器在管理和伸缩性方面的差异已经不大,在它们之间的取舍更多看风格取向和应用的类型。例如事件驱动的应用组件更适合用 FaaS 实现,而同步请求驱动的应用组件更适合用容器实现。我预计很快就会有很多团队和应用同时采用这两种架构模式,期待看它们会擦出怎样的火花。

对比 NoOps

Serverless 并不是“零运维”——尽管它多是“无系统管理员”,也要看你在这个 Serverless 的兔子洞里走多深。

“运维”的意义远不止系统管理,它还包括并不限于监控、部署、安全、网络、支持、生产环境调试以及系统伸缩。这些事务一样存在于 Serverless 应用中,你仍旧须要相应的方法处理它们。某些状况下 Serverless 的运维会更难一些,毕竟它仍是个崭新的技术。

系统管理的工做仍然要作,你只是把它外包给了 Serverless 环境。这既不能说坏也不能说好——咱们外包了大量的内容,是好是坏要看具体状况。不论怎样,某些时候这层抽象也会发生问题,就会须要一个来自某个地方的人类系统管理员来支持你的工做了。

Charity Majors 在第一届 Serverless 大会上就这个主题作了个很是不错的演讲,也能够看看她相关的两篇文章:WTF is operations?Operational Best Practices)。

对比存储过程即服务

还有一种说法把 Serverless FaaS 看作“存储过程即服务(Stored Procedures as a Service)”,我想缘由是不少 FaaS 函数示范都用数据库访问做为例子。若是这就是它的主要用途,我想这个名字也不坏,但终究这只是 FaaS 的一种用例而已,这样去考虑 FaaS 局限了它的能力。

我好奇 Serverless 会不会最终变成相似存储过程那样的东西,开始是个好主意,而后迅速演变成大规模技术债务。
Camille Fournier

但咱们仍然值得考虑 FaaS 是否会致使跟存储过程相似的问题,包括 Camille 提到的技术债。有不少存储过程给咱们的教训能够放在 FaaS 场景下从新审视,存储过程的问题在于:

  1. 一般依赖于服务商指定的语言,或者至少是指定的语言框架/扩展
  2. 由于必须在数据库环境中执行因此很难测试
  3. 难以进行版本控制,或者做为应用包进行管理

尽管不是全部存储过程的实现都有这些问题,但它们都是常会碰到的。咱们看看是否适用于 FaaS:

第一条就目前看来显然不是 FaaS 的烦恼,直接排除。

第二条,由于 FaaS 函数都是纯粹的代码,因此应该和其余任何代码同样容易测试。整合测试是另外一个问题,咱们稍后展开细说。

第三条,既然 FaaS 函数都是纯粹的代码,版本控制天然不成问题;最近你们开始关心的应用打包,相关工具链也在日趋成熟,好比 Amazon 的 Serverless Application Model(SAM)和前面提到的其余 Serverless 框架都提供了相似的功能。2018 年初 Amazon 还开放了 Serverless Application Repository(SAR)服务,方便组织分发应用程序和组件,也是基于 AWS Serverless 服务构建的。关于 SAR 能够看看个人另外一篇文章:Examining the AWS Serverless Application Repository

本文翻译的实时更新: https://amio.github.io/server...
相关文章
相关标签/搜索