彼得·萨巴斯基和萨姆·克鲁内伯格合著的《走无服务器道路》(GoServerless)一书。
如果你问软件开发人员何谓软件架构,可能会得到五花八门的答案:软件架构“是蓝图或计划”、“概念模型”或“大局”,不一而足。毫无疑问,架构或缺少架构关系到软件的成败。良好的架构有助于扩展Web或移动应用程序,而糟糕的架构可能导致严重问题,势必需要重写、花费高昂成本。了解架构方面的选择带来的影响,并且能够提前规划,这对于构建高效、高性能、最终成功的软件系统来说极为重要。
这篇文章阐述了为什么我们认为,无服务器架构对软件开发人员和解决方案架构师来说是改变行业规则的技术。它介绍了AWSLambda之类的关键服务,还介绍了无服务器架构的几个原则,帮助你了解什么造就真正的无服务器系统。
名称中有什么?
在我们开始探讨正文之前,应该提到无服务器这个词有点用词不当。无论你使用AWSLambda之类的计算服务来执行代码还是与API进行交互,仍然有服务器在后台运行。区别在于,这些服务器隐藏起来,我们是看不见的。我们不需要考虑基础设施,也无法调整/改动底层操作系统。别人负责基础设施管理的基本细节,那样我们可以腾出时间处理其他事情。无服务器技术是指,在计算服务中运行代码,并与服务和API进行交互,以完成任务。
我们如何走到今天这一步?
如果你看一看支持如今大多数具有Web功能的软件的系统,就会发现后端服务器执行各种各样的计算任务,而客户端前端为用户提供界面,以便通过浏览器、移动设备或桌面设备进行操作。
在一个典型的Web应用程序中,服务器接受来自前端的HTTP请求,处理请求。数据在保存到数据库之前可能经过无数个应用层次。最后,后端生成响应――可能采用JSON或完全呈现的标记这种形式,响应被发回给客户端(图1)。当然,一旦将其他元素考虑进来,比如负载均衡、事务、集群、缓存、消息传递和数据冗余,大多数系统比较复杂。大多数这种软件需要服务器在数据中心或在云端运行,这些服务器需要加以管理、维护、打补丁和备份起来。
图1:这是一种基本的请求/响应(客户端/服务器)消息交换模式,大多数开发人员对此很熟悉。该图中只有一台Web服务器和一个数据库。大多数系统要复杂得多。
服务器的配置、管理和打补丁是一项很耗费时间的任务,常常需要专门的操作人员。很难搭建并高效地运行一个重大的环境。基础设施和硬件是任何IT系统的必要组成部分,但它们也常常让人容易分心,忽视最重要的事情:解决业务问题。
过去这几年出现了平台即服务(PaaS)和容器等技术,这些解决方案有望解决这个头痛的问题:基础设施环境不一致、冲突和服务器管理开销。PaaS是一种云计算,它为用户提供了运行软件的平台,同时把一部分底层基础设施隐藏起来。为了有效地使用PaaS,开发人员需要编写针对该平台相应功能特性的软件。由于大多数PaaS实现方法具有短暂性,把当初被设计成在独立服务器上运行的老式应用程序迁移到PaaS服务,需要额外的开发工作。不过,如果面临选择,许多开发人员会决定使用PaaS,而不是更传统、更手动化的解决方案,那是由于PaaS减少了维护和平台支持方面的要求,这可以理解。
容器化是一种隔离应用程序的方法,让应用程序有自己的环境。这种轻量级方法可替代全面的虚拟化。容器是孤立的、轻量级的,但它们需要部署到服务器上,无论在公共云上、在私有云中还是在现场。如果依赖关系明确,容器是一种出色的解决方案,不过它们在内务处理(housekeeping)方面有各自的挑战和复杂性。它们并不是与仅仅能够直接在云端运行代码来得一样容易。
最后,我们迎来了Lambda,这是亚马逊网络服务(AWS)提供的一种计算服务。Lambda能够以一种大规模并行方式执行代码,以响应事件。Lambda拿来你的代码后即可运行,根本不需要配置服务器、安装软件、部署容器,或者是为低层细节而操心。AWS负责配置和管理运行实际代码的弹性计算云(EC2)服务器,并提供开发人员不需要考虑的一套高可用性计算基础设施,包括容量配置和自动扩展机制。无服务器架构这个词是指这些新型的软件架构:不需要直接访问服务器就能运行。通过采用Lambda,并充分利用各种功能强大的单一用途的API和Web服务,开发人员就可以迅速构建松散耦合、可扩展、高效的架构。无服务器架构的最终目的就是,远离服务器和基础设施方面的问题,让开发人员可以主要专注于代码。
面向服务的架构和微服务
在许多不同的系统和应用程序架构当中,面向服务的架构(SOA)在软件开发人员当中具有很高的知名度。这种架构清楚地使这个想法概念化:系统可以由许多独立的服务组成。SOA方面的文章已写了不少,可是由于开发人员常常把设计理念与具体的实施和属性混为一谈,所以它仍存在争议和误解。
SOA没有硬性规定使用任何特定的技术。相反,它鼓励这样一种架构方法:开发人员创建自治服务,这些服务通过消息传递来进行联系,常常有一种模式(schema)或契约(contract),定义了消息是如何创建或交换的。服务的可重用性、自主性、可组合性、细粒度和可发现性,这些都是与SOA有关的重要原则。
微服务和无服务器架构在核心思想上与面向服务的架构一脉相承。它们保留了许多上述原则和理念,同时试图消除老式的面向服务架构具有的复杂性。
最近出现的一股趋势是,使用微服务架构来实施系统。开发人员往往把微服务考虑成小型、单独、完全独立的服务,它们围绕一个特定的业务用途或功能而建。微服务可能有一个应用程序层,有自己的API和数据库。
理想情况下,微服务应该易于替换,每个服务用一种适当的框架和语言编写而成。微服务可以用不同的通用语言或特定领域语言(DSL)来编写,光这一点就让许多开发人员为之着迷。虽然可以通过使用合适的语言或针对相应任务的一套专用库来获得一些好处,但这也常常是个陷阱。如果拥有多种语言和框架,支持起来有难度;要是没有一套严格的准则,会在将来导致混淆和困难。
每个微服务可能保持其状态、存储数据,这增加了系统的复杂性。一致性和协调性管理也可能成为一个问题,因为状态必须常常跨不同的服务来加以同步。微服务可以通过消息总线间接联系,也可以通过将消息发给对方来直接联系。
可以说,无服务器架构同样体现了来自微服务的许多原则。毕竟,每个计算函数都可以被认为是其自己的独立服务,这取决于你如何设计系统。然而,你不需要完全接受微服务口号,就可以围绕某个特定的业务用途来开发每个函数或服务,保持状态,等等。
无服务器架构的好处在于,你想运用几个微服务原则,就可以随意运用几个,不会迫使你只有华山一条道。
软件设计
软件设计已从昔日代码在大型机上运行,变成如今在多层系统上运行:在许多设计中,表示层、数据层和应用/逻辑层具有重要地位。在每层里面,可能有多个逻辑层次处理某一功能或领域的特定方面。还有可能跨众多层次的横切组件(cross-cuttingcomponent),比如日志或异常处理系统。青睐分层可以理解。分层让开发人员得以将关注点分离开来,开发出更易维护的应用程序。
但是,反过来也可能如此。层次太多可能导致效率低下。一个小小的变化常常带来连锁反应,导致开发人员修改整个系统中的每个层次,把大量的时间和精力花费在实施和测试上。层次数量越多,久而久之系统会变得越复杂、越笨拙。图2显示了具有多个层次的分层架构的一个例子。
图2:一个典型的三层应用程序通常由表示层、应用层和数据层组成。在每个层中,可能有多个层次,它们有特定的职责。开发人员可以选择各层次彼此如何联系。这可以是严格的自上而下的方式,也可以是一种松散的方式:各层次可以绕过紧邻的层次,与其他层次对话。层次的联系方式将影响性能、依赖项管理和应用程序的复杂性。然后还有横跨多个层次的功能――这叫作横切关注点(cross-cuttingconcern)。
无服务器架构实际上有助于解决分层、非得更新太多对象这一问题。开发人员有机会消除或尽量减少层次,只要将系统分成多个功能,让前端得以安全地与服务、甚至数据库直接进行通信,如图3所示。这一切都可以以一种有组织的方式来实现,可以清楚地定义服务边界,防止意大利面条式实施和依赖项恶梦,让Lambda函数成为自治式,并且规划函数和服务如何交互。
图3:在无服务器架构中,没有单一的传统后端。通过API网关,应用程序的前端直接与服务、数据库或计算函数进行联系。然而,有些服务必须隐藏在计算服务函数后面,额外的安全措施和验证可能在这里进行。
无服务器方法解决不了所有问题,也无法消除系统的底层复杂性。然而,如果实施得当,它还是可以为减少、厘清和管理复杂性带来机会。精心规划的无服务器架构可以让开发人员更容易在将来做出变化,这对任何长期的应用程序来说都是一个重要因素。下一节将更详细地讨论服务的组织和编排。
层vs层次
一些开发人员对于层次(layer)与层(tier)之间的区别分不太清楚。层是一种模块边界,它是为了隔离系统的主要组件而存在的。用户看得见的表示层与包括业务逻辑的应用层分开来。反过来,数据层是另一个独立的系统,负责数据的管理、持久化和访问。分组在一个层中的组件可能实际上驻留在不同的基础设施上。
层次是逻辑片段,负责执行应用程序中特定的职责。每一层在里面可能有多个层次,负责功能的不同部分,比如域服务。
无服务器架构的原则
无服务器架构有五大原则,描述了一个理想的无服务器系统应该如何构建。你在构建无服务器架构时,可以运用这些原则,帮助指导你做出决定。
1.根据需要,使用计算服务来执行代码(没有服务器)。
2.编写单一用途的无状态函数。
3.设计基于推送的、事件驱动的管道。
4.创建更粗实、更强大的前端。
5.拥抱第三方服务。
不妨更详细地分析这每一个原则。
根据需要,使用计算服务执行代码
无服务器架构是SOA概念的自然延伸。在无服务器架构中,所有自定义代码作为孤立的、独立的、常常细粒度的函数来编写和执行,这些函数在AWSLambda之类的无状态计算服务中运行。开发人员可以编写函数,执行几乎任何常见的任务,比如读取和写入到数据源、调用函数以及执行计算。在比较复杂的情况下,开发人员可以构建更复杂的管道,编排多个函数的调用。可能会有这种场景:仍需要服务器来处理某个任务。然而,这种情况并不多见;作为开发人员,你应该尽量避免运行服务器、与之交互。
那么,Lambda究竟是什么?
Lambda是一种计算服务,它在AWS基础设施上执行用用JavaScript(node.js)、Python或Java编写的代码。源代码部署到孤立的容器上,该容器有单独分配的内存、磁盘空间和处理器。代码、配置和依赖项这一组合通常被称为Lambda函数。Lambda运行时环境可以并行多次调用某个函数。Lambda支持推拉事件操作模式,并与数量众多的AWS服务整合起来。函数可以通过API网关由HTTP请求来调用,也可以按时间表来运行。请注意:Lambda并不是市面上唯一的计算服务。微软Azure函数(MicrosoftAzureFunctions)、IBMBluemixOpenWhisk和谷歌云函数(GoogleCloudFunctions)是你可能应该关注的其他计算服务。
编写单一用途的无状态函数
作为软件工程师,你在设计函数时应该尽量着眼于单一职责原则(SRP)。单单处理某一项任务的函数更容易测试、运行稳定,而且带来的错误和意外的副作用比较少。通过以一种松散编排的方式将函数和服务组合起来,你就能构建照样易于理解、易于管理的复杂后端系统。拥有明确定义的接口的细粒度函数也更有可能在无服务器架构里面被重复使用。
为Lambda等计算服务编写的代码应该以无状态方式来构建。它不得假设:本地资源或进程会在当前的会话之后生存下去。无状态性功能很强大,因为它让平台得以迅速扩展,以处理数量不断变化的入站事件或请求。
设计基于推送的、事件驱动的管道
可以构建满足任何用途的无服务器架构。系统可以一开始就构建成无服务器,也可以逐步重新设计现有的整体单一式应用程序,以便充分发挥这种架构的优势。最灵活、最强大的无服务器设计是事件驱动型的。图4显示了我们如何将亚马逊的简单存储服务(S3)、Lambda和ElasticTranscoder连接起来,构建一条事件驱动的、基于推送的管道。
构建事件驱动的、基于推送的系统常常有望降低成本和复杂性(你不需要运行额外代码来轮询变更),可能让整个用户体验更流畅。不言而喻,虽然事件驱动的、基于推送的模式是个美好的目标,但它们并非在所有情况下都是适当的或可以实现的。有时候,你不得不实施一个Lambda函数来轮询事件源或按时间表运行。
图4:基于推送的管道这种设计风格与无服务器架构非常搭配。在这个例子中,用户上传一段转码成不同格式的视频。上传创建了一个事件,从而触发了Lambda函数。该函数创建一个转码作业。转码作业提交给转码视频服务,新的视频创建后,被保存到另一个S3存储桶。保存新视频这个过程触发了另一个Lambda函数,该函数反过来更新数据库。数据库中一个新的条目触发了最后一个函数,该函数创建通知,并调用通知服务,实现调派。在这个例子中,所有函数和服务仅仅负责一个动作,整个编排易于调整。
创建更粗实、更强大的前端
有必要记住这一点,在Lambda中运行的自定义代码应该快速执行。较早终结的函数较便宜,因为Lambda定价基于请求数量、执行时间段以及分配的内存量。在Lambda中要处理的事务比较少来得比较省钱。此外,拥有调用服务的更丰富的前端有利于更好的用户体验。在线资源之间更少的环节和缩短的延迟会让人觉得应用程序的性能和可用性更好。
数字签名的令牌让前端可以与不同的服务(包括数据库)直接进行通信。相比之下,在传统系统中,所有通信经由后端服务器来进行实现。让前端与服务进行通信有助于创建环节少得多、尽快获得所需资源的系统。
然而,不是一切都可以或者都应该在前端执行。有些秘密无法交给客户端设备。处理信用卡或向订户发送电子邮件只能由不受最终用户控制的服务来完成。在这种情况下,就需要计算服务来协调动作、验证数据,并实施安全。
另外要考虑的重要一点是一致性。如果前端负责写入到多个服务,可是中途出现故障,就会导致系统处于不一致的状态。在这种情况下,应该使用Lambda函数,因为它可以旨在从容地处理错误,重新尝试失败的操作。原子性和一致性在Lambda函数中实现起来和控制起来比在前端中容易得多。
拥抱第三方服务
如果第三方服务能提供价值、减少自定义代码,自然欢迎它们加入。如今,开发人员可以充分利用许多服务,从用于验证的Auth0服务,到用于支付处理的Stripe或Braintree服务,不一而足。只要考虑到价格、性能和可用性等因素,开发人员就应该试着采用第三方服务。开发人员花时间解决其领域独有的问题要比重复构建别人已经实施的功能有意义得多。如果已有了切实可行的第三方服务和API,别纯粹为了构建而构建。应站在巨人的肩上达到新的高度。
结束语
对IT基础设施和软件开发而言,云计算一向是改变行业规则的技术,现在也是如此。软件开发人员需要认真考虑他们最大限度地利用云平台的方式,以获得竞争优势。
无服务器架构是开发人员和企业组织需要考虑、研究和采用的最新进展。这是架构领域出现的一种激动人心的新变化,随着开发人员积极采用AWSLambda等计算服务,这种架构会迅速发展起来。如今,一些无服务器应用程序支持成千上万个用户,并执行复杂的操作,包括处理繁重任务,比如视频编辑和数据处理。在许多情况下,无服务器架构可获得比传统模式更好的效果,而且实施起来成本更低、速度更快。
还需要降低与运行基础设施,对传统软件系统进行开发有关的复杂性和成本。减少花在基础设施维护上的时间和成本,加上可扩展性带来的好处,这些是企业组织和开发人员考虑无服务器架构的充分理由。在今后几年,无服务器后端的发展步伐可能只会加快。
推荐: