分享到

引言

无服务器(serverless)范式代表了应用程序和 Web 开发人员与基础设施、语言运行时和辅助服务交互方式的显著转变。它通过抽象化并承担传统上影响代码在生产环境中运行的许多环境因素的责任,让开发者能够自由地专注于其主要关注领域。

虽然无服务器计算具有诸多优势,但也存在一些挑战,您必须在成功之前认识或解决这些挑战。本指南将探讨当前一代解决方案的一些主要痛点,并讨论它们的含义以及如何规避它们。您将更好地理解可能需要满足哪些要求以及可能遇到的障碍。

冷启动问题

在使用无服务器技术时,最常讨论的挑战之一是冷启动(cold start)问题。虽然无服务器的目标是允许函数按需立即执行,但在某些情况下可能会导致可预测的延迟。

什么是冷启动问题?

无服务器的一大卖点是在没有活动期间能够缩减到零。如果一个函数没有被主动执行,其资源就会被关闭,将容量返回给平台,并降低用户预留这些组件的成本。从成本角度来看,这是理想的,因为它意味着用户只需为其代码实际执行的时间和资源付费。

这样做的缺点是,当资源完全关闭后,下次需要执行时会出现可预测的延迟。需要重新分配资源来运行函数,这需要时间。最终,最近使用的“热”函数有一套性能特征,而需要等待平台创建执行环境的“冷”函数则有另一套性能特征。

开发者如何尝试解决冷启动问题?

开发者和平台已经尝试了多种方法来解决这个问题。一些开发者会安排“虚拟”请求,以保持与其函数相关的资源处于待机状态。许多平台在其服务中增加了额外的层级,以允许开发者自动保持资源处于待机状态。

这些解决方案开始模糊无服务器环境的定义。当开发人员在代码未主动执行时被迫支付待机资源费用时,这引发了对无服务器范式一些基本主张的质疑。

最近一种替代预分配资源的方法是切换到更轻量级的运行时环境来规避这个问题。像 V8 这样的运行时与传统无服务器具有截然不同的执行策略,并且能够通过使用不同的隔离技术和更精简的环境来避免冷启动问题。它们避免了冷启动问题,但代价是牺牲了与依赖更强大环境的函数之间的兼容性。

应用程序设计约束

无服务器模型的一个基本挑战是它所施加的应用程序设计。无服务器平台仅适用于能在其约束条件下工作的应用程序。其中一些是云计算固有的,而其他要求则是由无服务器模型特别规定的。

设计云友好型架构

应用程序要使用无服务器平台,首先必须以云友好的方式进行设计。在本次讨论的背景下,这至少意味着应用程序必须至少部分部署到一个云服务上,以便其他组件能够与之通信。尽管在您的设计中可以实现单体函数,但无服务器模型最适合微服务架构

这样做的结果是,您的应用程序必须部分设计为由无服务器提供商执行的一系列函数。您必须能够接受处理发生在您无法控制的基础设施上。此外,您必须能够将应用程序的功能分解为可远程执行的独立函数。

处理无状态执行

无服务器函数从设计上就是无状态的。这意味着,虽然如果函数使用相同资源执行,某些信息可能会被缓存,但您不能依赖函数在不同调用之间共享任何状态。

您必须设计您的函数,使其内部拥有执行所需的所有信息。任何外部状态都必须在调用开始时获取并在结束前导出。由于函数可以并行执行,这也限制了哪些类型的状态可以合理地被操作。总的来说,您的函数需要管理的状态越少,它们的执行速度就越快,成本就越低,您需要管理的复杂性也就越少。

函数的瞬时性还会带来其他副作用。如果您的函数需要访问数据库系统,您很可能会很快耗尽数据库的连接池。由于您的函数每次调用都可以在不同的上下文中执行,数据库的连接池可能会在响应不同调用或尝试将资源返回到其池时迅速耗尽。像 Prisma Accelerate 这样的解决方案通过管理无服务器实例的连接资源来帮助缓解这些问题,无论后端是否存在连接池。

供应商锁定顾虑

无服务器技术中难以摆脱的一个挑战是供应商锁定。当您架构应用程序以依赖在特定供应商平台运行的外部函数时,将来可能很难迁移到不同的平台。

可能发生哪些类型的锁定?

对于针对特定无服务器平台构建的应用程序,许多不同的因素可能会妨碍干净地迁移到另一个提供商。这些因素可能源于无服务器实现本身,或者源于将提供商相关服务集成到应用程序设计中的使用方式。

就实际无服务器实现造成的锁定而言,提供商之间最基本的差异之一可能是定义函数所支持的语言。如果您的应用程序函数是用其他候选提供商不支持的语言编写的,那么在不使用受支持语言重新实现逻辑的情况下,迁移将是不可能的。一个更微妙的无服务器不兼容性示例是,不同提供商概念化和公开平台内函数触发机制的方式存在差异。如果这些机制显著不同,您可能需要重新定义在新平台上如何实现您的触发器。

当无服务器应用程序使用其提供商生态系统中的其他服务来支持其应用程序时,可能会发生其他类型的锁定。例如,由于无服务器函数不处理状态,因此通常会使用提供商的对象存储服务来存储调用期间产生的任何工件。虽然对象存储广泛使用标准接口实现,但它表明了无服务器架构的约束如何导致对其他可用服务生态系统的更大采用和依赖。

开发者如何尝试限制锁定

开发者可以通过一些方法来尽量减少其应用程序发生锁定的可能性或影响。

使用像 JavaScript 这样被广泛支持的语言编写函数是避免硬依赖的最简单方法之一。如果您选择的语言受到许多提供商的支持,这为您提供了其他可能能够运行您代码的平台选项。

开发者还可以尝试将服务的使用限制在那些在每个平台上几乎都以相同方式支持的通用产品。例如,我们之前使用的对象存储示例实际上是一个理想的服务示例,它很可能可以被其他提供商的产品所替代。您所依赖的服务越专业化,就越难脱离该生态系统。这是一个您必须逐案评估的权衡,因为您可能不得不放弃专用工具而选择更通用的替代品。

调试时缺乏控制和洞察力的问题

开发者在评估无服务器技术以用于未来项目时,常见的抱怨之一是无服务器平台缺乏控制和洞察力。这部分是该服务固有的,因为对运行代码的基础设施的控制,必然会使该服务不符合无服务器的类别。尽管如此,开发者通常仍然对在限制可见性和控制的环境中进行部署感到担忧,尤其是在诊断可能影响正常运行时间和生产的问题时。

开发者可以预见哪些类型的差异?

无服务器范式的承诺是将除了代码本身之外的所有责任都转移给平台提供商。这可以在运维开销和简化开发者执行环境方面带来许多优势,但它也使得开发者通常依赖的许多技术和工具变得更难或无法使用。

例如,一些开发者习惯于通过直接访问编程环境进行调试,无论是通过 SSH 连接到主机,还是通过内省代码并使用进程暴露的数据。在无服务器环境中,这通常是不可能或不容易的,因为执行环境对用户是透明的,只有像函数日志这样的特定接口可用于调试。这使得诊断问题变得困难,特别是当问题无法在本地复现或在管道中调用多个函数时。

有哪些可选方案可以提供帮助?

开发者可以采取多种不同的策略来帮助他们在这种更受限的调试环境中工作。

一些无服务器功能可以在本地运行或模拟,允许开发者在自己的机器上调试他们在提供商的生产环境中无法调试的问题。许多工具旨在模拟常见的无服务器平台,以便开发者可以重新获得他们可能缺失的一些诊断能力。它们可以让你逐步执行函数、查看状态信息和设置断点。

要在平台本身进行调试,您必须尝试利用提供商提供的所有工具。这通常意味着在您的函数中进行大量日志记录,使用 API 测试工具自动以不同输入触发函数,以及使用平台提供的任何指标来尝试深入了解执行环境中可能发生的情况。

总结

无服务器环境在开发者生产力、降低操作复杂性以及实际成本节约方面提供了巨大价值。然而,重要的是要始终认识到这种范式的局限性以及在设计应用程序以在无服务器环境中运行时可能需要解决的一些特殊挑战。

通过熟悉可能面临的不同障碍,您可以更好地做出明智的决定,了解哪些应用程序可能从当前的权衡中获益最多。您还将更好地准备好解决这些问题,更深入地了解如何通过额外的工具或设计考虑来缓解或避免它们。

关于作者
Justin Ellingwood

贾斯汀·埃林伍德

贾斯汀自 2013 年以来一直撰写关于数据库、Linux、基础设施和开发者工具的文章。他目前与妻子和两只兔子住在柏林。他通常不必以第三人称写作,这对所有相关方来说都是一种解脱。
© . All rights reserved.