介绍 Swift AWS Lambda 运行时
我很高兴地宣布 Swift 服务器生态系统的一个新的开源项目:Swift AWS Lambda 运行时。Swift AWS Lambda 运行时以 Swift 包的形式分发,旨在帮助 Swift 开发人员为 Amazon Web Services Lambda 平台构建无服务器函数。
该项目是包括来自 Apple 和 Amazon 的工程师在内的整个 Swift 社区的工程师共同努力的成果。值得注意的是,Fabian Fett 在社区中率先开展了这项工作,并与他人合著了这个库。作为一个开源库,任何有兴趣为该项目做出贡献的人都可以轻松加入,帮助使其变得更好。
背景
许多现代系统都有客户端组件(如 iOS、macOS 或 watchOS 应用程序)以及与这些客户端交互的服务器组件。对于客户端应用程序开发人员来说,无服务器函数通常是将应用程序扩展到云端的最简单、最有效的方式。
无服务器函数正成为在云端运行事件驱动或其他临时计算任务的日益流行的选择。它们为关键任务微服务和数据密集型工作负载提供动力。在许多情况下,由于无服务器函数具有按需性质,开发人员可以更轻松地扩展和控制计算成本。
使用无服务器函数时,必须注意资源利用率,因为它直接影响系统成本。这就是 Swift 的闪光点!凭借其低内存占用、确定性的性能和快速启动时间,Swift 非常适合无服务器函数架构。
将这些与 Swift 的开发者友好性、表达性和对安全性的强调相结合,我们就得到了一个对所有技能水平的开发者都非常友好、可扩展且具有成本效益的解决方案。
Swift AWS Lambda 运行时旨在使使用 Swift 构建 Lambda 函数变得简单而安全。该库是 AWS Lambda 运行时 API 的一个实现,并使用嵌入式异步 HTTP 客户端,该客户端针对 AWS 运行时环境中的性能进行了微调。该库提供了一个多层 API,允许构建各种 Lambda 函数:从快速简单的闭包到复杂的、对性能敏感的事件处理程序。
它是如何工作的?
使用闭包
使用 AWS Lambda 运行时最简单的方法是传入一个闭包,例如
// Import the module
import AWSLambdaRuntime
// In this example we are receiving and responding with strings
Lambda.run { (context, payload: String, callback) in
callback(.success("Hello, \(payload)"))
}
更常见的情况是,有效负载将是一个 JSON,它使用 Codable
进行建模,例如
// Import the module
import AWSLambdaRuntime
// Request, uses Codable for transparent JSON encoding
private struct Request: Codable {
let name: String
}
// Response, uses Codable for transparent JSON encoding
private struct Response: Codable {
let message: String
}
// In this example we are receiving and responding with JSON using Codable
Lambda.run { (context, request: Request, callback) in
callback(.success(Response(message: "Hello, \(request.name)")))
}
由于 Lambda 函数通常由来自 AWS 平台(如 SNS、SQS 或 S3 事件)的事件触发,因此该软件包还包含一个 AWSLambdaEvents
模块,为这些常见的触发事件类型提供实现。例如,处理 SQS
消息
// Import the modules
import AWSLambdaRuntime
import AWSLambdaEvents
// In this example we are receiving a SQS Message, with no response (Void)
Lambda.run { (context, message: SQS.Message, callback) in
...
callback(.success(Void()))
}
除了这些常见的触发事件外,AWSLambdaEvents
还包括用于将 Lambda 函数与 APIGateway 集成的抽象 - APIGateway 是一个 AWS 系统,可帮助将 Lambda 函数公开为 HTTP 端点。
// Import the modules
import AWSLambdaRuntime
import AWSLambdaEvents
// In this example we are receiving an APIGateway.V2.Request,
// and responding with APIGateway.V2.Response
Lambda.run { (context, request: APIGateway.V2.Request, callback) in
...
callback(.success(APIGateway.V2.Response(statusCode: .accepted)))
}
使用 EventLoopLambdaHandler
将 Lambda 函数建模为闭包既简单又安全。Swift AWS Lambda 运行时将确保用户提供的函数从网络处理线程卸载到其自己的线程,这样即使代码变得缓慢或无响应,底层 Lambda 进程也可以继续并与运行时引擎交互。这种安全性是以网络和处理线程之间上下文切换带来的少量性能损失为代价的。在大多数情况下,基于闭包的 API 的简单性和安全性优于下面详述的面向性能的 API 的复杂性。
对性能敏感的 Lambda 函数可以选择使用更复杂的 API,该 API 允许用户代码与网络处理程序在同一线程上运行。Swift AWS Lambda 运行时使用 SwiftNIO 作为其底层网络引擎,这意味着这些 API 基于 SwiftNIO 的并发原语,如 EventLoop
和 EventLoopFuture
。
例如,处理 SNS
消息
// Import the modules
import AWSLambdaRuntime
import AWSLambdaEvents
import NIO
// Our Lambda handler, conforms to EventLoopLambdaHandler
struct Handler: EventLoopLambdaHandler {
typealias In = SNS.Message // Request type
typealias Out = Void // Response type, or Void
// In this example we are receiving a SNS Message, with no response (Void)
func handle(context: Lambda.Context, payload: In) -> EventLoopFuture<Out> {
...
context.eventLoop.makeSucceededFuture(Void())
}
}
Lambda.run(Handler())
除了使用基于 EventLoopFuture
的 API 的认知复杂性之外,请注意,应格外小心地使用这些 API。EventLoopLambdaHandler
将在与库的网络引擎相同的 EventLoop
(线程)上执行用户提供的函数,这要求实现永远不要阻塞底层的 EventLoop
。换句话说,Lambda 代码绝不应使用阻塞 API 调用,因为它可能会阻止库与 Lambda 平台交互。
其他资源
其他文档和示例可以在项目的 readme 中找到。
项目状态
这是一个社区驱动的开源项目的开端,积极寻求贡献。虽然核心 API 被认为是稳定的,但 API 可能会在更接近 1.0
版本时继续演进。有几个领域需要额外关注,包括但不限于:
- 进一步的性能调优
- 额外的触发事件
- 额外的文档和最佳实践
- 更多示例
参与其中
如果您对 Swift AWS Lambda 运行时感兴趣,请参与进来!源代码已公开,我们鼓励开源社区贡献代码。如果您有反馈、问题或想讨论该项目,请随时在 Swift 论坛上聊天。如果您想报告错误,请使用 GitHub 问题跟踪器。我们期待与您合作,帮助推动行业朝着更好、更安全的编程未来迈进。