用途
本技能用于设计和实现事件驱动系统,通过异步消息传递让服务彼此解耦。适合在构建微服务架构、实现分布式工作流、为独立部署而解耦服务、处理最终一致性,或把同步的服务间调用替换为异步事件时使用。
核心原则
- 事件是事实,命令是请求。事件描述已发生的事情(如 OrderPlaced、PaymentReceived);命令请求某个动作(如 ProcessPayment、ShipOrder)。这一区分决定了正确的系统设计:事件是广播,命令是点对点。
- 幂等不是可选项。消息至少会被投递一次(有时更多),每个消费者都必须优雅处理重复消息,可用事件 ID、版本检查或数据库约束去重。
- Schema 演进不能破坏消费者。事件 Schema 会变化,应采用向后兼容的演进方式(增加字段,绝不移除或重命名),显式地对 Schema 做版本化,并在迁移期支持多版本。
- 死信不是垃圾。无法处理的消息进入死信队列,它们代表缺陷、数据问题或边界情况。要监控 DLQ、在数量增长时告警,并构建重放工具。
- 本地事务、最终一致。每个服务拥有自己的数据并在本地事务中处理事件,跨服务一致性是最终而非即时的,UI 与工作流需据此设计。
关键模式
模式一:使用事务性发件箱发布事件。当需要原子地更新数据库并发布事件时使用,可避免“双写”问题(数据库写入成功但事件发布失败,或反之)。实现方式:第一步,在同一个数据库事务中把事件写入 outbox 表;第二步,由单独的轮询器/CDC 进程读取 outbox 并发布到消息中间件。原因:双写问题是事件驱动系统中最常见的数据不一致来源;发件箱模式保证只要业务数据写入成功,事件最终一定被发布。
模式二:幂等的消费者。适用于每一个事件消费者,因为所有主流中间件都是至少一次投递。以 Kafka 消费者为例,在消费消息时先做幂等检查(是否已处理过该事件),若已处理则跳过;随后在同一事务内记录“事件已处理”并执行业务逻辑,出错则不提交 offset,让消息被重新投递。原因:Kafka、RabbitMQ 和 SQS 都保证至少一次投递,消费者在再均衡、重试和网络问题期间会看到重复消息;把已处理事件 ID 与业务逻辑放在同一事务中记录,可确保精确一次的处理语义。
模式三:Saga 编排。当业务流程跨越多个服务,且任一步骤失败都需要协调回滚时使用。以订单履行为例,按“支付→库存→发货”顺序执行,每一步都定义 execute 与 compensate。某一步失败时,按逆序对已完成步骤执行补偿操作;若补偿本身失败,则记录严重日志并告警,交由人工介入。原因:跨服务的分布式事务不现实(两阶段提交无法扩展),Saga 用一系列本地事务加补偿动作来替代回滚。
模式四:死信队列处理。每个事件驱动系统都需要针对无法处理消息的策略。示例中使用 SQS,为主队列配置 RedrivePolicy,把超过最大接收次数(如 3 次)的消息转入 DLQ;同时监控 DLQ 并在有消息时告警运营团队,并提供把 DLQ 消息重放回主队列的工具(支持过滤)。原因:死信队列捕获所有重试后仍处理失败的消息,没有 DLQ 时失败消息会阻塞队列或被静默丢弃;DLQ 监控能发现缺陷,重放工具能在下游服务宕机等瞬时故障后恢复且不丢数据。
消息中间件选型参考
Kafka 适合高吞吐事件流与日志压缩,按分区保证顺序,吞吐非常高(每秒数百万),持久化可配置保留策略;RabbitMQ 适合任务队列、路由、请求-响应,按队列保证顺序,吞吐高(每秒 10 万),持久化可选;SQS/SNS 适合无服务器、AWS 原生、低运维场景,按 FIFO 队列保证顺序,吞吐高(FIFO 每秒 3k,标准队列不限),保留 14 天;NATS 适合低延迟、云原生、轻量场景,通过 JetStream 保证顺序,吞吐非常高,JetStream 提供持久化。
反模式
数据库与事件双写而不使用 outbox,会导致某次写入失败时数据不一致,应使用事务性发件箱模式;消费者没有幂等性,会在重投递时重复处理,应在同一事务中按事件 ID 去重;事件负载过大(超过 1MB)会拖慢处理并触及中间件限制,应把数据存在服务里、只发送引用(认领检查);同步处理事件会违背异步架构的初衷,应借助队列异步处理;未配置 DLQ 会使失败消息阻塞队列或消失,应始终配置 DLQ 并告警;事件 Schema 紧耦合会在变更时破坏消费者,应采用向后兼容演进并显式版本化;从多处发布领域事件会造成事件形态不一致与事件遗漏,应设置唯一发布点(聚合根/服务层)。
检查清单
原子化数据库与事件写入使用事务性发件箱;每个消费者都幂等(按事件 ID 去重);死信队列已配置并具备告警与重放工具;事件 Schema 已版本化且向后兼容演进;每个服务都配置了消费者组;DLQ 之前有带指数退避的重试策略;跨服务工作流使用 Saga 或编排模式;监控消费者延迟、DLQ 深度与处理错误;保证事件顺序。