在无服务器系统里,服务器不见了,架构图惯常的样子也随之消失。真正重要的变成了:每个函数由什么触发,失败时会发生什么,以及哪些事件把系统的一部分连接到下一部分。一张画了二十个 Lambda 方框却没有一个触发器的图,看起来很完整,其实什么也没解释。
本文介绍如何在 AWS 上画一张新同事也能看懂的无服务器架构图:一个完整示例、一套表示调用类型和失败路径的画法,以及会让这类图产生误导的常见错误。
先弄清每个函数如何被调用
图上的每个 Lambda 函数都由某个东西启动,而 AWS 有三种调用模式,出错时的行为各不相同。这是无服务器架构图最值得展示的信息。
| 调用模式 | 典型来源 | 失败时由谁重试 | 失败最终去向 |
|---|---|---|---|
| 同步 | API Gateway、函数 URL、SDK 调用 | 由调用方决定 | 返回给调用方的错误响应 |
| 异步 | EventBridge、S3 通知、SNS | Lambda 默认重试两次 | 失败时目标或死信队列(如果你配置了) |
| 事件源映射(Lambda 轮询) | SQS、DynamoDB Streams、Kinesis | Lambda 持续重试该批次 | SQS:队列的死信队列。Streams:失败时目标,否则记录过期 |
给每条触发连线标注来源和模式:sync、async 或 poll, batch 10。当一次故障以“消息在堆积”开头时,大家最先找的就是这条线。
示例:一个无服务器订单 API
一个完全基于托管服务构建的小型订单服务:
- 客户端调用 API Gateway 的 HTTP API。JWT 授权方会校验由 Amazon Cognito 用户池签发的令牌。
- API Gateway 同步调用
createOrder。该函数校验请求,并把订单写入ordersDynamoDB 表。 - 表上的 DynamoDB 流触发
publishOrderEvents,后者把OrderPlaced发送到一个自定义的 EventBridge 事件总线。由于事件来自流,只有写入成功时才会发布。 - 一条 EventBridge 规则匹配
OrderPlaced,并把它发送到receiptsSQS 队列。 - Lambda 轮询该队列,以每批最多 10 条消息调用
sendReceipt;该函数通过 Amazon SES 给客户发送邮件。 - 失败五次的消息会被移入
receipts-dlq,那里的警报会通知团队。
图表内容
- Clients
- Amazon Cognito
- orders-service stack (SAM)
- API Gateway
- createOrder
- DynamoDB: orders
- publishOrderEvents
- EventBridge bus: orders
- SQS: receipts
- sendReceipt
- SQS: receipts-dlq
- CloudWatch alarm
- Amazon SES
- POST /orders
- JWT authorizer
- sync
- PutItem
- stream, poll
- PutEvents: OrderPlaced
- rule: OrderPlaced
- poll, batch 10
- SendEmail
- after 5 receives
- messages > 0
请求路径在第 2 步结束:订单一存好,客户端就会收到响应。之后的一切都是异步的,图中用虚线连线画出这些触发。
无服务器架构图的规则
把触发器画成带标签的连线
进入函数的连线说明了是什么启动了它:POST /orders、DynamoDB stream、rule: OrderPlaced、SQS, batch 10。没有入向连线的函数,要么是死代码,要么是图上漏画了一条线。
把请求路径和异步处理分开
同步调用用实线连线,之后才发生的一切都用虚线连线。读者不必逐个看标签,也能顺着找到给用户增加延迟的那条路径。
有意识地画出失败路径
对每条异步连线,都要决定失败的内容去往哪里,并把它画出来:死信队列、失败时目标,或者一条写着“记录在 24 小时后过期”的注释。DynamoDB Streams 会把记录保留 24 小时,因此一个持续失败的消费者,会在记录过期后丢失事件。S3 类型的失败时目标会保留失败记录的副本;SQS 或 SNS 目标只收到元数据,所以必须有某个组件在这 24 小时内从流中重新读取记录。
一个函数一个节点
用一个“Lambda”节点代表三十个函数,会把触发器藏起来,而触发器恰恰就是架构。如果函数太多,就按服务拆分图,而不是合并方框。
按部署单元加框
把一起部署的资源(例如一个 SAM、CDK 或 Terraform 堆栈)放进一个框里。这样能看出归属,以及哪些东西会一起变更。
把权限和限制写成注释
每个函数都有一个 IAM 执行角色,有些还设置了预留并发或较长的超时时间。不要为每个函数画一个角色。把评审时重要的信息写成注释:“只有 createOrder 可以写入 orders”“sendReceipt 的 SQS 触发器最大并发为 5,以保护 SES 限额”。
常见错误
- 把 API Gateway 画成负载均衡器。 它还负责认证、限流和请求转换,授权方也应该出现在图上。
- 缺少死信队列,或者死信队列无人监控。把警报也画出来。
- 事件总线上没有规则。 EventBridge 总线按规则扇出;连线上要标注规则,而不只是总线。
- 不区分同步和异步。 这正是 API 慢和邮件慢之间的区别。
- 基础设施噪音。 日志组、层和每一条 IAM 策略都应该放在模板里,而不是总览图上。
在 Archboard 中构建
Archboard 云节点包中的节点与云厂商无关,并带有端口,所以要给每个节点标上 AWS 服务名:
- 使用 Google 或 GitHub 登录,并新建一张图。
- 为客户端和 Amazon SES 添加基础节点包中的方框节点,再添加云节点包中的 API 网关,以及安全节点包中标签为
Amazon Cognito的身份提供商。 - 为每个 Lambda 函数添加一个云节点包中的函数,名称与模板中完全一致。
- 添加云节点包中标签为
DynamoDB: orders的托管数据库、数据节点包中标签为EventBridge bus的主题、用于队列及其死信队列的云节点包队列节点,以及表示警报的 DevOps 节点包告警。 - 连接端口。请求路径保持实线,把异步连线设为虚线,并给每个触发器标上来源和调用模式。
- 把整个堆栈放进基础节点包中的框架,添加关于权限和限制的注释,然后把在线链接分享给团队。
这个示例用了 13 个图表节点,在 Free 套餐的限制之内。关于无服务器或容器工作负载周边的网络,请参阅 AWS VPC 架构图指南;更多云架构模式见云架构使用场景页面。
常见问题
每个 Lambda 函数都要画出来吗? 在服务级的图上要画,因为每个函数都有自己的触发器和失败行为。在系统总览图上,把这个服务画成一个节点,并链接到它自己的图。
可以使用 AWS 官方图标吗?
Archboard 没有 AWS 专用的节点包:请用云、网络和安全节点包中带端口的类型化节点搭建图,并给每个节点标上服务名,例如 Amazon SES 或 DynamoDB: orders。如果还想要 logo,搜索并插入中有 AWS 服务的品牌图标(例如 AWS Lambda),可以作为图标节点放置。
Step Functions 怎么表示? 在架构图上画成一个节点,标上状态机名称;工作流本身另画一张流程图或 BPMN 图。
冷启动和并发写在哪里? 写在相关函数旁边的注释里,例如对延迟敏感的端点上配置的预置并发。
需要画出 IAM 角色吗? 不需要画成节点。把影响设计的权限记在注释里,完整的策略留在基础设施代码中。