1. 事件驱动集成工程导论
在传统请求—响应式集成中,调用方必须知道被调用方在哪里、是否可用、返回什么,系统之间形成紧密耦合。事件驱动架构(Event-Driven Architecture,EDA)改变了这一前提:生产者只负责把“已经发生的事实”发布出去,消费者按需订阅并自行决定如何处理。生产者不需要知道谁在听,消费者也不需要知道事件从哪来,双方通过事件通道解耦。这种“事实广播 + 按需订阅”的模型,是构建高弹性、可扩展云原生应用的基础。
事件、消息与命令的边界
初学者最容易混淆的三个概念是事件、消息和命令。事件描述的是过去时的事实,例如“订单已创建”“支付已完成”,它不可被拒绝,可以有零个或多个消费者;命令是祈使句,例如“创建订单”“扣减库存”,它面向特定接收者,可能被拒绝或失败;消息则是传输层的泛称,事件和命令都可以封装成消息。理解这一区别非常关键:如果把事件当命令用,就会在事件里塞入“请执行某操作”的语义,导致生产者重新耦合到消费者行为,解耦收益随之消失。
与之配套的是三种投递语义。最多一次(at-most-once)不重试,可能丢事件;至少一次(at-least-once)保证不丢,但可能重复;恰好一次(exactly-once)在分布式系统中通常指“至少一次投递 + 幂等消费”的组合效果。工程实践中,绝大多数场景选择至少一次投递,并在消费者侧实现幂等,例如用订单号作为去重键,重复事件只处理一次。
AWS 集成服务全景
AWS 提供了一组职责互补的集成服务,理解它们各自的位置比记住名字更重要。下面的信号链图展示了从事件产生、路由、缓冲到消费与观测的完整路径,以及各服务在链路中的角色。
从图中可以看出,EventBridge 负责“路由”,SQS/SNS 负责“缓冲与扇出”,Lambda 或容器服务负责“消费”,Step Functions 负责“编排”,CloudWatch 与 X-Ray 负责“观测”。一个成熟的事件驱动系统通常同时使用其中多个服务,而不是只选一个。例如订单创建事件先进入 EventBridge,按规则分别路由到库存 SQS 队列和通知 SNS 主题,库存消费者处理失败时事件进入 DLQ,运维人员通过 CloudWatch 告警发现并重放。
课程实战项目:订单事件处理流水线
本课程围绕一个贯穿始终的实战项目展开:构建一条订单事件处理流水线。项目模拟电商下单场景,包含以下角色与流程。
- 订单服务:接收下单请求,生成订单号(如
ORD-20240612-0001),向 EventBridge 发布OrderCreated事件。 - 库存服务:订阅订单事件,扣减库存;若库存不足,发布
InventoryFailed事件。 - 支付服务:订阅订单事件,发起支付;支付成功后发布
PaymentCompleted事件。 - 通知服务:订阅支付完成事件,发送确认邮件或短信。
- 编排与补偿:用 Step Functions 串联库存与支付,当支付失败时触发库存回滚。
项目采用至少一次投递语义,消费者以订单号作为幂等键。事件结构统一采用如下示例格式,便于跨服务解析:
{
"source": "order.service",
"detail-type": "OrderCreated",
"detail": {
"orderId": "ORD-20240612-0001",
"customerId": "CUST-8821",
"items": [{"sku": "SKU-1001", "qty": 2}],
"amount": 199.00,
"createdAt": "2024-06-12T10:15:30Z"
}
}
在实现过程中,需要重点关注几个工程判断点。第一,事件模式设计:EventBridge 规则通过 source 和 detail-type 匹配事件,规则写得过宽会导致无关事件进入消费者,过窄则容易漏事件。第二,幂等实现:消费者在处理前先查询去重表,若订单号已处理则直接返回成功,避免重复扣库存。第三,失败隔离:为每个 SQS 队列配置 DLQ,并设置最大接收次数(例如 3 次),超过后转入 DLQ 而不是无限重试。第四,可观测性:为每个消费者发布自定义指标,例如 OrdersProcessed、OrdersFailed,并配置告警阈值。