Mono-Lambda 与单函数 API 的区别、原因和时机

2025-06-08

Mono-Lambda 与单函数 API 的区别、原因和时机

我几乎每周都会在 Twitter、StackOverflow 或 Reddit 上看到一个关于如何构建无服务器 API 的问题。就像软件领域的大多数事情一样,TL;DR 的意思是“视情况而定”。如果你已经觉得无聊了,就直接浏览 TL;DR,然后在 Twitter 上跟我提你的反对意见。如果没有,那就准备好深入研究吧!

TL;DR

单功能 API:

  • 对设置和 IAM 执行角色的更多控制/粒度
  • 轻松查找日志/日志组
  • 更小的封装尺寸
  • 使用 API 密钥、高度定制的授权器、速率限制等的最高可选性。
  • 由于功能隔离,开发更容易
  • 需要注意CF堆栈限制
  • 部署时间长
  • 配置更加复杂(相对于代码)
  • 在 REST 函数之间共享代码变得更加困难

Mono Lambda API:

  • 路由超级灵活
  • 使用你自己的框架,例如 Express
  • 无需担心 CF 堆栈限制
  • 在路线/资源之间共享代码非常容易
  • 总体可选性较低(需要为所有功能设置授权器并在代码中处理 RBAC)
  • 综合开发经验,需要良好的CI流程
  • 更大的封装尺寸
  • 调试更加复杂,因为所有操作都路由到一个日志流
  • 粒度较低的 IAM 权限

详细比较

但我们的目标是深入研究这些选项、它们的技术后果以及可能帮助您做出决定的因素,因此“视情况而定”是不够的。

坦白说,Lambda 是 Serverless 中相当无聊的一部分。无聊是好的方面——就像健康的 DevOps 文化一样,部署频繁、轻松,而且,嗯,无聊!

如果您来自传统的反向代理和服务器背景,那么您已经使用过某种基于域(或基于顶级路由)的请求路由,然后通常使用 Rails 或 Express 之类的东西将各个路由与业务逻辑相匹配。

无服务器 API 也位于某种负载均衡器之后。分析 API 网关/REST API、HTTP API 和应用程序负载均衡器 (ALB) 是另一篇文章的主题,所以我就不赘述了。选择 API 提供商后,集成 Lambda 时有两种选择。您可以创建单独的路径并将这些请求路由到各个 Lambda 函数(单函数),也可以将所有请求路由到一个函数,然后在函数内部使用类似 express 的路由系统将路径路由到业务逻辑(单 Lambda)。

单功能 API

单函数 API 模式与 Lambda 非常契合。只需在serverless.yml文件中添加新函数,声明新的处理程序,一切就绪!在单函数 API 的世界里,还有两种额外的选择:

  • 您可以为资源上的每个操作(GET、LIST、PUT、POST 和 DELETE)设置单独的函数。这样可以使代码更简洁、更简洁。
  • 您可以将所有资源分组到一个函数下,然后根据传递的 HTTP 方法和 URL 参数编写一个 case 语句。这种方法稍微复杂一些,但如果您拥有大量资源,并且不想遇到堆栈资源限制或长时间部署的情况,这种方法可能对您来说很有意义。

单一函数具有一些关键优势。单一函数具有最高的可用粒度级别,可用于设置以下各项:

  • 最大和/或预配置并发
  • 函数超时
  • 请求主体
  • 查询字符串格式
  • IAM 执行角色

列表中最重要的一项或许是 Lambda 函数执行时所遵循的 IAM 策略。在单函数 API 中,每个函数都可以被限制为其独有的操作。例如,如果我有一个用于更新用户 API 的单独函数,我可以限制 IAM 角色仅执行对 DynamoDB 的更新调用,这将保证我的更新函数永远不会删除任何记录。

单函数通常更容易调试,因为每个日志流只包含针对特定资源的单个操作的数据!与 Mono-Lambda 相比,所有 API 资源和操作都合并在一个日志流中,因此单函数 API 的故障排除要容易得多。

您还可以通过以下方式大大减少整体包装尺寸和占用空间:

package:
  individually: true
Enter fullscreen mode Exit fullscreen mode

有助于缩短冷启动时间,但任何改进都可能被 Web 请求分散到多个函数中抵消。请勿仅根据感知到的冷启动风险来选择 API 模式,因为冷启动很少发生(而且会越来越少发生),启动时间很短(而且会越来越短),并且很容易通过其他措施来缓解。

最后,单功能 API 符合 AWS 对基于 Lambda 的 API 的通用设计理念。这意味着您在使用基于 API 的速率限制、API 密钥、授权器等功能时,通常会遇到更少的阻力,并拥有最大的灵活性。

单函数 API 设计也存在一些缺点。随着资源的增加,Cloudformation 的部署速度会变慢,而且每个 Lambda 函数都需要函数本身以外的多种资源(例如执行角色和日志组)。

每个 Cloudformation 堆栈还限制 500 个资源。如果您为每个路由、每个资源设置单独的函数(以及角色和组),那么您很快就会遇到此限制。

最后,在多个 Lambda 函数之间共享代码可能非常困难。Lambda 层很棒,但它们有明确的版本控制,需要第二个并行的 CI/CD 流程来部署。这意味着,如果您要更新某些共享代码(例如请求/响应负载格式化程序或常用实用程序函数),则必须发布该层的新版本,然后在每个函数中更新其用法(这同样可能需要很长时间)。

例子

functions:
  getUser:
    handler: users.get
    events:
      - httpApi:
          path: /users/{id}
          method: GET
  listUsers:
    handler: users.list
    events:
      - httpApi:
          path: /users/
          method: GET
  createUser:
    handler: users.create
    events:
      - httpApi:
          path: /users/
          method: POST
  updateUser:
    handler: users.update
    events:
      - httpApi:
          path: /users/{id}
          method: PUT
  deleteUser:
    handler: users.delete
    events:
      - httpApi:
          path: /users/{id}
          method: DELETE
Enter fullscreen mode Exit fullscreen mode

Mono-Lambda API

Mono-Lambda 设计有几个关键优势。对于使用过 Rails 或 Express 的传统编程背景的人来说,它更容易上手。事实上,你可以很容易地将Express API迁移到 Lambda 中(尽管我不推荐这样做,因为 Express 会增加不少开销)。

从发布和部署的角度来看,Mono-Lambda API 也更加简单。这可能是 Mono-Lambda API 最大的卖点,因为对我来说,软件团队最重要的方面是能够尽可能频繁地部署软件。

我经常发现一些单功能 API 的发布流程极其复杂,这源于数百个 Lambda 函数和多个共享库(通过层或私有包)。如果您的组织没有足够的资源来快速安全地将共享代码部署并发布到单功能 API,那么 Mono-Lambda 是一个不错的选择。

Mono-Lambda API 的统一配置可能是好事,也可能是坏事。如果您的问题域包含大量具有类似操作和行为的资源,并且您使用的是单表 DynamoDB 模式,那么每种资源的 IAM 策略可能非常相似。这意味着您可以生成一个相当严格的策略,既允许 Mono-Lambda API 执行必要的操作,又不会过于宽松。

使用 Mono-Lambda API,您可以在 Lambda 函数内部执行路由、请求格式验证、访问控制和限流等操作。对于许多人来说,这已经足够了,因为 Express/Koa 等都有强大的库可供使用,而且开发人员可能已经熟悉如何操作。如果您不使用 API 网关的高级功能,那么考虑使用 Mono-Lambda API 会非常明智。

如果您不介意 API 网关的高级功能,也不在乎 IAM/并发/超时设置的精细度,那么 Mono-Lambda API 最大的缺点就是 AWS 控制台和 Cloudwatch 的使用可能会有点混乱。默认情况下,整个函数的日志会发送到一个流中。由于您的函数处理不同的资源,因此可能难以追踪。我建议使用自定义日志记录器编写高度结构化的日志消息,然后依靠 Cloudwatch 日志洞察进行筛选。

这可能会很慢,而且有很多第三方选项可以帮助解决这个问题(坦白说——我就在一家公司工作)。所以,探索你的选择,多尝试一下吧!

例子

functions:
  app:
    handler: index.handler
    events:
      - httpApi:
          path: ANY {proxy+}
          method: ANY
Enter fullscreen mode Exit fullscreen mode

总结

Mono-Lambda 与 Single-Function 并不是一个硬性选择,而是一个范围,大多数用户会长期尝试两者的结合。

我认为 Mono-Lambda 是一个很好的默认选择,而且由于它很容易拆分出无服务器功能,所以它不是一个单向的选择。

当我发现高度特定权限的用例、想要使用 API 网关功能(如 API 密钥)或需要单一责任 Lambda 函数时,我就会使用一个!

祝你好运!欢迎在Twitter上提问,或者分享你正在构建的东西!

参考链接:https://dev.to/aws-builders/the-what-why-and-when-of-mono-lambda-vs-single-function-apis-5cig
PREV
使用 Tofu/Terraform 和 SAM 在 AWS 中实现零停机部署
NEXT
AWS 无服务器开发现状