• home > webfront > engineer > Architecture >

    事件驱动型架构:从EDA原理剖析其优劣

    Author:zhoulujun Date:

    什么是事件驱动型架构(EDA)事件驱动架构(Event-Driven Architecture,简称EDA)是一种用于应用设计的软件架构和模型。事件驱动系统旨在


    什么是事件驱动型架构(EDA)

    事件驱动架构(Event-Driven Architecture,简称EDA)是一种用于应用设计的软件架构和模型。

    事件驱动系统旨在捕获、沟通和处理解耦服务之间的事件。这意味着,系统可以保持异步,同时仍共享信息和完成任务。 

    在事件驱动架构中,系统中的各个部分可以产生、发布、捕获和响应事件

    什么是事件?

    事件用于记录系统硬件或软件的任何重要事件或状态变更

    事件与事件通知不同

    • 事件通知是由系统发送的消息或通知,用于通知系统的另一方发生了事件。

    • 事件是系统中发生的有意义的事情源可能来自于内部输入,也可能是外部输入。事件可以由用户生成,例如单击鼠标或按键;也可以是外部来源,例如传感器输出;或来自于系统,例如加载程序。

    解耦与松散耦合

    解耦与松散耦合指的是软件架构和事件驱动系统中两个相关但不同的概念。

    • 解耦是消除或最小化系统中独立组件之间的直接依赖关系的做法,以便组件之间不存在“唇亡齿寒”的关系。在 EDA 的语境下,通过确保生成事件的组件只需发送事件数据,而不必考虑特定的使用者组件,从而实现解耦。这种“断联”使组件彼此独立,创造出总体更灵活的系统。

    • 松散耦合是一种特定形式的解耦,旨在降低组件之间的相互依赖的程度,而不是将它们完全分离开。在松散耦合的系统中,组件可能会彼此交互,但不会导致形成任何形式的依赖关系。

    这两种系统都有利于提高灵活性和独立性,进而创造出敏捷且可扩展的系统。

    事件驱动型架构是一种现代架构模式,由发布、使用或路由事件的小型解耦服务构建而成。

    与传统的请求驱动模型不同,EDA 促进了产生器和使用器服务之间的松耦合。这样就可以更加轻松地扩展、更新和独立部署系统的单独组件

    事件驱动架构的工作原理

    事件驱动架构由事件发起者(发布者)和事件使用者(订阅者)组成。事件发起者检测或感知事件,并以消息的形式呈现事件。由于是解耦系统,它不知道事件的使用者,也不知道事件的结果。

    检测到事件后,将从事件发起者通过事件通道将事件传输给事件使用者,在事件通道中,事件处理平台会异步处理事件。发生事件时,需要通知事件使用者。他们可能会处理事件,也可能只是会受到事件影响。

    事件处理平台将执行正确的事件响应,并将活动发送给下游正确的使用者。该下游活动即看到事件结果的位置。

    Apache Kafka 是一个分布式数据流平台,是备受欢迎的事件处理解决方案。它能够实时处理事件流的发布、订阅、存储和处理。Apache Kafka 支持各种重视高吞吐量和可扩展性的用例,通过最大程度减少某些应用中对数据共享的点对点集成需求,因而可以将延迟降至毫秒级。

    除此之外,还有其他一些中间件事件管理器也可用作事件处理平台。

    事件驱动经常使用在I/O框架中,可以很好的实现I/O复用。很多高性能的I/O框架都是使用事件驱动模型的,例如:Netty、Mina、Node.js。


    事件驱动架构模型

    事件驱动架构模型如下:

    • 事件生产者:产生一连串的事件,也叫事件源;如界面上的按钮是一个事件源,能够产生点击事件;

    • 事件消费者:监听并且消费事件,也叫事件监听器

    • 事件:或者成为事件对象,是事件源和事件监听器之间的信息桥梁,整个事件模型驱动的核心;

    事件驱动架构体系结构具备以下三个能力:

    • 事件收集:负责收集各种应用发生的事件,如新建订单,退换货订单等其他状态变更。

    • 事件处理:对事件进行脱敏处理,并对事件进行初步的过滤和筛选。

    • 事件路由:分析事件内容并将事件路由分发至下游产品。

     主要包括 4 个基本组件:

    • 事件队列(event queue):接收事件的入口,存储待处理事件

    • 分发器(event mediator):将不同的事件分发到不同的业务逻辑单元

    • 事件通道(event channel):分发器与处理器之间的联系渠道

    • 事件处理器(event processor):实现业务逻辑,处理完成后会发出事件,触发下一步操作

    事件驱动架构可以基于发布/订阅模型或事件流模型。

    发布/订阅模型(PUB/SUB)

    这是基于事件流订阅的消息传递基础架构。借助该模型,在事件发生或发布后,事件将发送给需要通知的订阅者。

    事件流模型

    借助事件流模型,事件会被写入日志。事件使用者无需订阅事件流。相反,他们可以读取事件流的任何部分,并可以随时加入事件流。

    事件流有几种不同的类型:

    • 事件流处理会使用数据流平台(如 Apache Kafka)获取事件,并处理或转换事件流。

    • 简单事件处理是指事件会立即触发事件使用者行动的情形。

    复杂事件处理需要事件使用者处理一系列事件才能检测到模式。事件流处理可用于检测事件流中有意义的模式。

    发布/订阅模型

    发布/订阅模型是一种消息传递范式,其中发布者(Publisher)发布消息而不需要知道谁是其订阅者,订阅者(Subscriber)可以订阅它感兴趣的消息而不需要知道谁是发布者。这种模型通过引入一个中间件组件(通常被称作消息代理或事件通道),实现了发布者和订阅者之间的解耦。

    • 解耦:发布者和订阅者不直接相互通信,它们通过中间件进行交互。

    • 灵活性:可以轻松地添加或移除订阅者,而无需修改发布者的代码。

    • 支持多对多通信:多个发布者可以发布消息到同一个话题,多个订阅者可以订阅同一个话题。

    事件流模型

    事件流模型通常与反应式编程(Reactive Programming)或数据流编程概念相结合,侧重于事件的连续、实时处理。在事件流模型中,数据(或事件)被视为一个连续不断的流,应用程序通过对这些流的响应来执行业务逻辑。

    • 连续流处理:强调对数据流的连续处理,例如,使用操作符如map、filter、reduce等来转换、聚合和操作这些事件流。

    • 实时性:适用于需要实时处理数据的场景,如实时数据分析、实时监控。

    • 反应式编程:通常与反应式编程范式紧密相关,提供了一套丰富的API来处理异步数据流。

    主要区别

    • 通信模式发布/订阅模型强调在解耦的组件之间的异步消息通信,而事件流模型关注于如何处理并响应连续的数据流

    • 架构目的:发布/订阅主要解决模块解耦和消息分发的问题,适合于构建松耦合的分布式系统;事件流模型则侧重于在应用程序内部对数据流的实时处理和操作,适用于需要流式处理和反应式编程的场景

    • 实现复杂性:事件流模型通常需要一套丰富的操作符来处理流,可能涉及更复杂的编程模式,如反应式编程,而发布/订阅模型则更多关注于消息的传递和订阅管理。

    尽管这两种模式有着不同的关注点和适用场景,但它们并不是相互排斥的。在实际应用中,很多系统可能会同时使用发布/订阅模型来实现跨系统或模块的消息传递,而在系统内部则使用事件流模型来处理和响应数据流。

    事件驱动架构提供解耦优势,数据或服务的发起者和使用者不需要直接沟通,因此有利于打造更灵活且扩展性高的系统。进而进一步简化新组件的集成,提高容错性和系统的整体效率。

    当物联网(IoT)设备、应用和网络等事件源发生事件时,事件便会被捕获,使事件发起者和事件使用者能够实时共享状态和响应信息。

    企业可以向其系统和应用添加事件驱动架构,提高应用的可扩展性和响应速度,改善对数据和背景信息的访问以做出更明智的业务决策。


    下图是人力资源服务系统的事件驱动架构示例,事件总线EventBridge收集人力资源服务系统产生的新员工入职事件,并对此事件进行路由和转发。这种体系结构可以提高站点的可扩展性,同时能更轻便地应对企业架构升级和系统拓展。

    eda架构

    下图是订单服务系统的事件驱动架构示例,该架构中事件总线EventBridge负责收集各种订单状态的事件后分发事件至目标端。

    eventdriven-2



    事件驱动架构的编程范式

    事件驱动方式可以通过多种设计模式实现,其中观察者模式和发布-订阅模式都是实现事件驱动架构的流行方法。

    推荐阅读 观察者模式与发布订阅模式的区别

    观察者模式图一 发布-订阅模式

    • 观察者模式,实现简单:由于观察者直接注册到主题上,实现这一模式相对直接和简单,适用于对象间关系较为固定,通信路径明确的场景。

    • 发布-订阅模式,复杂实现:由于加入了中间件的概念,实现发布-订阅模式相比观察者模式在逻辑上稍微复杂一些。但是这种复杂性带来的好处是更高的灵活性和低耦合度,适用于大型应用和分布式系统。

    观察者模式是实现事件驱动编程的一种经典方式:

    • GUI组件和事件监听:最常见的例子是图形用户界面(GUI)框架中的事件监听机制。例如,当用户点击按钮(一个具体主题)时,按钮对象会通知其所有注册的监听器(观察者),而这些监听器则响应这些事件(通过执行预定的操作)。

    • 股票/新闻订阅:股票或新闻更新系统也是观察者模式的一个典型应用。用户可以订阅特定的新闻频道或股票更新(成为观察者),当有新的内容或数据更新时,系统(作为发布者或主题)将自动推送更新给订阅者。

    • 社交媒体通知:在社交媒体平台上,用户可以关注其他用户或话题。这里,关注的用户或话题可以看做是主题,而关注者则是观察者。当有新帖子或动态发布时,关注者会收到通知。

    • MVC架构:在模型-视图-控制器(MVC)架构中,模型(Model)充当主题,视图(View)作为观察者。当模型的状态发生变化(比如数据更新)时,视图会自动更新以反映最新的数据。


    发布订阅模式实践事件驱动架构

    事件驱动编程的代码核心就是事件循环器,在Linux下推荐使用epoll实现,在其它没有epoll 的系统上可以使用kqueue/ports/poll/select实现。

    事件驱动往往和轮询机制相关,它们通常被统称为 event loop。重点在于并不会给每一个事件分配一个轮询来探知其变化,而是设置一个中央轮询中心,用这个轮询中心去轮询每个注册的对象。轮询中心一旦检测到了注册其中的对象有事件发生,那么就通知对此事件感兴趣的对象。而对此事件感兴趣的对象此时会调用的方法被称为回调函数。


    有不少软件项目都使用了消息队列,但是这里需要明确的是,对消息队列的使用并不意味着你的项目就一定是事件驱动架构,很多项目只是由于技术方面的驱动,小范围地采用了某些消息队列的产品而已。

    在采用事件驱动架构时,我们需要考虑业务的建模、事件的设计、上下文的边界以及更多技术方面的因素,这个系统工程应该如何从头到尾的落地,是需要经过思考和推敲的。总而言之,“事件驱动架构”的设计并不是一件易事。

    另外,如果盲目使用事件驱动设计架构,就有可能要承担中断业务逻辑的风险,因为这些业务逻辑具有概念上的高度内聚,却采用了解耦机制将它们联系在一起

    换句话说,就是将原本需要组织在一起的代码强行分离,并且这样难于定位处理流程,还有数据一致性保证等问题。为了防止我们的代码变成一堆复杂的逻辑。

    事件驱动架构

    bjjav6m8pr.png



    事件驱动型架构(EDA)有哪些优势?


    事件驱动型架构(EDA)可促进系统组件之间的松耦合,从而提高敏捷性。微服务可以独立扩展,失败时不会影响其他服务,并且可以降低工作流的复杂性。可以灵活地路由、缓冲和记录事件以用于审计目的。基于推送的事件流可以实时运行,从而降低了与创建和运行代码相关的成本,该代码不断地轮询系统以进行更改。

    实现扩展和故障的独立性

    通过解耦服务,事件驱动型架构中的组件可以独立扩展和失败,从而提高应用程序的弹性。随着服务之间集成数量的增加,这一点变得越来越重要。如果一个服务出现故障,其余的可以继续运行。

    事件驱动的架构还可以简化近实时系统的设计,帮助组织摆脱基于批处理的处理。应用程序状态更改时会生成事件。处理事件的层可以随着事件的扩展而扩展。
    事件通常发布到消息传递服务,其行为类似于微服务之间的弹性缓冲区,并且有助于处理扩展。事件也可能被发送到路由器服务,该服务可以根据事件的内容筛选和路由消息。因此,基于事件的应用程序可以比整体式应用程序更具可扩展性并提供更大的冗余。

    敏捷开发

    借助事件驱动型架构和事件路由器,开发人员不再需要编写自定义代码来轮询、筛选和路由事件。事件路由器会自动筛选事件并将其推送给使用器。该路由器还将消除产生器和使用器服务之间进行繁重协调的必要性,从而提高开发人员的敏捷性。

    事件驱动型架构是基于推送的,这意味着当事件被发送到路由器和下游系统时,一切都按需发生,而无需通知相关服务。正因为如此,基础设施和资源可以随着事件量的增加和减少而扩展,从而降低处理工作负载和运行已部署应用程序的成本。

    构建可扩展系统

    事件驱动型架构也是高度可扩展的。其他团队可以在不影响现有微服务的情况下扩展特性和添加功能。通过发布事件,应用程序可以与现有系统集成 — 未来的应用程序可以作为事件使用器轻松集成,而无需更改现有解决方案。

    事件产生器不了解事件使用器,因此扩展系统的摩擦较小,并且新功能或集成不会添加依赖项,进而拖慢未来开发的进度。

    降低复杂性

    微服务使开发人员和架构师能够分解复杂的工作流程。例如,他们可以将电子商务整体分解为具有单独库存、履行和会计服务的订单接受和支付流程。

    在整体式应用中的管理和编排可能较为复杂的工作负载变成了一系列简单的、解耦的服务,这些服务被独立管理并通过事件消息异步通信。
    事件驱动的方法使组装和编排以不同速率处理数据的服务成为可能。在以下示例中,订单接受微服务通过队列与支付处理系统交互。


    在示例中,订单接受服务可以通过在队列中缓冲消息来存储大量传入订单。
    由于处理支付的复杂性,支付处理服务通常较慢,它可以从队列中获取稳定的消息流。由于重试和错误处理逻辑,支付服务在各种系统状态之间转换。工作流服务根据系统状态编排和管理支付步骤,并最终产生更多库存、履行和会计服务感兴趣的事件。

    轻松审核

    事件驱动型架构中的事件路由器充当审核应用程序和定义策略的集中位置。这些策略可以限制谁能够发布与订阅到您的路由器,并控制哪些用户和资源有权限访问您的数据。您还可以对您的事件进行动态和静态加密。

    削减成本

    EDA 是基于推送的,因此一切都在事件本身出现在路由器中时按需发生。如此一来,您不用为持续轮询以检查事件付费。这意味着更少的网络带宽消耗、更低的 CPU 利用率、更少的闲置实例集容量,以及更少的 SSL/TLS 握手。


    下面这幅图可以较好地体现基于SOA和EDA两种体系结构的差异处,SOA更多地是面向垂直系统的请求和响应处理,EDA则是应对横向的系统通.

    面向服务架构VS事件驱动架构



    事件驱动型架构(EDA)有哪些挑战?

    可变延迟

    与可能在单个设备上处理相同内存空间内的所有内容的整体式应用程序不同,事件驱动应用程序跨网络通信。这种设计引入了可变延迟。尽管整体式应用程序可能具有更低或更少的可变延迟,但这通常是以牺牲可扩展性和可用性为代价的。
    需要一致的低延迟性能的工作负载不适合 EDA。银行中的高频交易应用或仓库中的亚毫秒机器人自动化就是其中的两个示例。

    最终一致性

    事件代表状态的变化。由于许多事件会在任一给定时间点流经架构中的不同服务,因此此类工作负载通常最终是一致的。 这使得处理事务、处理重复或确定系统的确切整体状态变得更加复杂。

    由于需要 ACID 属性,一些工作负载不太适合 EDA。但是,许多工作负载包含最终一致性(例如,当前小时内的总订单)或强一致性(例如,当前库存)的需求组合。对于那些需要强数据一致性的特性,有一些架构模式可以提供支持。例如:

    • DynamoDB 可以提供强一致性读取,有时延迟较高,它还可以支持事务以帮助保持数据一致性。

    • 您可以将关系数据库用于需要 ACID 属性的功能,尽管任何关系数据库的可扩展性都低于 NoSQL 数据存储。

    向调用者返回值

    在许多情况下,基于事件的应用程序是异步的。这意味着调用者服务在继续其他工作之前不会等待来自其他服务的请求。EDA 的这一基本特征实现了可扩展性和灵活性;但是,它使传递返回值或工作流结果比在同步流中更复杂。

    在许多情况下,返回一个值不如确保事件处理的成功或失败重要。确保事件处理的功能可能比将值返回给调用者更重要。

    对于交互式工作负载,例如 Web 和移动应用程序,最终用户通常希望收到返回值或交易的当前状态。对于这些工作负载,有几种设计模式可以将各种事件处理返回给调用者。但是,事件驱动型架构中的这些实施比使用传统的异步返回值更复杂。该平台通常可以减轻这种复杂性。

    跨服务和功能调试

    调试事件驱动系统不同于调试整体式应用程序。与所有基于微服务的应用程序以及传递事件的不同系统和服务一样,在发生错误时记录和重现多个服务的确切状态可能是一项挑战。由于每个服务和函数调用都有单独的日志文件,因此确定导致错误的特定事件发生了什么可能会更加复杂。

    编排

    随着时间的推移,简单的工作流程变得更加复杂是很常见的。在典型的整体式应用中,这可能导致更紧密耦合的功能和服务组,以及复杂的代码处理路由和异常。

    为了跟踪系统的状态,涉及分支逻辑、不同类型的故障模型和重试逻辑的工作流通常会使用编排工具。在创建事件驱动的无服务器应用程序时,重要的是要确定这种情况何时发生,以便您可以将此逻辑迁移到状态机以进行适当的编排。




    参考文章:

    什么是 EDA(事件驱动型架构)? https://aws.amazon.com/cn/what-is/eda/

    什么是事件驱动架构? https://www.redhat.com/zh/topics/integration/what-is-event-driven-architecture

    事件驱动模型与观察者模型 https://www.itzhai.com/articles/event-driven-model-and-observer-pattern.html

    Spring/SpringBoot面向事件驱动编程(观察者模式) https://juejin.cn/post/7262372637283385402




    转载本站文章《事件驱动型架构:从EDA原理剖析其优劣》,
    请注明出处:https://www.zhoulujun.cn/html/webfront/engineer/Architecture/9073.html