EDA事件驱动架构具有什么特点和优缺点?
扫描二维码
随时随地手机看文章
随着互联网和移动互联网的快速发展,越来越多的应用程序需要处理海量数据和大量的并发请求。传统的软件架构已经无法满足这些需求,因此,一些新的架构模式开始受到关注。其中,事件驱动架构(Event-Driven Architecture,EDA)因其高效、可扩展和灵活等优点,逐渐成为热门的选择。本文将探讨事件驱动架构在实际应用中的优势和挑战。
一、事件驱动架构的概述
事件驱动架构是一种基于事件和消息的软件架构模式,其核心思想是将应用程序设计为响应事件的系统。在这种架构中,事件是系统中发生的某种事情,可以是用户行为、设备状态变化等。当事件发生时,系统会产生相应的消息,该消息会被传递给感兴趣的组件进行处理。组件可以是其他应用程序、服务或者处理器等,它们通过订阅消息的方式来接收事件。
事件驱动架构与传统的请求响应模式相比,最大的不同在于处理方式。传统的请求响应模式是基于事务的,即客户端发起请求,服务端进行处理并返回响应。而事件驱动架构是基于消息的,即系统会在事件发生时异步地发送消息给感兴趣的组件进行处理。这种异步的处理方式可以使系统更加灵活、可扩展和高效。
二、事件驱动架构的优势
1. 可扩展性
事件驱动架构是一种高度可扩展的架构模式。由于事件是异步的,不同的事件可以由不同的组件进行处理。因此,可以根据应用程序的需求,动态地添加或删除组件,以实现系统的可扩展性。
2. 高效性
事件驱动架构可以提高系统的处理效率。由于事件是异步的,组件可以在事件发生时立即进行处理,而不需要等待请求的响应。这种异步的处理方式可以提高系统的响应速度和吞吐量。
当类或组件之间内聚性很高,它们的耦合度应该很低,也就是说当组件需要相互协作调用时,比如我们假设一个组件“A”需要触发组件“B”中的一些逻辑,自然的方式是直接让组件A调用组件B中的一个方法。但前提是A必须知道B的存在,这样它们之间就是耦合的,A必须依赖于B了,这会使得系统更难以改变和维护。因此,这里可以使用事件来防止这种直接调用的耦合。
此外,使用事件实现组件解耦也有其另外的,如果我们有一个只负责组件B的工作团队,那么他们则可能不需要与负责组件A的团队进行交流,直接针对组件A中的逻辑改变在组件B中做出相对反应。两个组件团队可以独立发展(banq注:微服务特点之一), 我们的应用系统变得更灵活。
即使在同一个组件团队中,有时候我们不需要在同一请求/响应中立即执行一个动作的结果,只要异步执行这个动作,比如发送电子邮件。在这种情况下,我们可以立即向用户返回响应,并以异步方式发送电子邮件,并避免让用户等待发送电子邮件。
不过,如果我们不加区别地使用它,也有危险。我们会遇到逻辑流程的风险,这些逻辑流程在概念上是高度凝聚力的,但是通过采取脱钩机制的事件连接在一起。换句话说,应该在一起的代码将被分开,并且难以跟踪它的流程(类似于goto语句),不易于理解:可能是意大利面一样混在一起!
为了防止将我们的代码库变成一大堆意大利面条,我们应该将事件的使用限制在明确的情况下。根据我的经验,有三种使用事件的情况:
(1)去耦组件
(2)执行异步任务
(3)跟踪状态变化(审核日志)
1.去耦组件(微服务)
当组件A执行的逻辑需要触发组件B的逻辑时,不要直接调用它,我们可以将触发事件发送到事件分派器。组件B将侦听调度程序中的特定事件,并在事件发生时执行操作。
这意味着A和B都将取决于调度器和事件,但他们之间将不会知道对方存在,它们将被解耦。
理想情况下,调度员和事件都不应该在两个组件之间存在:
(1)调度员应该是完全独立于我们应用程序的库,因此使用依赖管理系统安装在通用位置。在PHP世界中,这是使用Composer等安装在vendor文件夹中的东西。
(2) 事件是我们的应用程序的一部分,应该在两个组件之间生存,组件之间通过事件进行通讯(结构上解耦,行为上耦合)。事件在组件之间共享,它是应用程序的核心部分。事件在DDD中属于共享内核Shared Kernel的一部分。这样,两个组件都将依赖于共享内核,但彼此不会意识到。然而在单体Monolithic应用程序中,为方便起见,可以将其放在触发事件的组件中。
DDD共享内核
[。..]明确界定指定团队同意分享的领域模型的一些子集。保持这个内核很小。[。..]这个明确共享的东西有特殊的地位,如果没有与其他团队协商,不应该改变。
Eric Evans 2014, 领域驱动设计参考
2.执行异步任务
有时候我们有一个我们想要执行的逻辑,但它可能需要相当长的时间来执行,我们不想让用户等待它完成。在这种情况下,希望将其作为异步工作运行,并立即返回给用户的消息,通知他请求将在以后异步执行。
例如,在网上商店下订单可以同步完成,但发送通知用户的电子邮件可以进行异步。
在这种情况下,我们可以做的是触发一个将被排队的事件,直到一个工作任务可以获得这个事件并执行它,只要系统有资源。
在这些情况下,相关联的逻辑是否在相同的有界环境中并不重要,无论哪种方式,逻辑都是去耦的。
3.跟踪状态变化(审计日志)
以传统的数据存储方式,我们拥有一些数据的实体。当这些实体中的数据发生变化时,我们只需更新数据库表行以反映新值。
这里的问题是,我们并不存储这些值为什么改变且什么时候改变。
我们可以将这些改变的事件存储在审计日志中。
更多关于这个进一步的前景,在关于事件溯源的解释。
事件模式
Martin Fowler确定了三种不同类型的事件模式:
(1)事件通知
(2)事件执行状态转移
(3)事件溯源Event Sourcing
所有这些模式共享相同的关键概念:
(1)事件是代表发生了一些事情(发生在某事之后);
(2)事件被广播到正在监听的任何代码(代码可以对事件做出反应)。
一。 事件通知
假设我们有一个具有明确定义的组件作为应用程序核心。理想情况下,这些组件是完全相互分离的,但是它们的一些功能需要在其他组件中执行一些逻辑。
最典型的情况如前所述:当组件A执行的逻辑需要触发组件B的逻辑时,A不是直接去调用B,而是触发事件将且发送到事件调度程序。组件B将侦听调度程序中的特定事件,并在事件发生时执行操作。
重要的是,这种模式的一个特征是事件携带最少的数据。它只为听众提供足够的数据,以便知道发生了什么并执行其代码,通常只是实体ID,也可能是事件创建的日期和时间。
优点
(1)弹性更大:将事件排队后,发送方组件可以继续执行其自己逻辑,即使由于错误发生,因为它们排队等候,它们可以在错误被修复时被执行。
(2)降低延迟,如果事件排队,用户不需要等待该逻辑执行;
团队可以独立发展组件,使他们的工作更轻松,更快,更容易出现问题,更灵活;
缺点
(1)如果没有使用标准,有可能变成一堆意大利面条代码。
二。 事件执行状态转移
让我们再次看看前面例子,一个具有明确定义的组件作为应用程序核心。如果A组件一些功能需要来自其他组件的数据。获得该数据的最自然的方法是询问其他组件,但这意味着被查询组件必须提供查询方法以供查询组件使用,一次两次修改增加无所谓,如果频繁要求被查询组件提供新的查询方法,说明这两个组件彼此耦合!
在组件之间共享数据的另一种方法是:拥有数据的组件触发的更改事件时,该事件将携带全新更改后的数据。对该数据感兴趣的组件将会监听这些事件,从事件中获得数据并存储该数据的本地副本,然后进一步对这些全新数据做出反应。这样,当他们需要外部数据时,他们其实在本地已经拥有它们,它们将不需要查询其他组件,也不需要其他组件提供对应的查询方法。
单体架构
如果使用最早的单体架构部署,作为最传统的应用部署模式,是将整个应用程序作为一个单一的、紧密耦合的单元进行开发和部署。
在这种情况下,MP4文件转换为WMV格式的功能将作为应用程序的一部分实现。整个应用程序在一个部署单元中运行,包括处理用户界面、业务逻辑和数据访问等功能。
遇到问题
使用这种模式,问题非常明显,虽然部署简单,但会导致代码和功能之间的紧密耦合,遇到局部bug会影响整个应用功能运行,可伸缩性受限,整个应用程序需要按照最高负载需求进行伸缩,而不仅仅是转换文件的功能。这可能导致资源浪费和低效的资源利用,另外也会存在单点故障问题,如果应用程序的某个组件出现故障,整个应用程序都会受到影响。
在单体架构中,所有的功能模块都被打包在一起,共享同一个数据库和用户界面。单体架构在早期的软件开发中非常常见,因为它简单、易于理解和实现,但受限于可扩展、可维护性、高可用性等问题,单体架构逐渐被时代淘汰。
容器技术/微服务
为了解决单体架构存在问题,容器技术孕育而生,直至docker容器技术出现,行业改变了以往的架构模式。
从过去以物理机和虚拟机为主体的开发运维环境,向以容器为核心的基础设施的转变过程,这并不是一次温和的改革,而是涵盖了对网络、存储、调度、操作系统、分布式原理等各个方面的容器化理解和改造。
容器技术发展彻底释放了微服务天性,在单体架构部署存在的问题,在微服务架构中,应用程序被拆分为多个小型、独立部署的服务,每个服务专注于一个特定的功能。对于MP4文件转换为WMV格式的过程,可以将其作为一个单独的转换服务实现,甚至可以根据转换过程进一步拆分,实现更精细化管理,每个服务可以独立部署和伸缩,提供更好的灵活性和可扩展性,服务之间都是独立的,可以独立开发、测试、扩展和部署。
遇到问题
随之而来地系统复杂性增加,微服务架构引入了分布式系统的复杂性,包括服务之间的通信、数据一致性和故障处理等方面。
部署和管理成本增加,管理多个服务的部署和运维需要更多的工作和资源。
企业需求
对于企业,如果希望既要实现高效、可伸缩、高可用等功能,同时提高团队人员效率,开发者可以专注于编写业务逻辑,而无需担心服务器的配置、扩展或管理。
还是之前“MP4文件转换为WMV格式存储到数据”例子中,如何实现开发者可以专注于编写业务逻辑,而无需担心服务器的配置、扩展或管理问题?
可以通过两个步骤来了解:
1、Serverless服务
2、事件驱动架构(EDA)
Serverless在基础设施端解决运维困扰
在Serverless计算服务中,开发人员只需关注应用程序的业务逻辑,云服务提供商将负责管理和调配计算资源,平台根据需求自动扩展计算资源,以适应变化的工作负载,同时按使用付费,根据实际使用的计算资源付费,避免了长期维护和不必要的成本。
EDA让开发者可以专注于编写业务逻辑使用事件驱动架构
使用EDA架构来实现将MP4文件转换为WMV格式的过程可以提供一种高度可扩展和灵活的方式。