软件架构-事件驱动架构

本文涉及的产品
日志服务 SLS,月写入数据量 50GB 1个月
简介: 事件驱动架构是一种系统或组件之间通过发送事件和响应事件彼此交互的架构风格。

image.png

你好,我是看山。


本文源自并发编程网的翻译邀请,翻译的是 Jakob Jenkov 的 《软件架构》 中关于事件驱动的内容,虽然是 2014 年的文章,但是从软件架构层面上,并不过时。


以下是正文。


事件驱动架构是一种系统或组件之间通过发送事件和响应事件彼此交互的架构风格。当某个事件发生时,组件A不直接调用组件B,而只是发出一个事件。组件A不知道哪些组件监听并处理这些事件。事件驱动架构可以在进程内和进程间使用。比如,GUI框架中会大量使用事件驱动。【译者注:目前很多系统采用微服务架构,事件驱动使用的更加广泛了。】此外,正如我在并发模型教程 中所提到的,装配线并发模型(AKA reactive,非阻塞并发模型)也使用了事件驱动架构。


本文主要介绍进程之间的事件驱动架构,后文提到这个词的时候也是指进程交互方式。


进程间的事件驱动架构

事件驱动架构是一种架构风格,先将请求事件集中存放在一个或多个事件队列中,然后事件从这些事件队列转发到后端服务,处理这些事件。


因为事件可以被看做是消息流,所以事件驱动架构也被称为消息驱动架构或者流处理架构。流处理架构又可以被称为lambda架构。为了保证统一,后文会继续使用事件驱动这个名词。


事件队列

在事件驱动架构中,你会有一个或多个集中的事件队列,所有的事件被处理前,会先保存在集中的事件队列中。下面给出一个简单示例:


image.png


事件插入队列时是有序的,这样就可以顺序处理这些事件。


事件日志

写入事件队列时,消息可能写入到事件日志(通常是磁盘存储)中。如果发生系统崩溃,系统只需要重放事件日志即可恢复到崩溃前的状态。下面是一个事件驱动架构的示例,其中包括一个用于持久化事件的事件日志:


image.png


我们还可以通过备份事件日志,来备份系统状态。在将新版本的系统部署在生产环境之前,可以使用这个备份数据对其性能进行测试。或者,通过重放事件日志的备份,来重现某些错误。


事件收集器

请求都是通过网络传输,比如HTTP或者其他协议。为了保持一致,可以通过事件采集器接收来自不同来源的事件。下面是一个添加了事件收集器的事件驱动架构示例:


image.png


响应队列

有时,我们还需要向请求(即事件)返回响应,所以,很多事件驱动架构除了包含事件队列,还会有一个响应队列。下面是包含事件队列(入队队列)和响应队列(出队队列)的事件驱动架构示例:


image.png


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


通常,响应队列不会持久化,也就意味着它不会写入事件日志,只有输入的事件才会持久化到事件日志中。


读事件 vs. 写事件

如果将所有传入的请求都认为是事件,就需要将这些事件都推送到事件队列中。如果事件队列是实现了持久化(持久化到事件日志中),就意味着所有事件都需要持久化。通常持久化都比较慢,如果我们能够过滤掉一些不需要持久化的事件,我们就能够提升队列的性能。


我们将事件持久化到事件日志的原因是,我们可以重放事件日志,并重建因为事件引起的系统状态变化。为了支持这个特性,实际上只需要持久化更改系统状态的事件。换句话说,我们只需要将事件分为读事件和写事件。读事件只读取系统数据,不会更改,写事件会更改系统数据。


通过根据读和写划分事件,我们只需要持久化写事件的消息即可。这将提升事件队列的性能,提升比例大小,取决于读写事件之间的比例。


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


还可以将事件队列拆分为两个,一个用于存储读事件的事件队列,一个用于存储写事件的事件队列。这样读事件就不会慢于写事件,事件队列也不需要检查每条事件是否需要持久化。读事件队列不需要进行持久化,写事件队列始终持久化事件。


下面是一个事件驱动架构的示例,其中事件队列分为读和写事件队列:


image.png


上图示例中箭头比较乱,但实际上创建3个丢列并在它们之间分发消息简单很多。


事件日志重放的挑战

事件驱动架构的一大优点是,在系统崩溃或系统重启情况下,只需要重放事件日志,就能够重建系统状态。在日志可以独立于时间和周边系统的情况下重放日志,这是一个很大的优势。


但是,完全独立于时间重放事件日志有时候很难实现。接下来介绍下事件日志重放的一些挑战。


处理动态数据

如前所述,写事件处理时可能会修改系统数据。有些情况,这种数据的修改受事件处理时动态数据的影响。比如,处理事件的日期和时间或者特定日期和时间的货币汇率。


这些动态数据会对事件重放造成困难。如果在不同的时间重放事件日志,处理该事件的服务可能会解析不同的动态值,比如其他的日期和时间或其他汇率。因此,在不同的日期重放事件日志,可能会出现重建系统数据与最初处理事件产生的数据不一致。


要解决动态数据的问题,可以让写事件队列将所需的动态数据标记在事件中。但是,要实现这种方案,需要事件队列知道每条事件消息需要哪些动态数据。这样会使事件队列的设计复杂化,每次需要新的动态数据时,事件队列都需要知道如何查找这些动态数据。


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


与外部系统的交互

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


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


事件日志重放解决方案

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


重放模式

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


多步骤事件队列

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



相关实践学习
日志服务之使用Nginx模式采集日志
本文介绍如何通过日志服务控制台创建Nginx模式的Logtail配置快速采集Nginx日志并进行多维度分析。
目录
相关文章
|
26天前
|
设计模式 开发框架 前端开发
在开发框架中实现事件驱动架构
【9月更文挑战第2天】事件驱动架构(EDA)通过事件机制让组件间解耦交互,适用于动态扩展和高响应性的系统。本文提供一个基于Beego框架实现事件驱动的示例,通过事件管理器注册和触发事件,实现用户注册和登录时的不同处理逻辑,展示了其在Web应用中的灵活性和高效性。
61 5
|
1月前
|
弹性计算 监控 数据挖掘
事件驱动架构的优势与应用:深度解析与实战应用
【8月更文挑战第17天】事件驱动架构以其松耦合、可扩展性、异步处理、实时性和高可靠性等优势,在实时数据处理、复杂业务流程、弹性伸缩和实时通信等多个领域展现出巨大的应用潜力。通过合理应用事件驱动架构,可以构建灵活、可扩展和可维护的系统架构,满足不断变化的业务需求和技术挑战。对于开发者而言,深入理解事件驱动架构的核心概念和优势,将有助于更好地设计和实现高质量的软件系统。
|
28天前
|
消息中间件 Kafka Java
Spring 框架与 Kafka 联姻,竟引发软件世界的革命风暴!事件驱动架构震撼登场!
【8月更文挑战第31天】《Spring 框架与 Kafka 集成:实现事件驱动架构》介绍如何利用 Spring 框架的强大功能与 Kafka 分布式流平台结合,构建灵活且可扩展的事件驱动系统。通过添加 Spring Kafka 依赖并配置 Kafka 连接信息,可以轻松实现消息的生产和消费。文中详细展示了如何设置 `KafkaTemplate`、`ProducerFactory` 和 `ConsumerFactory`,并通过示例代码说明了生产者发送消息及消费者接收消息的具体实现。这一组合为构建高效可靠的分布式应用程序提供了有力支持。
85 0
|
1月前
|
消息中间件 缓存 Kafka
混合云中的事件驱动架构
混合云中的事件驱动架构
31 4
|
2月前
|
人工智能 供应链 架构师
软件架构一致性问题之Serverless架构处理架构一致性问题如何解决
软件架构一致性问题之Serverless架构处理架构一致性问题如何解决
46 2
|
2月前
|
消息中间件 监控 Java
在Java项目中实现事件驱动架构
在Java项目中实现事件驱动架构
|
2月前
|
消息中间件 监控 Java
使用Kafka实现分布式事件驱动架构
使用Kafka实现分布式事件驱动架构
|
3天前
|
安全 应用服务中间件 API
微服务分布式系统架构之zookeeper与dubbo-2
微服务分布式系统架构之zookeeper与dubbo-2
|
3天前
|
负载均衡 Java 应用服务中间件
微服务分布式系统架构之zookeeper与dubbor-1
微服务分布式系统架构之zookeeper与dubbor-1
|
30天前
|
Kubernetes Cloud Native Docker
云原生之旅:从容器到微服务的架构演变
【8月更文挑战第29天】在数字化时代的浪潮下,云原生技术以其灵活性、可扩展性和弹性管理成为企业数字化转型的关键。本文将通过浅显易懂的语言和生动的比喻,带领读者了解云原生的基本概念,探索容器化技术的奥秘,并深入微服务架构的世界。我们将一起见证代码如何转化为现实中的服务,实现快速迭代和高效部署。无论你是初学者还是有经验的开发者,这篇文章都会为你打开一扇通往云原生世界的大门。

热门文章

最新文章