SuperAPI AI 工具集

arch-event-driven

编程与开发

查看项目

更新于 10-16 16:26

技能介绍

用途

该技能用于围绕异步事件设计系统时参考。触发场景包括出现「event-driven architecture」「EDA」「event broker」「Kafka」「publish-subscribe」等表述,或需要设计由事件驱动、松耦合、可独立扩展的系统。

核心思路:组件通过事件代理发出并响应事件来通信,而不是彼此直接调用。生产者不知道谁消费,消费者不知道谁生产。

适用场景

  • 需要松耦合、可独立扩展的组件。
  • 实时数据处理、流式处理或分析管道。
  • 业务工作流天然呈现「X 发生了,现在 Y 作出反应」的形态。
  • 下游消费者可以增加或移除,而生产者无需知晓。

不适用场景

  • 有严格事务一致性要求——事件是最终一致的。
  • 同步请求-响应是自然的通信形态——强行异步会引入延迟与复杂度。
  • 组件少、全部运行在同一进程内的小系统——事件属于过度设计,直接调用更简单。

两种拓扑(Richards & Ford)

  • 代理拓扑:组件向主题发出事件,订阅者消费,没有中心协调者。适合每个步骤都是小反应的协同式工作流。
  • 中介拓扑:中心中介编排工作流,向事件处理器发送命令。适合工作流有确定顺序、需要有人掌握整体流程的场景。

事件与命令

  • 事件描述已经发生的事情,用过去时(OrderPlaced、PaymentSettled)。生产者陈述事实,订阅者自行决定是否响应。领域事件是模型层面的同一概念,在 EDA 中同一类事件经由代理流动。
  • 命令是要求做某事的祈使请求(PlaceOrder、SettlePayment),面向一个特定处理器。事件是扇出,命令是定向到一个目标。

协同与编排

  • 协同:各组件独立响应事件,整体工作流从各自的局部决策中涌现。去中心化、易扩展,但难以看清全貌。
  • 编排:由协调者(中介、Saga、工作流引擎)告诉每个组件下一步做什么。中心化、更易推理,但复杂度集中在一处。

代理选型

  • 持久日志主题(Kafka):事件保留一段时间,订阅者可重放。适合分析、审计、后加入的消费者。
  • 带投递保证的队列(RabbitMQ、SQS):事件投递一次后消失。适合工作队列模式。
  • 进程内总线(Spring ApplicationEventPublisher):事件留在单个 JVM 内,成本低,适合单体内部的解耦。

模式纪律

事件模式是事件驱动系统的公共 API,应像对待任何外部契约一样严格版本化:只做向后兼容的变更;新增字段带默认值;废弃字段保留到消费者完成迁移。

决策启发式

  • 参与者集合稳定且步骤不超过 4 步时用协同;步骤增多或补偿逻辑不简单时用编排。
  • 按实际需要选代理:需要重放选基于日志;一次性投递选队列;进程内选内存总线。
  • 单体内部也可以做事件驱动(进程内事件),做 EDA 不一定需要 Kafka。
  • 从第一天就搭配模式注册表。模式失控漂移是事件驱动系统腐化最快的原因。

反模式

  • 把命令伪装成事件的「事件驱动」(如 UpdateOrderEvent)——本质仍是 RPC,只是多了延迟。必须使用过去时命名。
  • 事件当作方法调用:生产者发出事件后立刻监听某个特定消费者的响应,是伪装成异步的同步 RPC。若确实需要请求-响应,就用真正的请求-响应。
  • 模式混乱:生产者未经协调就修改事件载荷,消费者静默出错。
  • 没有重放策略:关键事件丢失后无法恢复。应有意识地选择代理的保留策略。
  • 12 步工作流使用协同:没人能理清整体,应升级为编排。

相关主题

  • 微服务架构:事件驱动是微服务常见通信风格之一(另一种是 REST/gRPC)。
  • Saga:通过事件/命令编排分布式事务。
  • 事件溯源:事件是状态的事实来源,而不仅是通信机制。
  • CQRS:常与 EDA 搭配,写入产生事件,读取从事件派生的物化视图投影。
  • 领域事件:模型层面的事件概念,常成为线上传输的事件。

参考资料

  • Richards & Ford, Fundamentals of Software Architecture, 第 14 章(Event-Driven Architecture Style)。
  • Adam Bellemare, Building Event-Driven Microservices(O'Reilly)。
  • Khononov, Learning DDD, 第 15 章(Event-Driven Architecture)。