无服务架构(Serverless Architectures)
无服务器架构是一种应用程序设计,它整合了第三方的 “后端即服务(backend as a service)” (BaaS)服务,以及/或包含在“ 功能即服务(functional as a service)” (FaaS) 平台上托管的临时容器中运行的自定义代码。通过使用这些思想以及单页应用程序等相关思想,这样的体系结构消除了对传统的始终在线服务器组件的大量需求。无服务器架构可能受益于显著降低的操作开销、复杂度和工程交付时间,而代价是增加对供应商依赖和相对不成熟的支持服务的依赖。
无服务计算(Serverless Computing),或者更简单的 Serverless,在软件架构世界中是一个非常火热的话题。云供应商三巨头 —— Amazon、Google 以及 Microsoft 都很在 Serverless 上投资了大量资源,我们看到的许多致力于此的大量书籍以及开源项目,会议以及软件供应商。但是什么是 Serverless?为什么考虑 Serverless 是值得的?这篇文章就是为了解决这些问题的。
让我们从什么是无服务架构开始,并列出其中的优点和缺点。
什么是 Serverless?
就像软件领域的许多趋势一样,没有人清楚地知道什么是无服务器。首先,它包含两个不同但重叠的领域:
- Serverless 最初用于描述显著或完全合并第三方云托管应用程序和服务的应用程序,以管理服务器端逻辑和状态。这些典型的 “富客户端(rich client)” 应用程序 —— 想想单页面应用程序或移动应用程序 —— 使用云访问数据库(如 Parse、Firebase)的庞大生态系统,身份验证服务(如 Auth0、AWS Cognito),等等。这些类型的服务之前都被描述为 “后端即服务”,我在后面的内容将此简述为 “BaaS”。
- Serverless 也可以是指服务器端逻辑仍然由应用程序开发人员编写的应用程序,但是,与传统架构不同的是,它运行在无状态计算的容器中,它负责事件触发的、短暂的(可能只持续一次调用)、完全由第三方管理的。称之为 “函数即服务(FaaS)”。(注意:原始资源将它命名的,但是现在无法访问了)AWS Lambda 是其中最受欢迎的 FaaS 平台实现,但是也有很多其它的实现。
在这篇文章里,我们主要集中讨论 FaaS。这不仅是因为 Serverless 领域的更新和大量的炒作,而且它与我们通常认为的技术架构有显著的不同。
BaaS 和 Faas 在它们的操作属性中有一些是相关的(如无资源管理)并且经常一起使用。最大的云供应商全部都有 “无服务组合(Serverless portfolios)”,包含 BaaS 和 Faas 的一些产品—— 例如,Amazon Serverless 产品页。Google 的 BaaS 数据库 Firebase 数据库就已经通过 Google 云函数 Firebase 显式支持了 FaaS。
小公司在这两个领域也有类似的联系。Auth0 从一个实现了多用户管理的 BaaS 产品开始,随后创建了配套的 FaaS 服务 Webtask。该公司通过扩展将这一想法更进一步,使其他 SaaS 和 BaaS 公司能够轻松地向现有产品添加 FaaS 功能,从而创建统一的无服务器产品。
一系列的案例
UI 驱动程序
让我们回头看具有服务器端逻辑的传统三层面向客户端的系统。一个典型的例子就是电商 app。
传统架构图看起来就像下面展示:
使用这种体系结构,客户端可能相对不智能,系统中的许多逻辑 —— 身份验证、页面导航、搜索和事务 —— 都是由服务器应用程序实现的。
如果使用 Serverless 架构的话,那么就会像下图所示:
这是一个非常简化的视图,但即使在这里我们也看到了一些显著的变化:
-
我们在应用程序中删除了身份验证以及用第三方 BaaS 服务替换(如 Auth0)
-
使用其它的 BaaS 的案例,我们允许客户端直接访问数据库的一个子集(用于产品列表),该数据库本身完全由第三方托管(例如谷歌 Firebase)。对于以这种方式访问数据库的客户机,我们可能有不同的安全配置文件,而对于访问数据库的服务器资源,我们可能有不同的安全配置文件。
-
前面两点暗示了非常重要的第三点:一些在宠物商店服务(Pet Store Server)中的逻辑现在在客户端中,例如,跟踪用户会话,理解应用程序的 UX 结构,从数据库读取数据并将其转换成可用的视图,等等。客户端正在朝着成为单页应用程序的方向发展。
-
我们可能希望在服务器中保留一些与 UX 相关的功能,例如,如果它是计算密集型的或需要访问大量的数据。在我们的宠物店例子中就是 “搜索” 功能。与原始体系结构中始终运行的服务器不同,我们可以实现一个 FaaS 函数,该函数通过 API 网关(稍后介绍)响应 HTTP 请求。客户端和服务器的 “搜索” 功能都从同一个数据库中读取产品数据。
如果我们选择使用 AWS Lambda 作为我们的 FaaS 平台,我们可以将从原来的宠物商店服务器的搜索代码移植到新的宠物商店上,而不需要完全重写,因为 Lambda 支持 Java 和 javascript —— 我们最初使用的实现语言。
-
最后,我们可以将 “Purchase” 功能替换为另一个独立的 FaaS 功能,出于安全考虑,选择将其保留在服务器端,而不是在客户端中重新实现它。它的前端也是一个 API 网关。在使用 FaaS 时,将不同的逻辑需求分解为单独部署的组件是一种非常常见的方法。
回过头来看,这个例子展示了关于无服务架构的另一个非常重要的观点。在原始版本中,所有流、控制和安全性都由中央服务器应用程序管理(中心化管理)。在无服务版本中,没有这些问题的中心仲裁者。是去中心化的。相反,我们看到编排比编排(choreography over orchestration )更受欢迎,每个组件都扮演更具有体系结构意识的角色 —— 这一想法在微服务方法中也很常见。
使用这种方式有很多好处。Sam Newman 在他的构建微服务的笔记中记载道,以这种方式构建系统会 “更加灵活,更加适应变化”,无论是作为整体还是通过组件的独立更新;有更好的明确的分工;还有一些令人着迷的成本效益,Gojko Adzic 在这次精彩的演讲中讨论了这一点。
消息驱动程序
另一个例子是后端数据处理服务。
现在你正在写一个用户中心应用程序,它需要以秒级快速响应请求,它还需要为随后的处理捕捉所有的用户所发生的不同状态。在说一个在线广告系统:当用户点击一个广告时,要快速重定向到广告目标页。与此同时,你还要手机点击事件发生的事实以便向广告商收取费用。(这个例子并不是假设的——我在 Intent Media 的前团队正是有这种需求,他们以 Serverless 的方式实现了这种需求。)
你可以看到传统架构是下面图展示的。”广告服务器“ 同步响应到用户并发送一个 ”点击事件“ 到通信管道中去。然后该消息由更新数据库的 “点击处理程序” 异步处理,例如,以减少广告客户的预算。
Severless 模式就像下面所示:
能看到不同么?不同的是在这个架构图中要比第一个例子的变化要小得多 —— 这也是为什么 Serverless 技术在异步消息处理如此受欢迎的用例。我们用 FaaS 取代了长期的消息消费者程序。这个函数运行在供应商提供的事件驱动上下文内。注意,云平台供应商都会提供消息 broker 以及 FaaS 环境 —— 两个系统紧密相连。
FaaS 环境也能并发的处理多个消息,通过复制多个 FaaS 实例。根据我们编写原始流程的方式,这可能是我们需要考虑的新概念。
分解 ”函数即服务(Function as a Service)“
之前已经提到 FaaS,现在是时候解释它真正的含义了。首先我们来看一下 Amazon FaaS 产品的公开描述:Lambda。我已经加了一些标记,后面我会拓展。
AWS Lambda 能允许您在不配置或管理服务器的情况下运行代码。1) 使用 Lamda 您可以为几乎任何类型的应用程序或后端服务运行代码。2)所有这些都是零管理。只要上传代码,Lambda 就会处理运行所需的一切。3)以高可用的方式拓展代码。你可以设置你的代码自动在其它 AWS 服务上触发。4)或者可以在任何网站和移动 app 直接调用。
-
从根本上讲,FaaS 是不需要管理自己的服务器系统或长期运行的服务器程序运行后台代码。与容器和 PaaS(平台即服务)等现代体系结构趋势相比,第二个子句 —— 长期存在的服务器应用程序 —— 是一个关键的区别。
如果我们回到点击处理程序的例子,FaaS 替代了点击处理程序服务(可能是物理机,上面有一个应用程序)不需要特定的服务器,也不需要一直需要运行的应用程序。
-
FaaS 产品不需要对特定的框架或库进行编码。FaaS 函数是语言和环境方面的常规应用程序。例如 AWS Lambda 函数可以在Javascript、Python、Go、任何JVM 语言(Java、Clojure、Scala 等)或任何 . net 语言中实现“一级类(first class)”。然而,Lambda 函数还可以执行与其部署构件绑定的另一个进程,因此您可以实际使用任何可以编译成 Unix 进程的语言(请参阅本文后面的Apex)。
但是 FaaS 功能有重要的架构限制,特别是在状态和执行持续时间方面。我们很快就会讲到。
让我们再次回到我们的点击处理示例。在转移到 FaaS 时,唯一需要更改的代码是 “主方法” (启动)代码,因为它被删除了,而且很可能是顶级消息处理程序(“消息侦听器接口”实现)的特定代码,但这可能只是方法签名的更改。其余的代码(例如,写入数据库的代码)在 FaaS 中没有什么不同。
-
部署与传统系统非常不同,因为我们不需要自己运行承载应用程序的服务器。在 FaaS 环境中,我们将函数的代码上传到 FaaS 供应商,而提供者则负责提供资源、实例化 vm、管理进程等所有必要的工作。
-
水平扩展是完全自动的、弹性的,并由提供者管理。如果您的系统需要并行处理 100 个请求,则供应商将处理该请求,而不需要您进行任何额外的配置。执行函数的 ”计算容器” 是短暂的,FaaS 供应商提供者完全由运行时需求驱动来创建和销毁它们。最重要的是,使用 FaaS,供应商处理所有底层资源的供应和分配 — 用户根本不需要集群或虚拟机管理。
让我们回到点击处理器那个案例。假设我们今天是个好日子,客户的点击量是平常的十倍。对于传统的体系结构,我们的点击处理应用程序能够处理这个问题吗?例如,我们是否开发了能够同时处理多条消息的应用程序?如果我们这样做了,一个正在运行的应用程序实例是否足以处理高负载?如果我们能够运行多个实例,那么拓展是自动的,还是需要手动重新配置?使用 FaaS 方法,所有这些问题都已经得到了回答 —— 您需要提前以假设水平伸缩的并行性编写该函数,但从这一点开始,FaaS 提供者会自动处理所有上面说的这些需求。
-
FaaS 中的函数通常由提供者定义的事件类型触发。对于 Amazon AWS,这样的触发包括 S3(文件/对象)更新、时间(计划任务)和添加到消息总线的消息(例如,Kinesis)。
-
大多数提供者还允许作为对 HTTP 请求的响应触发函数。在 AWS 中,通常通过使用 API 网关来实现这一点。在我们的 Pet Store 示例中,我们使用了一个API 网关来实现 “搜索” 和 “购买” 功能。还可以通过平台提供的 API 直接调用函数,可以从外部调用,也可以从相同的云环境中调用,但这种用法相对不常见。
状态
FaaS 函数在处理本地(机器/实例绑定)状态时有很大的限制,例如存储在内存变量中的数据,或写入本地磁盘的数据。您的确有这样的存储需求,但您不能保证这种状态在多个调用之间持久化,而且更强烈地说,您不应该假设一个函数调用的状态对另一个相同的调用是可用的。因此 FaaS 函数通常被描述为无状态的,但是更准确地说,需要持久的 FaaS 函数的任何状态都需要在 FaaS 函数实例之外被具体化。
对于无状态的 FaaS 函数,例如对于那些仅提供输入到输出的函数转换的应用程序,这是无关紧要的。但对于其他人来说,这可能会对应用程序架构产生很大的影响,尽管不是唯一的——”十二因素应用程序“的概念有完全相同的限制。这种面向状态的函数通常会利用数据库、跨应用程序缓存(如 Redis)或网络文件/对象存储(如 S3)来跨请求存储状态,或提供处理请求所需的进一步输入。
执行期间
FaaS 函数在它每次允许调用的时间是受限的。目前 AWS Lambda 函数响应一个事件的时间在超时时间到达终止之前最多为 5 分钟。Microsoft Azure 和 Google Cloud Functions 都有相同的限制。
这意味着如果不进行重新架构,某些长期存在的这类任务就不适合 FaaS 功能 —— 您可能需要创建几个不同的协同 FaaS 功能,这在以前传统环境中你可能有一个长时间任务同时执行协作和执行。
启动延迟和 ”冷启动“
FaaS 平台在每个事件之前初始化一个函数的实例需要一些时间。即使对于一个特定的函数,启动延迟也可能变化很大,这取决于许多因素,可能从几毫秒到几秒不等。这听起来很糟,但让我们更具体一点,以 AWS Lambda 为例。Lambda 函数的初始化可以是“热启动” —— 重用 Lambda 函数的一个实例以及来自前一个事件的宿主容器。或者是“冷启动” —— 创建一个新的容器实例,启动函数宿主进程,等等。
不出所料,在考虑启动延迟时,最让人关心的就是这些冷启动。
冷启动取决于很多因素:你使用的语言,你使用的那些组件,所写的代码以及 Lamdba 功能自己的配置环境,是否需要连接 VPC 资源等等。这些方面很多都是受开发者控制的,所以通常可以减少作为冷启动的一部分而导致的启动延迟。
与冷启动持续时间一样可变的是冷启动频率。例如,如果一个函数每秒处理 10 个事件,每个事件处理时间为 50 毫秒,那么您可能只会看到 Lambda 每 10 万到20 万个事件发生一次冷启动。另一方面,如果您每小时处理一次事件,您可能会看到每个事件的冷启动,因为 Amazon 会在几分钟后停止不活动的 Lambda 实例。了解这一点将有助于您理解冷启动是否会影响聚合,以及您是否希望对函数实例执行“保持活跃状态”以避免它们被忽略。
冷启动有什么影响?这取决于应用程序的形式和流量形状。我以前在 Intent Media 的团队有一个异步消息处理 Lambda 应用,用 Java 实现(通常是启动时间最慢的语言),每天处理数亿条消息,他们不担心这个组件的启动延迟。也就是说,如果您正在编写一个低延迟的交易应用程序,那么此时您可能不希望使用云托管的FaaS 系统,无论您使用哪种语言来实现。
无论您是否认为您的应用程序可能存在这样的问题,您都应该使用类似于产品的负载来测试性能。如果您的用例现在不能工作,您可能想在几个月后再试一次,因为这是 FaaS 供应商持续改进的主要领域。
API 网关
我们前面提到的无服务的一个方面是“API 网关“。API 网关是在配置中定义路由和终结点的 HTTP 服务器,每个路由都与处理该路由的资源相关联。在无服务体系结构中,此类处理程序通常是 FaaS 函数。
当 API 网关接收到请求时,它会找到与请求匹配的路由配置,如果是 FaaS 支持的路由,它会调用相关 FaaS 函数来表示原始请求。通常,API 网关将允许从 HTTP 请求参数映射到 FaaS 函数的更简洁的输入,或者将允许通过整个 HTTP 请求(通常作为一个 JSON 对象)。FaaS 函数将执行其逻辑并将结果返回给 API网关,该网关将该结果转换为 HTTP 响应,并将该响应传递回原始调用者。
Amazon Web Services 有自己的API网关(名称稍有混淆的“API 网关”),其他供应商也提供类似的功能。Amazon 的 API Gateway 本身就是一个 BaaS(是的,是BaaS!)服务,因为它是一个您可以配置的外部服务,但不需要您自己运行或提供。
除了纯粹的路由请求之外,API 网关还可以执行身份验证、输入验证、响应代码映射等等。(如果你在思考这是否真的是个好主意的时候,你蜘蛛般的感觉开始发麻,那就先别想了!我们稍后再进一步考虑。)
具有 FaaS 功能的 API 网关的一个用例是以无服务的方式创建基于 http 的微服务,这些微服务具有来自 FaaS 功能的所有扩展、管理和其他好处。
当我第一次写这篇文章时,至少 Amazon API Gateway 的工具还非常不成熟。自那以后,这些工具有了显著的改进。像 AWS API Gateway 这样的组件还不是“主流”,但希望它们不像以前那么痛苦,而且只会继续改进。
工具
略
开源
除了云厂商提供给的官方工具之外,在开源界也有很多相关的项目提供使用。
在 Serverless 中,开源最常见的用途是用于 FaaS 工具和框架,特别是流行的 Serverless Framework,它的目的是让使用 AWS API Gateway 和 Lambda 比使用AWS 提供的工具更容易。它还提供了大量跨供应商的工具抽象,一些用户认为这很有价值。类似工具的例子包括 Claudia 和 Zappa。另一个例子是 Apex,它特别有趣,因为它允许您用非亚马逊直接支持的语言开发 Lambda 函数。
然而,在开源工具方面,大型供应商自己并没有落后。AWS 自己的部署无服务应用程序模型(Serverless Application Model)工具也是开源的。
专有 FaaS 的主要好处之一是不必关心底层计算基础设施(机器、vm 甚至容器)。但是如果你想要关心这些事情呢?也许您有一些安全需求云供应商无法满足,或者您已经购买了一些服务器,但不想扔掉。在这些场景中,开源是否能提供帮助,允许您运行自己的“Serverful”的 FaaS 平台?
当然,这在社区是非常活跃的。开源 FaaS 的最初领导者之一是 IBM(使用 OpenWhisk,现在是 Apache 项目),这让我很惊讶——至少对我来说!——微软,该公司开放了其 Azure Functions平台的大部分源代码。许多其他自托管 FaaS 实现都使用底层容器平台,通常是 Kubernetes,出于许多原因,这很有意义。在这个领域,像 Galactic Fog、Fission 和 OpenFaaS 这样的项目值得探索。这是一个巨大的、快速发展的世界,我建议看看云原生计算联盟(Cloud Native Computing Federation(CNCF))的 Serverless Working Group 是如何做以及跟进的。
什么不是 Serverless
到目前为止,在本文中,我将 Serverless 描述为两种思想的结合:后端即服务(BaaS)和功能即服务(FaaS)。我还研究了后者的能力。关于我认为的Serverless 服务的关键属性(以及为什么我认为甚至像 S3 这样的老服务也是无服务器的),我请您参考我的另一篇文章:定义无服务器。
在我们开始研究优缺点这一非常重要的领域之前,我想再花一点时间来解释一下定义。让我们来定义什么不是 Serverless。
比较 PaaS
考虑到无服务 FaaS 功能与 Twelve-Factor 应用程序非常相似,那么它们只是像 Heroku 那样的“平台即服务”(PaaS)的另一种形式吗? 我引用 Adrian Cockcroft 的话作简短回答
如果您的 PaaS 能够在 20ms 内有效地启动实例,并且运行时间为半秒,那么就称它为 Serverless。——Adrian Cockcroft
换句话说,大多数 PaaS 应用程序并不是为了使整个应用程序上下响应一个事件而设计的,而 FaaS 平台恰恰做到了这一点。
如果我是一个优秀的 Twelve-Factor 应用程序开发人员,这并不一定会影响我如何编写和构建我的应用程序,但它确实会对我如何操作它们产生很大的影响。因为我们都是优秀的 DevOps-savvy 工程师,所以我们在考虑开发的同时也在考虑运作,对吧?
FaaS 和 PaaS 在操作上的关键区别在于可伸缩性。一般来说,对于 PaaS,您仍然需要考虑如何伸缩——例如,使用 Heroku,您想运行多少个 Dynos?对于FaaS 应用程序,这是完全透明的。即使您将 PaaS 应用程序设置为自动伸缩,也不会达到单个请求的级别(除非您有非常明确的流量配置文件),因此 FaaS 应用程序在成本方面要有效率得多。
有了上面这些好处,为什么还要使用 PaaS?有几个原因,但工具可能是最大的原因。还有一些人使用像 Cloud Foundry 这样的 PaaS 平台来提供跨混合公共和私有云的共同开发体验;在撰写本文时,还没有一个 FaaS 比得上这一点。
比较容器
使用 Serverless FaaS 的原因之一是为了避免在操作系统级别管理应用程序进程。虽然像 Heroku 这样的 PaaS 服务也提供这种功能,我已经在上面描述了 PaaS 与 Serverless FaaS 的不同之处。另一个流行的进程抽象是容器,Docker 是这种技术最明显的例子。容器托管系统(如 Mesos 和 Kubernetes)从操作系统级部署中抽象出单独的应用程序,它们越来越受欢迎。沿着这条路前进,我们会看到像 Amazon ECS 和 EKS 这样的云托管容器平台,以及谷歌容器引擎(Google Container Engine)等就像 Serverless FaaS 一样,让团队完全不必管理自己的服务器主机。考虑到容器的发展势头,是否还值得考虑 Serverless FaaS?
我对 PaaS 的主要论点原则仍然适用于容器——因为 Serverless FaaS 的伸缩是自动管理的、透明的和细粒度的,这与我前面提到的自动资源提供和分配是相关联的。容器平台传统上仍然需要您管理集群的大小和形状。
我还认为容器技术仍然不成熟和稳定,尽管它已经越来越接近成熟和稳定了。当然,这并不是说 Serverless FaaS 已经成熟,但是选择您喜欢的未完善的边界仍然是当务之急(picking which rough edges you’d like is still the order of the day)。
值得一提的是,自伸缩容器集群现在可以在容器平台中使用。Kubernetes 在“水平节点自动伸缩(Horizontal Pod Autoscaling)”中内置了这一功能,AWS Fargate 等服务也承诺提供“无服务容器”。
正如我们所看到的,Serverless FaaS 和托管容器之间的管理和伸缩性差距越来越小,它们之间的选择可能只取决于应用程序的风格和类型。例如,对于每个应用程序组件的事件类型很少的事件驱动风格,FaaS 可能是更好的选择,而对于具有许多入口点的同步请求驱动组件,容器则是更好的选择。我期望同样在相当短的时间内,许多应用程序和团队将使用这两种体系结构方法,看到这种使用模式的出现将是非常有趣的。
NoOps
Serverless 并不意味着“No Ops”——尽管它可能意味着“没有系统管理员”,这取决于你在 Serverless 的兔子洞(rabbit hole)里走了多远。
“Ops”不仅仅意味着服务器管理。它还意味着—至少—监视、部署、安全、网络、支持,以及通常一定数量的生产调试和系统扩展。这些问题在 Serverless 应用程序中仍然存在,您仍然需要一个策略来处理它们。从某种程度上说,在 Serverless 世界里,Ops 变得更难了,因为很多东西都是新的。
系统管理员仍然存在——您只是使用无服务器将其外包(outsourcing)。这并不一定是坏事(或好事)——我们外包了很多,它的好坏取决于你到底想要做什么。无论采用哪种方法,抽象在某些时候可能会泄漏,您需要知道某个地方的人工系统管理员正在支持您的应用程序。
Charity Majors 在第一次 Serverlessconf 上就这个主题做了一个很好的演讲。(你也可以阅读她的两篇评论:WTF is operations?和 Ops 最佳实践。)
存储过程即服务
// TODO
原文连接:https://martinfowler.com/articles/serverless.html