亚马逊AWS官方博客
利用 AWS Lambda 扩展 SaaS 平台
许多 SaaS 提供商允许客户(租户)提供特定于客户的代码,作为 SaaS 平台各种工作流的一部分来触发。这种可扩展性模式允许客户定制系统行为并添加丰富的集成,同时允许 SaaS 提供商将工程资源优先用于核心 SaaS 平台,避免按客户定制。
为了简化企业开发人员在 SaaS 平台上的构建体验,SaaS 提供商提供了在 SaaS 平台内托管租户代码的功能。本博客为使用 AWS 无服务器技术和 AWS Lambda 在 SaaS 平台上运行自定义代码提供架构指导,而无需在 SaaS 提供商或客户方管理基础设施。
供应商托管的扩展功能
利用供应商托管的扩展功能,SaaS 平台会根据 SaaS 应用程序中发生的事件运行客户代码。在这种模式下,管理和扩展代码启动环境的重任由 SaaS 提供商承担。
要托管和运行自定义代码,SaaS 提供商必须考虑将运行不受信任的自定义代码的环境与核心 SaaS 平台隔离,详见图 1。这给安全性、成本和利用率的管理带来了更多挑战。
使用 AWS 无服务器服务运行自定义代码
使用 AWS 无服务器技术时,由于没有服务器需要管理,因此省去了基础设施预置和管理的任务,SaaS 提供商可以利用自动扩缩、高可用性和安全性的优势,同时只需按价值付费。
应用场景示例
让我们以一个简单的 SaaS 待办事项列表应用程序为例,该应用程序支持在列表中添加新待办事项时启动自定义代码的功能。客户可使用该应用程序提供自定义代码,来丰富新添加的待办事项的内容。对该解决方案的要求包括:
- 每个租户提供的自定义代码应与所有其他租户和 SaaS 核心产品隔离运行
- 跟踪每个客户的 AWS 资源使用情况和成本
- 可根据客户需求进行扩展
解决方案概览
图 2 中的 SaaS 应用程序是客户使用的核心应用程序,每个客户都被视为一个单独的租户。为简洁起见,我们假设客户代码在登记过程中已存储在 Amazon Simple Storage Service(Amazon S3)存储桶中。当 SaaS 应用程序中因用户操作(如添加新的待办事项)而生成符合条件的事件时,该事件会向下传播,以安全地启动相关的客户代码。
自定义代码运行演练
让我们详细说明一下用户添加新待办事项时自定义代码的启动流程:
- 当用户执行一项操作(如添加新的待办事项)时,SaaS 应用程序中就会生成一个事件。为了扩展 SaaS 应用程序的行为,该事件与自定义代码相关联。每个事件都包含一个租户 ID 和作为有效负载一部分传递的任何其它数据。每个事件都是自定义代码 Lambda 函数的“启动请求”。
- Amazon EventBridge 用于将 SaaS 应用程序与事件处理的具体实施解耦。EventBridge 使大规模构建事件驱动型应用程序变得更加容易,并为未来添加更多消费者提供了可能。如果任何下游服务出现意外故障,EventBridge 会重试一定次数的事件发送。
- EventBridge 会将事件作为消息发送到 Amazon Simple Queue Service(Amazon SQS)队列,随后由 Lambda 函数(分配器)接收并进一步路由。Amazon SQS 可实现微服务的解耦和扩展,还可为等待处理的事件提供缓冲。
- 分配器从 SQS 队列中轮询消息,并负责将事件路由到相应的租户进行进一步处理。分配器会从消息中检索租户 ID,并在数据库中执行查找(我们推荐使用低延迟的 Amazon DynamoDB),检索租户 SQS Amazon 资源名称(ARN),确定将事件路由到哪个队列。为了进一步提高性能,可以缓存租户到队列的映射。
- 租户 SQS 队列充当消息存储缓冲区,并被配置为 Lambda 函数的事件源。使用 Amazon SQS 作为 Lambda 的事件源是一种常见的模式。
- Lambda 执行租户上传的代码来执行所需的操作。通用实用程序和管理代码(包括日志记录和遥测代码)保存在 Lambda 层中,这些层会添加到每个已预置的自定义代码 Lambda 函数中。
- 在对数据执行所需的操作后,自定义代码 Lambda 会将一个值返回给 SaaS 应用程序。至此,运行周期结束。
这种架构允许 SaaS 应用程序创建一个自我管理的队列基础设施,为租户并行运行自定义代码。
租户代码上传
SaaS 平台可允许客户通过用户界面或使用 SaaS 提供商为开发人员提供的命令行界面上传代码,从而方便将自定义代码上传到 SaaS 平台。上传的代码以 .zip 格式保存在自定义代码 S3 存储桶中,可用于预置 Lambda 函数。
自定义代码 Lambda 预置
租户环境包括一个租户 SQS 队列和一个从队列中轮询启动请求的 Lambda 函数。该 Lambda 函数由两部分组成:(1) SaaS 平台提供的通用代码;(2) 客户提供的自定义代码。
通用代码负责连接 SaaS 平台和租户提供的自定义业务逻辑。通用代码“封装”了客户提供的自定义代码,使自定义代码从处理实施的具体细节中完全抽象出来。例如,我们不希望自定义代码知道其接收的有效负载来自 Amazon SQS,也不希望自定义代码知道启动响应的发送目的地。通用代码主要负责两个部分:
- 从 SQS 队列中轮询消息并构造 JSON 有效负载,将其作为输入发送给自定义代码。
- 一旦自定义代码启动完成,通用代码就会向 SaaS 应用程序发送处理结果通知。这可以直接通过 EventBridge 或 Amazon SQS 完成。
这些通用代码可以跨租户共享,并由 SaaS 提供商部署,既可以作为库,也可以作为添加到 Lambda 函数中的 Lambda 层。
通过结合使用开源和专有隔离技术,每个 Lambda 函数启动环境都是完全隔离的,这有助于您解决交叉污染的风险。通过为每个租户预置单独的 Lambda 函数,您可以实现最高级别的隔离,并通过跟踪每个租户的成本而获益。
结论
在这篇博文中,我们探讨了使用自定义代码扩展 SaaS 平台的需求,以及为什么使用 Lambda 和 Amazon SQS 的 AWS 无服务器技术可以很好地实现这一目标。我们还研究了一种解决方案架构,这种架构可以提供必要的租户隔离,并且在这种应用场景下具有成本效益。
有关使用 Lambda 构建应用程序的更多信息,请访问 Serverless Land。有关构建 SaaS 应用程序的最佳实践,请访问 AWS 上的软件即服务(SaaS)。