首页 > 编程知识 正文

事件驱动控制器,事件驱动的工作模式注意事项

时间:2023-05-03 11:40:20 阅读:142010 作者:4617

你好,我在看山。

本文基于来自并发编程网络的翻译请求,该网络翻译了Jakob Jenkov的《软件架构》事件驱动相关内容。 虽然是2014年的文章,但是在软件架构层面上,不会花太多时间。

以下是正文。

事件驱动体系结构是一种通过在系统或组件之间发送事件并响应事件来进行交互的体系结构样式。 当某个事件发生时,组件a不会直接调用组件b,而是只发布一个事件。 组件a不知道哪个组件接收和处理这些事件。 事件驱动体系结构可以在进程内和进程之间使用。 例如,GUI框架大量使用事件驱动。 【译者注:目前大多数系统采用微服务器架构,事件驱动的使用更为广泛。 】此外,正如并发模型教程中所述,装配线并发模型(AKA reactive,无阻塞并发模型)也使用事件驱动架构。

本文主要介绍了过程之间的事件驱动体系结构,后面提到这个词也是指过程的交互方式。

跨进程事件驱动体系结构事件驱动体系结构是一种将请求事件组织到一个或多个事件队列中,然后将事件从这些事件队列传输到后端服务进行处理的体系结构样式。

事件驱动体系结构也称为消息驱动体系结构或流处理体系结构,因为可以将事件视为消息流。 流处理架构也称为lambda架构。 为了保证统一,后文继续使用事件驱动这一名词。

事件队列是一种事件驱动体系结构,它具有一个或多个集中式事件队列,在处理所有事件之前存储在集中式事件队列中。 以下是一个简单的例子。

事件将插入队列中,以便可以按顺序处理。

当事件日志写入事件队列时,消息可能会写入事件日志,通常会写入磁盘存储。 如果发生系统崩溃,只需播放事件日志就可以恢复到崩溃前的状态。 以下是包含持久性事件事件日志的事件驱动体系结构示例:

还可以通过备份事件日志来备份系统状态。 在将新系统版本部署到生产环境之前,可以使用此备份数据测试性能。 或者,播放事件日志的备份,以再现一些错误。

事件收集器请求通过网络(如HTTP或其他协议)传输。 为了保持一致,可以使用事件收集器从各种源接收事件。 以下是添加了事件收集器的事件驱动体系结构的示例。

许多事件驱动体系结构除了事件队列外还具有响应队列,因为响应队列可能需要对请求或事件进行响应。 以下是一个包括事件队列(入队)和响应队列的事件驱动体系结构示例。

如您所见,响应队列必须路由到正确的事件收集器。 例如,如果HTTP收集器(本质上是web服务器)通过HTTP将接收到的请求发送到事件队列,则事件生成的响应也必须通过HTTP收集器发送回客户端。

通常,响应队列不会持久化。 这意味着不会写入事件日志,而是仅将输入的事件永久保存在事件日志中。

阅读事件如果要将编写vs .事件的所有传入请求都视为事件,则必须将这些事件推入事件队列。 如果事件队列持久化(永久化为事件日志),则意味着所有事件都必须持久化。 通常,持久化很慢,如果可以过滤不需要持久化的事件,就可以提高队列性能。

使事件持久化为事件日志的原因是可以播放事件日志,并重建事件引起的系统状态更改。 为了支持此特性,实际上只需将改变系统状态的事件持久化即可。 这意味着您只需将事件分为读取和写入。 读取事件只读取系统数据,没有变化。 写入事件更改系统数据。

通过基于读写来分割事件,使事件的消息持久化即可。 这样可以根据读写事件之间的比例提高事件队列的性能,并提高缩放比例。

要将事件拆分为读/写事件,必须在事件到达事件队列之前,即在事件收集器中进行区分。 否则,事件队列就无法知道到达的事件是否需要持久化。

也可以将事件队列拆分为两个事件队列:用于存储读取事件的事件队列和用于存储写入事件的事件队列。 这样,阅读事件就不会比写事件慢。 此外,事件队列也不需要检查每个事件是否需要持久化。 读取事件队列不需要持久化,而写入事件队列总是使事件持久化。

以下是一个分为读取和写入事件队列的事件驱动体系结构示例。

在上图的示例中,箭头很乱,但实际上创建三个下拉列并在它们之间分发消息很简单。

事件日志播放挑战事件驱动体系结构的一个重要优点是,如果系统崩溃或系统重新启动,只需播放事件日志即可重建系统状态。 能够独立于时间和外围系统播放日志是一大优势。

但是,有时很难完全独立于时间播放事件日志。 接下来,我们将讨论事件日志播放的几个挑战。

处理动态数据如上所述,写入事件处理可能会更改系统数据。 在一些情况下,这种数据改变受到事件处理时的动态数据的影响。 例如,处理事件的日期和时间或特定日期和时间的货币汇率。

这些动态数据会给事件的播放带来困难。 在不同的时间播放事件日志时,处理事件的服务可能会解析不同的动态值,如其他日期和时间或其他汇率。 因此,如果在不同的日期播放事件日志,重建的系统数据可能与首次处理事件时生成的数据不匹配。

要解决动态数据问题,可以将写入事件队列中所需的动态数据标记为事件。 但是,要实现这种方案,事件队列必须知道所有的事情

件消息需要哪些动态数据。这样会使事件队列的设计复杂化,每次需要新的动态数据时,事件队列都需要知道如何查找这些动态数据。

另外一种解决方案是,写事件队列只在写事件上标记事件的日期和时间。使用事件的原始日期和时间,处理事件的服务可以查找给定日期和时间对应的动态数据。比如,可以通过原始的日期和时间,查询当时有效的汇率。这就要求处理事件的服务需要基于日期和时间查询动态数据,但是这只是理想状态。

与外部系统的交互

事件日志重放的另一个挑战是与外部系统的协调。比如,事件日志中包含电商平台的订单,在第一次处理这个事件时,需要将订单发送到外部支付网关,以从客户信用卡中收费。

如果重放事件日志,就不希望再次为同一个订单向客户收费。因此,就不希望在事件重放时,将订单发送到外部支付网关。

事件日志重放解决方案

解决重放事件日志问题挺不容易的。有些系统没有问题,可以直接重放事件日志;有些系统可能需要知道原始事件的日期和时间;有些系统可能需要知道更多类似于事件原始处理过程中从外部系统获取的原始数据。

重放模式

在任何情况下,倾听写事件队列中事件的任何服务都必须知道传入事件是原始事件还是重放事件。这样,处理服务就能够确定如何处理动态数据或者如何与外部系统交互了。

多步骤事件队列

另外一个解决方案是采用多步骤事件队列。第一步,收集所有写事件;第二步,解析动态数据;第三步,与外部系统交互。如果需要重放事件日志,只需要跳过第一步和第二步,重放第三步即可。具体如何实现,需要取决于具体的系统设计。

你好,我是看山,公众号:看山的小屋,10 年老后端,Apache Storm、WxJava、Cynomys 开源贡献者。主业:程序猿,兼职:架构师。游于码界,戏享人生。

原文链接:Event-driven Architecture
翻译: https://www.howardliu.cn
译文链接: 软件架构-事件驱动架构
CSDN主页: http://blog.csdn.net/liuxinghao
CSDN博文: 软件架构-事件驱动架构

版权声明:该文观点仅代表作者本人。处理文章:请发送邮件至 三1五14八八95#扣扣.com 举报,一经查实,本站将立刻删除。