如何将单体架构转变为无服务器架构

2025-06-09

如何将单体架构转变为无服务器架构

无服务器技术的受众群体日益壮大,许多人渴望利用其带来的优势。市面上有很多关于无服务器技术的资源,但它们往往侧重于如何入门。它们往往侧重于如何使用无服务器架构构建全新的应用。

但是,这种方法缺少了更广泛的受众。那些现有代码库难以迁移到无服务器架构的人。他们通常背负着巨额的技术债务。这使得无服务器架构看起来只不过是一个幻想。

因此,在这篇文章中,我想重点介绍整体应用程序如何随着时间的推移转变为无服务器应用程序。

我们已经知道,任何全新的应用都可以使用无服务器架构构建。但是,如何将现有的应用或服务变成无服务器架构呢?最简单的答案是重写。但从开发角度来看,这成本很高,而且取决于需要重写的内容。

在开始重写代码库之前,我建议大家先暂停一下。我们先来思考一下如何将现有应用程序的组件迁移到无服务器架构。通过这个过程,我们或许可以发现哪些方面进展顺利,以及可能遇到的痛点。一旦搞清楚了这两个问题,我们就可以制定一个计划,将我们的遗留应用程序(至少是其中的一部分)迁移到无服务器架构。

关于无服务器的思考

关于无服务器,存在着良性争论。它的优点、缺点,甚至它的定义都有待商榷。这篇文章我无意再次讨论这些话题。但我确实认为,分享一个与我产生共鸣的定义是有价值的。

无服务器是一种云优先架构,让我可以专注于向最终用户交付代码。无需配置、维护、修补和规划底层服务器的容量。支持各种规模工作负载的规模和可用性由云提供商负责。

在理想情况下,无服务器让我无需再处理代码运行的服务器。有了这种自由,我可以专注于为最终用户提供价值的代码。在我看来,这就是无服务器的核心。这有时是否有些理想化?是的,作为开发者,维护服务器并非我们唯一需要做的与代码无关的事情。但为了实现这一目标,我们仍然值得努力。

因此,当我考虑将现有服务迁移到无服务器架构时,我会强迫自己考虑成本和回报。就像你做出的任何其他架构技术债务决策一样。事实上,做出技术债务决策充满挑战。衡量每一项决策的成本和回报非常复杂,并非易事,而且很难做到完美。

因此,当我们探索将遗留代码迁移到无服务器架构时,我们应该承认这是一个非常难以解决的问题。它有很多解决方案,有些比其他方案更好,有些甚至不值得一试。但至少让我们探索一下如何从大型单体应用迁移到无服务器架构。

第一步:立足现实

首先,让我们先把这个放出来:

$ echo 'Not everything fits into the serverless model.'
Enter fullscreen mode Exit fullscreen mode

当你考虑无服务器架构时,这一点从一开始就很重要。它并非适用于所有情况,至少目前如此。

话虽如此,它确实适用于很多事情,其中​​一些事情对你来说可能并不直观或自然。请记住,这与我们今天许多人使用的范式不同。但它与我们现有的应用程序编写方式并没有太大区别。

在考虑投入精力将现有架构转型为无服务器架构时,务必立足现实。明确阐述你认为迁移到无服务器架构对你的应用程序或服务而言是最佳选择的理由。如果你无法迈过这个阶段,就应该重新评估你即将踏上的道路。

这些原因对于您和您的工作负载来说都是独一无二的。所以,请思考一下您希望通过迁移到无服务器架构获得什么。您的驱动因素可能是成本,您不想为每天 1-2 小时的流量而全天候运行的服务器付费。也可能是规模。您希望获得可扩展性,而无需对底层基础设施负责。

无论你迁移到无服务器的原因是什么,务必确认其重要性与你预期的一致。接下来的每一步都将是一个挑战,并将考验你对这一旅程的理性判断。

一旦我们明确了我们想要实现的现实目标,就该开始评估我们的申请了。

步骤 2:区分动产和不动产

乐趣就从这里开始。现在是时候看看你的应用程序中哪些部分可以立即迁移到无服务器,哪些部分你认为不能。

这里没必要想太多。在你的单体应用中,那些很容易移动的东西往往会突然出现。而那些一开始就看起来很困难的东西,最好暂时搁置。

在此阶段,考虑无服务器架构内部存在的约束通常会有所帮助。

  • 根据您的无服务器云提供商,单个函数的执行时间可能为 1-15 分钟。它需要启动、完成必要的工作,然后退出。此时间限制是可配置的,因此请确认您认为完成工作需要多长时间,并将时间限制设置为该时间。
  • 冷启动延迟是真实存在的。根据您的用例,您可能会注意到无服务器函数首次调用时存在相当长的延迟。造成这种情况的因素有很多,您可以采取很多措施来减少延迟。
  • 磁盘大小限制是另一件需要注意的事情。在无服务器函数内部,通常没有 GB 的存储空间可供使用。但是,tmp如果需要,通常可以使用某种类型的临时存储空间。
  • 内存也受到限制,根据云提供商的不同,最多可以使用 3GB 内存。与这里列出的其他限制相比,这个限制通常较小,但仍然需要牢记。

当我们考虑单体应用的哪些部分可以移动、哪些部分不能移动时,这些核心约束至关重要。此外,部署规模、负载大小、环境变量和文件描述符方面也存在其他约束。但这些约束仅适用于少数工作负载,对您来说可能并不那么重要。

需要注意的是,这些限制是可以规避的。但是,当你踏上这段旅程时,应该暂时避免这些工作负载。当你是新手时,它们很容易失控。我可以向你保证,还有其他工作负载在初期更容易过渡。

以下是我认为可以立即迁移的一些高级内容。注意:此处提到的服务特定于 Amazon Web Services,但 AWS 之外也存在适用的服务。

CRON 作业

CRON 作业是一个很好的起点,只要它们符合上述限制条件。这些作业通常是我们每个人都在运行的自动化进程,通常用于执行一些日常任务。如果幸运的话,它们会在自己的实例上运行,这意味着当你将它们迁移到无服务器环境时,你可以终止一个实例 💀

这些作业通常也位于应用程序或服务的主要开发流程之外。这意味着错误的爆发半径可能较小。因此,CRON 作业是开启无服务器之旅的理想之选。您可以借此熟悉该范式,汲取一些经验教训,获得一些价值,并且希望不会打扰您的用户。

“粘合”服务

我确信肯定有比“粘合剂”更专业的术语,但让我先解释一下我理解的这些服务是什么。首先,这里的“服务”是一个宽泛的定义。它可以是在其自身实例上运行的独立服务,也可以是单体应用内部的服务层。

粘合服务是指充当一个或多个其他服务之间中介的服务。换句话说,它将两个服务粘合在一起。这些服务通常会在服务之间进行转换或消息传递。因此,只要是无状态的,这类工作负载就能很好地融入无服务器架构。

将这些类型的服务迁移到无服务器架构意味着您需要仔细考虑它们的契约。这些工作负载如何接收输入以及如何传递输出?如果您已经使用 HTTP,则可以通过 API 网关接收输入。或者,如果您的客户端服务只想发送消息,则输入可以来自 SNS 主题。

这些“粘合剂”服务通常可以直接融入无服务器架构,但需要注意的是,它们不保存状态。在无服务器的世界中,状态可能很棘手。这是因为计算能力是短暂的,甚至比虚拟机更短暂,所以你必须牢记这一点。这并非一个无法解决的问题,但它可能会暂时将某些东西从“可移动”状态转变为“暂缓”。

电子邮件服务

许多应用程序都包含向用户发送电子邮件的代码或服务。根据这些功能在代码库中的复杂程度,将其分离出来并实现无服务器化可能是个不错的选择。与 CRON 任务类似,这些服务可能在后台运行,因此不面向用户。如果我们无法发送邮件,它们可能会对用户造成影响,但这并非坏事,用户体验不应与邮件的实际发送直接相关。

发送电子邮件的实现在不同类型的用例中差异很大。一般来说,它们往往遵循如下流程:

  • 用户完成某些操作或他们希望收到某事发生的通知。
  • 通常有一个电子邮件模板用于用户需要了解的已发生的事件。
  • 该电子邮件是通过模板和事件详细信息生成的。
  • 然后将电子邮件发送给用户。

根据您的使用情况,这里可能有更多或更少的步骤,但这是一个一般的逻辑流程。

此流程适用于无服务器架构。如果幸运的话,你的电子邮件传递可能已经从单体应用中分离出来了。在这种情况下,你可以将逻辑移至无服务器架构,更改服务向其传递消息的方式,这样就差不多完成了。如果你的电子邮件传递功能与你的应用程序集成在一起,则需要先进行解耦,然后再考虑将其变为无服务器架构。

这些是一些适用于无服务器架构的高级理念。这并非详尽的清单,因为这取决于您自己的工作负载和需求。但是,我们可以总结一下,可移动的事物通常都满足这三个要求。

  1. 一般来说,不要面向客户。虽然这不是硬性规定,但迁移到无服务器的第一步通常不会面向客户。背后的原因各不相同,但对我来说,关键在于学习这种新模式的同时,不要扰乱用户的工作流。
  2. 不与任何同步 API 耦合。初次迁移到无服务器时,解耦和异步程度越高越好。为什么?因为这正是该架构蓬勃发展的地方。通过保持异步和分布式,我们可以独立扩展工作负载。
  3. 目标是工作负载或服务具有清晰的边界。我意识到,对于大型应用程序来说,这可能是一个真正的挑战。然而,你越能为给定服务定义清晰的边界,迁移到无服务器架构就越容易。道理很简单,清晰的边界定义了清晰的契约。如果我们迁移某个服务时,契约不清晰或变得混乱,最终可能会产生分布式技术债务,而不是单体架构。

现在我们已经掌握了定义可移动服务的原则。接下来,让我们开始思考如何实际移动它们,以及可以使用哪些工具。

步骤 3:移动可移动物

现在我们已经将服务分为两类:可移动的和不可移动的(至少目前如此)。我们可以开始思考如何真正实现这种移动。

这是一个可变的步骤,取决于你自己的代码库。有些东西你可能决定重写,以充分利用无服务器范式。其他东西你可能可以“移植”到无服务器环境中,因为它非常适合。或者,有些东西你开始迁移,却发现无法迁移。

这三种情况都是可行的。但更值得关注的是前两种情况,因为它们是“前进”的阶段。

考虑到这一点,让我们思考一下何时可能会发生重写。

对于任何这些高级场景,可能都需要将现有服务重写为无服务器服务。

  • 该语言/框架无法在无服务器环境中运行。该服务可能是用 Cobol 编写的,使用了 Spring Boot,或者大量使用了原生二进制文件。这个问题曾经很常见,但随着AWS Lambda Layers的推出,这个问题实际上已经不那么严重了。
  • 服务与单体应用紧密耦合。这是我在旧代码库中经常看到的常见场景。我们想移除该服务,但可能需要扼杀旧服务并构建一个新的。即使你未来不打算使用无服务器架构,也可以参考Strangler 模式。
  • 现有代码的性能不足以在无服务器环境中运行。这是另一种常见情况。执行时间可能不适合此工作负载,或者内存太有限。

以上是我在“重写为无服务器”方案中最常见的三种情况。我们可能还会想到更多,所以在决定是否采用重写方案时,请根据自身情况做出最佳判断。

第二种方法更可取,因为它避免了重新创建现有服务的额外开销。

与前一条路径一样,我们可以设想一些可能实现这条路径的高级场景。

  • 该语言/框架在无服务器环境中得到支持。这听起来很简单,但实际上意义重大。如果您的服务已经使用了无服务器提供商开箱即用的语言或框架,那么我们可以将其移植到无服务器环境中运行。这通常意味着需要添加在函数处理程序中运行所需的代码、调整监控、更新日志记录以及进行任何其他配置更改。
  • 该服务可以在 Docker 容器内运行,也可以已经容器化。还记得之前我们说过,在无服务器环境中不支持开箱即用的语言或框架需要重写。如果您使用 AWS,这可能不是您唯一的选择。img2lambda降低了这一门槛,让您能够使用 Lambda Layers 直接迁移这些工作负载

在开始将可移动工作负载迁移到无服务器架构时,我们可以选择这两种方法。当然还有其他方法,其中容器化是比较常见的一种。在考虑向无服务器架构转型时,将工作负载迁移到容器中可能是一个不错的折中方案。但是,仔细分析可能会发现,这是一个不必要的步骤,您应该考虑前两种方法中的一种。

步骤 4:移动不可移动的部分

但是那些我们认为不可移动的东西又该怎么办呢?

在这种情况下,首先要回答的问题是,为什么一开始就认定它是不可移动的?当我们刚接触无服务器时,我们会认为某些东西不可移动,是因为无服务器本身的限制。

  • 执行时间有限,1-15 分钟,取决于您的云提供商。
  • 与无服务器工作负载相关的冷启动延迟。
  • 磁盘大小限制,我们只有少量的暂存空间。
  • 内存受到限制,最多 3GB,具体取决于您的云提供商。

遇到这些限制的事物也能迁移吗?当然可以,但你可能需要做一些重构。让我们逐一分析一下这些限制,并勾勒出一些可以尝试消除限制、将其转变为“可迁移”服务的总体思路。

执行时间有限

无服务器架构刚推出时,这是一个颇具争议的限制。我们倾向于认为程序和应用程序是无限期运行的。但对于现代云计算来说,这已不再必要。

如果我们想象一下云端的自动伸缩组,它会进行横向扩展和纵向缩减,同时启动和终止工作负载。在这方面,无服务器并没有太大的不同。只不过,在我们的“实例”消失之前,我们完成工作的时间更短了。

如果您受到此限制,您可能需要重新想象此特定服务的工作方式。

这项服务是否批量处理任务?如果是,请创建一个函数,将这项任务和另一个处理单个任务的无服务器工作负载进行扇出。通过扇出任务,我们可以利用并行化来缩短执行时间。

服务可以从同步转为异步吗?通常我们先从同步开始,因为异步更容易上手。但是,异步允许我们在后台处理工作,并且可以更有策略地安排执行时间。

这种限制还可能出现在许多其他场景中。我最好的建议是创造性地思考如何重构代码,使其能够在无服务器的世界中正常工作。你或许仍然决定不走这条路,这很正常。但至少,这种尝试应该能让你更多地思考为什么这是不可能的。

冷启动延迟

对于许多希望迁移到无服务器架构的人来说,这仍然是一个障碍。函数被调用到实际开始工作之间的时间,我们称之为冷启动

这种情况仅当您的无服务器工作负载没有现成的容器/镜像/环境时才会发生。在这种情况下,必须启动一个新的容器/镜像/环境,初始化代码,然后才能开始工作。

当您在 VPC 内部运行工作负载时,AWS Lambda 中这个问题非常明显。您经常这样做是为了连接到 RDS 等数据库服务。由于这个问题,Lambda 实际上会让这些环境长时间处于热状态。即便如此,您的同步 API 可能仍会在初始访问时检测到冷启动。

那么这里有哪些解决方案呢?

众所周知的“最佳实践”是对工作负载进行 ping 操作,以保持容器处于温暖状态。这听起来有点奇怪,但这是我们目前能想到的最好的方法。Serverless实际上有一个插件可以做到这一点。在 AWS 中,你可以创建一个 CRON 作业,每 5 分钟调用一次你的 Lambda 函数。这可以为该函数保持一个温暖的环境,从而最大限度地减少冷启动。

但是,冷启动延迟不仅在于云提供商,也在于开发者。函数处理程序中声明的内容越多,启动所需的时间就越长。

全局变量或可在函数调用之间复用的内容在函数处理程序之外声明。这是为了更好地利用冷启动和热启动。保留在处理程序之外的内容无需热启动环境中重新初始化。

冷启动是每个迁移到无服务器应用的人都应该考虑的一个限制因素。它会成为阻碍吗?大多数情况下不会,因为在相当活跃的应用程序中,环境可能会保持温暖。但如果你的工作负载非常频繁,那么你可能会看到频繁的冷启动,因此你需要考虑上述策略。

磁盘大小和内存限制

说实话,我在运行无服务器工作负载时从未遇到过这些限制。

也就是说,如果遇到磁盘或内存限制,您可以考虑改变一些高层次的事情。

如果磁盘空间受限,你很可能在函数中管理某种状态,或者操作非常大的文件或文件集合。在前一种情况下,将状态保留在外部并以流式传输的方式传入,而不是一次性读取所有内容。这有利于节省内存和磁盘空间。

用于处理大文件。如果可以的话,您可能需要考虑以流式传输文件并分散处理。如果可以进行流式传输,那么您可以指示一个函数处理第一个块,下一个函数处理下一个块,依此类推。

这些限制在无服务器环境中很难解决,但并非不可能。然而,它们应该引发一场关于这种工作负载是否适合无服务器的讨论。

第五步:为成功做好准备

一旦你在第三步确定了可行的路径,你很可能会开始考虑实施。不过,在你深入实施之前,这里有一些技巧、流程和工具可以帮助你取得成功。

  • 使用基础设施即代码,未来的你会感谢你。想想看,你从管理一个大型应用程序到管理许多无服务器工作负载,从集中式到分布式。手动配置这些分布式服务是灾难的根源。使用 Terraform、无服务器框架、CloudFormation 或 Pulumi 等工具可以大大简化管理。
  • 十二要素应用将使您的生活更加轻松。AWS 无服务器倡导者 Chris Munns 发表了一篇精彩的博客文章,重点介绍了无服务器环境中的方法论。
  • 将服务彼此解耦可以定义清晰的契约并实现独立扩展。这并非新概念,但它将提升你的无服务器性能。服务之间能够异步且解耦的程度越高越好。让服务之间传递消息,而不是相互调用。根据事件队列进行工作,而不是响应单个请求。
  • 先走后跑。在迁移到无服务器架构时,请从规模较小的服务开始。这将帮助您建立良好的模式和实践。它还能揭示您可能遇到的一些痛点。

结论

无服务器工作负载是云计算的未来之一,但并非未来。随着技术的进步,我们将需要各种各样的计算平台。有些东西可能至少在一开始就不适合无服务器模型。

没关系。但这并不是不在可能的情况下利用它的理由。

无服务器架构使我们摆脱了配置和管理系统所依赖的底层计算能力的责任。摆脱了这些复杂性,我们可以专注于编写能够为用户带来价值的代码。这就是无服务器架构的附加价值。

它并不完美。它有一些缺陷和怪异之处,会阻碍你的旅程,但大多数问题都可以通过退一步思考、换个角度思考来解决。有些问题无法解决,这也没关系。没有人能保证你的单体应用一夜之间就能变成无服务器应用。但它们可以通过一个深思熟虑的计划,逐步实现。

您是否渴望了解更多有关 Amazon Web Services 的信息?

如果您正计划开启您的 AWS 之旅,但不知从何入手,不妨看看我的课程。我们专注于在 AWS 上托管、保护和部署静态网站。这将使我们能够在使用过程中学习超过 6 种不同的 AWS 服务。在您掌握基础知识后,我们将深入学习两个附加章节,涵盖更高级的主题,例如“基础设施即代码”和“持续部署”。

鏂囩珷鏉ユ簮锛�https://dev.to/kylegalbraith/how-a-monolith-architecture-can-be-transformed-into-serverless-8l4
PREV
获得 AWS 认证如何改变您的职业生涯?
NEXT
FreeCodeCamp 侵犯了 Medium 作者的权利