本文介绍了 Serverless(无服务器)架构的六个特质(Traits):入门门槛低(Low barrier-to-entry)、无主机(Hostless)、无状态(Stateless)、弹性(Elasticity)、分布式(Distributed)和事件驱动(Event-driven)。其目的是倡导大家尽可能广泛地采用 Serverless 架构。Serverless 架构带来了一个有趣的范式转变,这使得软件开发的许多方面都变得更好了。但它也带来了技术人员必须要适应的新挑战。对于如何应对每种特质所带来的挑战,我也给出一些简短的建议,希望这些挑战不会阻止大家采用 Serverless 架构。
每当新技术出现时,技术专家的首要任务就是要理解采用新技术的意义。Serverless(无服务器)架构就是一个很好的例子。
不幸的是,目前关于 Serverless 架构的文献大多都只关注于它的优点。许多文章(以及使用示例)都是由云供应商推出的,因此,会毫不意外地谈论其积极方面。本文的意图是让大家更好地理解 Serverless 架构的特质。
我特意选了特质(Trait)这个词,而不是特性(Characteristic),因为这些是 Serverless 架构的元素,我们无法更改它们。Characteristic 特性是可塑的,而 Trait 特质是固有的。Trait 特质也是中性的,因此它既不是积极的也不是消极的。在某些情况下,我所描述的某些类型的 Trait 特质可能具有积极的含义,但我会保持中立的态度,以便你了解自己将要面对的是什么。
Trait 特质也是内在的,因此你必须要接受它们,而不是与之抗争,因为这样尝试的话可能会付出相当大的代价。另一方面, Characteristic 特性需要花费精力去塑造它们,然而你还是可能会把它们搞错。
我还应该向大家介绍 Mike Roberts 的这篇文章,他也探讨了Serverless服务的 Traits 特质。尽管我们在这里使用了相同的术语,但值得注意的是,本文所研究的是架构的 Traits 特质,而不是你所使用的服务的 Traits 特质。
本文的目的不是帮助你深入理解所有的主题,而是为你提供一个大致的概述。以下是本文中定义的 Serverless 架构的 Traits 特质:
入门门槛低(Low barrier-to-entry)
无主机(Hostless)
无状态(Stateless)
弹性(Elasticity)
分布式(Distributed)
事件驱动(Event-driven)
入门门槛低
让你的代码开始在 Serverless 架构中运行相对来说是简单的。你可以参照任何教程来开始,并让代码在生产级生态系统中运行。在许多方面,Serverless 架构的学习曲线并没有典型的DevOps 技能那么令人生畏——当你使用 Serverless 架构时,DevOps 的许多元素就都是不必要的了。例如,你不必学习服务器管理技能,如配置管理或补丁。这就是为什么入门门槛低是 Serverless 架构的 Traits 特质之一。
这意味着,最初开发人员的学习曲线比许多其他架构风格的曲线都要低。但这并不意味着学习曲线会一直保持在较低的水平,事实上,随着开发人员继续他们的旅程,整体学习曲线将会变得更陡峭。
由于这种架构特质,我看到许多新的开发人员很快就加入到了项目中,并且他们能够有效地为项目做出贡献。开发人员能够快速上手,这可能是 Serverless 项目能更快上手的原因之一。
正如我们所指出的那样,事情确实会变得更加复杂。例如,基础设施即代码(Infrastructure as a code,Iac)、日志管理、监控,有时还包括网络,这些仍然都是必不可少的。你必须要了解如何在 Serverless 的世界中实现它们。如果你来自不同的开发背景,那么你需要了解一些 Serverless 架构的 Traits 特质(本文将介绍这些 Traits 特质)。
尽管最初的入门门槛很低,但开发人员不应该认为他们可以忽略重要的架构原则。
我注意到,一些开发人员倾向于认为 Serverless 架构意味着他们不必考虑代码设计。理由是他们只是在处理函数,所以代码设计是无关紧要的。事实上,像 SOLID 这样的设计原则仍然适用——你不能将代码的可维护性外包给你的 Serverless 平台。尽管你可以将代码打包并上传到云上运行,但我强烈建议你不要这样做,因为持续交付实践在 Serverless 架构中仍然是相关的。
无主机
Serverless 架构的一个明显特质是,你无需直接处理服务器。在这个时代,你可以在各种各样的主机上安装并运行服务——无论是物理机、虚拟机、容器等等——用一个词来描述这一点是很有用的。为了避免使用已经使用过的术语“无服务器”(“serverless”),我将在这里使用“主机”(“host”,术语“主机”在《构建微服务》一书中使用过)这个词,因此该 Trait 特质名为“无主机”(Hostless)。
无主机的一个优势是,你在服务器维护方面的操作开销将会大大减少。你无需再为升级服务器而忧心,安全补丁将自动为你执行。无主机还意味着在应用程序中你需要监控的度量指标也会不同。这是因为你使用的大多数底层服务不会再发布 CPU、内存、磁盘大小等传统度量指标了。这意味着你不再需要理解架构的低级操作细节。
但不同的监控指标意味着,你必须重新学习如何调整你的架构。AWS DynamoDB 提供了可以供你进行监控和调控的读写能力,这是一个你必须要了解的概念,而且这种学习是不能迁移到其他 Serverless 平台的。你使用的每项服务都有其局限性。AWS Lambda 具有并发执行的限制,你所拥有的 CPU 核数不存在限制。更奇怪的是,更改 Lambda 的内存分配大小将会更改获得的 CPU 核数。如果你为了性能测试和生产环境共享一个 AWS 帐户,那么如果性能测试意外地消耗了你的全部并发执行限制,可能会导致生产的宕机。AWS 很好地记录了每项服务的限制,因此请务必检查它们,以便做出正确的架构决策。
一个常见的误解是,Serverless 应用程序更安全,因为安全补丁会自动应用于你的底层服务器。这个假设很危险。
由于 Serverless 架构具有不同的攻击向量,传统的安全防护已不再适用。应用程序的安全实践仍然适用,并且在代码中存储秘密仍然是一个很大的禁忌。AWS 在其责任共担模式中概述了这一点,例如,如果数据包含敏感信息,你仍然需要保护数据。我强烈建议你阅读10 大 OWASP Serverless 项目以获得更多有关该主题的见解。
虽然你的运维操作开销大大减少了,但值得注意的是,在极少数情况下,你仍然需要管理底层服务器更改后的影响。你的应用程序可能依赖于原生库,并且你需要确保在升级基础操作系统时它们仍可以工作。例如,在 AWS Lambda 中,操作系统最近已升级到了 AMI 2018.03。
无状态
函数即服务,即 FaaS,是很短暂的,因此你不能在内存中存储任何内容,因为运行代码的计算容器将由平台自动创建和销毁。因此,无状态(Stateless)是 Serverless 架构中的一个 Trait 特质。
无状态是水平扩展应用程序的一个很好的特质。无状态的概念是鼓励你在应用程序中不要存储状态。通过不在应用程序中存储状态,你将能够启动更多的实例,而无需担心应用程序的状态,从而实现水平扩展。我在这里发现了一个有趣的点,实际上无状态是被迫的,因此错误的空间大大减少了。是的,这里有一些注意事项:例如,计算容器可能会被重复使用,你可以存储状态,但是如果你采用这种方法,请务必谨慎处理。
就应用程序开发而言,你将无法使用需要状态的技术,因为状态管理的负担是强加给调用方的。例如,不能使用 HTTP 会话,因为你没有具有持久化文件存储的传统 Web 服务器。如果你想使用 WebSockets 等需要状态的技术,那么你需要等待,等到相应的后端即服务(BaaS)支持这些技术为止,或者应用你自己的解决方案。
弹性
由于你的架构是无主机的,那么你的架构也将具有弹性的特质。 你使用的大多数 Serverless 服务都被设计为具有高弹性,你可以从零扩展到允许的最大值,然后再回到零,大部分是自动管理的。 弹性是 Serverless 架构的一个 Trait 特质。
对于可扩展性来说,弹性的好处是巨大的。这意味着你不必手动管理资源扩展。资源分配的许多挑战都消失了。在某些情况下,具有弹性可能只意味着你只需为所使用的内容付费,因此,如果你的使用模式较低,则可以降低运行成本。
你可能需要将 Serverless 架构与不支持这种弹性的遗留系统集成。当这种情况发生时,你可能会破坏下游系统,因为它们可能无法像 Serverless 架构那样扩展。如果你的下游系统是关键系统,那么考虑如何缓解此问题是至关重要的——可能是通过限制 AWS Lambda 的并发性或利用队列与下游系统对话。
虽然在这种高弹性的情况下,“拒绝服务”攻击(denial of service,DOS)将会变得更加困难,反而更容易受到“拒绝钱包”(denial of wallet)攻击。在这种情况下,攻击者试图通过强制增加资源分配来迫使你超出云帐户的限制,从而破坏应用程序。为了防止这种攻击,你可能会发现在你的应用程序中使用 DDoS 保护(如 AWS Shield)是很有帮助的。在 AWS 中,设置 AWS 预算也很有用,这样当你的云账单暴涨时,你就会收到通知。如果高弹性不是你所期望的,那么在应用程序上设置约束是很有用的,比如通过限制 AWS Lambda 并发性。
分布式
由于无状态计算是一种特质,所有的持久性需求都将存储在后端即服务(BaaS)中,通常是 BaaS 的组合中。一旦你更多地使用 FaaS,你还会发现你的部署单元(即函数)比你已习惯了的可能还要小。因此,在默认情况下,Serverless 架构是分布式的,并且有许多组件必须要通过网络来进行集成。你的架构还将包括将服务连接在一起,比如身份验证、数据库、分布式队列等。
分布式系统有很多好处,比如我们前面讨论过的弹性。在默认情况下,分布式还能为你的架构带来了单区域的高可用性。在 Serverless 环境中,当云供应商所在区域的某个可用性区域出现故障时,你的架构将能够利用其他仍在运行的可用性区域——从开发人员的角度来看,所有这些都是不透明的。
在选择架构时总要权衡利弊。在这个特质中,你牺牲了一致性来换取可用性。通常在云上,每个 Serverless 服务也都有自己的一致性模型。例如,在 AWS S3 中,通过在 S3 桶中对新对象的 PUT 操作可以获得“写后读”(read-after-write)的一致性。对于对象更新,S3 是最终一致的。对于你来说,决定使用哪种 BaaS 是很常见的,因此要注意它们的一致性模型的行为。
另一个挑战是你需要熟悉分布式消息的传递方法。例如,你需要熟悉并了解精确一次投递(exactly-once delivery)这一难题,因为分布式队列的常见消息投递方式是至少一次投递(at-least-once-delivery)。由于这种投递方式,AWS Lambda 可以被多次调用,因此你必须确保你的实现是幂等的(了解 FaaS 的重试行为也很重要,其中 AWS Lambda 可能会在失败时多次执行)。你需要了解的其他挑战还包括分布式事务的行为。然而,随着微服务的普及,构建分布式系统的学习资源一直在演进。
事件驱动
Serverless 平台提供的许多 BaaS 自然会支持事件。对于第三方服务来说,这是一个很好的策略,它们可以为其用户提供可扩展性,因为你无法控制他们服务的代码。由于你将在 Serverless 架构中使用大量的 BaaS,因此你的架构是具有事件驱动这一 Trait 特质的。
我还认识到,即使你的架构是具有事件驱动这一 Trait 特质的,但这并不意味着你需要完全采用事件驱动的架构。然而,我观察到,当将事件驱动架构自然地提供给团队时,团队更倾向于接受它。这个特质和弹性特质类似,不需要时,你仍然可以关闭它。
事件驱动能带来很多好处。架构组件之间的耦合程度很低。在 Serverless 架构中,你可以很容易地引入一个新函数来监听 blob 存储中的更改:
注意,当添加函数 B 时,函数 A 并没有改变(参见上图)。这增加了函数的内聚性。函数具有高内聚是有很多好处的,其中一个好处是当单个操作失败时,你可以轻松地重试该操作。当函数 B 失败重试时,意味着你不需要运行高昂的函数 A。
特别是在云计算中,云供应商将确保你的 FaaS 与他们的 BaaS 能够轻松集成。FaaS 可以被设计成由事件通知触发。
事件驱动架构的缺点是,开始时你可能会失去系统作为一个整体的整体视图。这会使得对系统进行故障排除变得更具挑战性。分布式跟踪是你应该研究的一个领域,尽管它在 Serverless 架构中仍然是一个成熟的领域。AWS X-Ray 是一种可以在 AWS 中开箱即用的服务。X-Ray 确实有其自身的局限性,如果你已经超越了它,你应该关注这个领域,因为有第三方的产品正在涌现。这就是为什么记录关联 ID(Correlation IDs)的实践是必不可少的,特别是在事务中使用多个 BaaS 的情况下。所以一定要确保实现关联 ID。
结论
本文介绍了 Serverless 架构的六个 Traits 特质:入门门槛低、无主机、无状态、弹性、分布式和事件驱动。我的目的是倡导大家尽可能广泛地采用 Serverless 架构。Serverless 架构带来了一个有趣的范式转变,这使得软件开发的许多方面都变得更好了。但它也带来了技术人员必须要适应的新挑战。对于如何应对每种 Trait 特质所带来的挑战,我也给出一些简短的建议,希望这些挑战不会阻止你采用 Serverless 架构。
原文链接:
https://www.thoughtworks.com/insights/blog/traits-serverless-architecture
评论