您还未登录! 登录 | 注册 | 帮助  

您的位置: 首页 > 软件开发专栏 > 开发技术 > 正文

现代软件架构:事件驱动设计遇上事件溯源

发表于:2023-12-13 作者:小技术君 来源:小技术君

在当今的软件领域中,做出正确的架构决策对于确保性能、可扩展性、可维护性和整体成功至关重要。在众多模式中,事件驱动架构(EDA)和事件溯源(ES)作为复杂软件系统最受欢迎的两种选择之一。虽然可以单独使用EDA或ES,但它们的结合可能效果惊人。

事件驱动架构与传统的请求驱动系统相对立,传统系统中组件通过紧密耦合的方式显式调用彼此的方法或直接使用同步的API调用。在事件驱动架构中,组件通过事件间接通信,松耦合,促进灵活性、可扩展性和模块化。

事件溯源,另一个强大的设计模式也利用事件,强调维护事件的时间顺序记录,以实现更好的审计、分析和历史跟踪。事件溯源的主要理念是最终一致性。

让我们来详细了解它们,并看看如何将它们结合起来,构建一个适合我们使用案例的可扩展架构,有效服务数百万客户来自数千商家。

事件驱动架构解释

事件驱动架构关注系统中事件的流动和处理。事件代表重要的事件或状态变化,在不同组件之间通信的骨干。在事件驱动系统中,组件(如微服务或函数)通过生成、检测和消费事件进行异步通信。这种方法促进了松耦合,允许灵活性、可扩展性,并对动态变化作出响应。EDA特别适用于分布式系统,在这些系统中,组件可以独立操作,在无需直接同步交互的情况下实时对事件做出反应。

EDA的常见使用案例:

1.可扩展的异步处理,即工作器

通过消息代理实现可扩展的异步处理

在任务数量庞大且具有异步处理灵活性的场景中,此配置极具扩展性。在服务A中,组件X生成消息,并将其发布到消息代理(即事件代理)。随后,这些消息根据需要被许多消费者(称为工作器)订阅和处理。事件的来源可能包括cron作业、用户交互和类似来源。

在传统系统中,任务通常按顺序处理,或者在支持的堆栈中通过多线程支持。然而,即使有多线程支持,只有垂直扩展是可行的选项。

2.消息队列

消息队列

这是上述异步处理的一种变体,但是工作器现在位于另一个服务中。这使得服务B能够在事件数量增加时无缝扩展。到达服务B的事件可能来自不同的服务。

这可用于由服务B负责同时处理大量小任务的体系结构,例如向移动设备提供大量推送通知或短信通知。

3.跨领域通信

这是EDA的更高级版本,系统的多个组件可能对同一消息感兴趣,也可能不感兴趣。因此,复杂性更多地在代理端,事件通过不同的绑定路由到不同的服务。

跨领域通信

上图展示了一个示例设置,其中服务A的事件通过不同的队列路由到服务B和C。请注意,我在这里使用了RabbitMQ的术语:联邦、交换和虚拟主机。但是,这个设置也可以使用其他消息代理来完成。

事件溯源与CQRS

在传统的以数据库为中心的方法中,我们通常存储实体的当前状态。相比之下,事件溯源将焦点从存储应用程序的当前状态转移到捕获并存储对该状态的更改的一系列不可变事件。这些事件表示系统中特定的事件或事务,并存储在事件日志或事件存储中。

1.关键概念

  • 事件: 表示系统中状态更改的不可变记录。事件捕获发生了什么,而不是当前状态。
  • 事件存储: 专门的数据存储,维护事件的时间顺序序列。这允许通过重新播放事件轻松重建系统在任何时间点的状态。
  • 聚合: 将相关事件分组的一致性单元。聚合负责执行业务规则和维护数据完整性。

很多情况下,事件溯源与CQRS结合使用。这将读模型(查询模型)和写模型(命令模型)分开,以实现关注点的分离。在此结合时,还有两个事件溯源的重要概念:

2.读模型

专门用于查询和呈现数据的模型。它对读取操作进行了优化,并根据写模型生成的事件构建。读模型是去规范化的,并根据其服务的查询需求定制。从相同的事件源,可以构建不同视图的读模型,为业务领域提供不同的视角。

3.映射

根据事件存储中存储的事件转换和更新读模型的过程。

事件溯源与CQRS

在此设置中,事件被填充以记录由业务流程引起的聚合的每个状态,并存储在事件存储中。随后,投影从事件存储中检索这些事件,并开始将它们转换为各种读表。这些表可以以不同的视图呈现,为业务用户提供不同的可视化效果。需要强调的是,尽管拉取事件是一种选择,但投影还可以通过使用消息代理利用发布/订阅模式,订阅新事件。

这种设置通过捕获事件的时间顺序序列增强了系统的韧性,为全面的审计跟踪提供了全面的记录。因此,该方法允许进行有效的时间查询,使应用程序在任何给定时间点都可以重建状态。此外,它通过将数据模型变更与历史事件日志分开,为业务需求的变化提供了灵活性。

结合CQRS,该机制促进了命令和查询职责之间的松耦合,提供了韧性和灵活性。

将事件驱动架构和事件溯源结合

如上所述,EDA和ES都为可扩展性和协作提供了非常强大的方式。EDA强调通过事件松耦合通信的组件,而ES捕获并持久化状态变更的历史记录。因此,如果我们使用ES生成的事件并将其用于EDA,那将是一个自然的组合。

生成的事件不仅可以包含变更的状态,还可以包含变更的详细信息。然后,这些事件可以通过消息代理传输到另一个服务/组件,并在EDA中被消费。

事件溯源和事件驱动设计的结合

上图显示了如何以一种非常直接的方式将ES和EDA结合起来。来自事件存储的事件可以通过消息代理发布和被不同的服务和组件消费。

结合EDA和ES的优势

将事件驱动架构(EDA)与事件溯源(ES)结合带来了显著的优势。其中一个主要优势是系统的响应能力提升。这种设置允许系统快速适应实时变化,在动态环境中效率极高。

另一个关键优势是对状态变更的全面历史记录,有助于详细的历史分析,并确保符合规范的强大审计跟踪。此外,其不可变和可重播的特性使得实时分析、可扩展性和适应不断变化的分析需求变得更加容易。事件还可以流式传输到数据分析流水线或复制到数据湖进行进一步处理。

此外,这种组合固有的灵活性和可扩展性也值得注意。系统可以轻松演变以满足不断增长的业务需求,确保长期的可持续性和适应性。

最后,系统的韧性也是一个值得关注的优点。这种设置提供了强大的机制来恢复中断,确保即使在具有挑战性的情况下也能保持连续性和可靠性。

应对挑战

将事件溯源(Event Sourcing)和事件驱动架构(EDA)相结合引入了一系列挑战,包括协调分布式系统、确保可扩展和高性能的事件存储,以及管理模式演进。

  • 首先,在分布式环境中协调多个微服务的交互引入了一些复杂性,维护正确的事件顺序和系统一致性变得复杂。需要精心设计事件流和协调机制,以防止出现事件重复或跨服务的乱序处理等问题。
  • 其次,事件存储的可扩展性和性能是关键挑战。事件溯源依赖于不可变事件,而事件驱动架构依赖于服务之间高效的事件通信。确保事件存储基础设施的耐久性和可靠性变得至关重要,特别是在事件在网络中产生和消费的分布式环境中,这对于维持系统的响应能力尤为重要。
  • 第三,解决模式演进和版本控制至关重要。随着系统的演变,与事件相关的数据模式可能会发生变化。在保持历史事件完整性的同时平衡向后和向前兼容性是一项挑战。实施有效的版本控制策略对于避免事件消费者可能根据不同模式版本处理事件的问题至关重要。要克服这些挑战,需要深思熟虑的设计和技术选择,创建基于事件溯源和事件驱动架构的弹性和可扩展的架构。
  • 最后,但同样重要的是,操作这种架构并不容易。监控和管理结合了EDA和ES的系统需要新的运营实践。确保在生产环境中系统的可用性、可靠性和性能可能具有挑战性。操作消息代理也需要特定的专业知识。我们需要了解所使用的消息代理的优缺点和最佳实践。

最终思考

尽管存在这些挑战,将事件驱动架构和事件溯源相融合是一种强大的方法,当得到良好管理时,它提供了一种动态且强大的架构。在设计和实施阶段解决这些挑战对于充分发挥这种组合架构策略的潜力至关重要。