-
2022-01-20 22:35:33
之前简单写过一些关于事件驱动的文章:【C/C++服务器开发】事件驱动、事件驱动架构、事件驱动编程及设计模式。
最近看到一篇不错的文章,在此转载一下:事件驱动和消息驱动
事件驱动和消息驱动
消息驱动和事件驱动很类似,都是先有一个事件,然后产生一个相应的消息,再把消息放入消息队列,由需要的项目获取。他们的区别是消息是谁产生的消息驱动:鼠标管自己点击不需要和系统有过多的交互,消息由系统(第三方)循环检测,来捕获并放入消息队列。消息对于点击事件来说是被动产生的,高内聚。
事件驱动:鼠标点击产生点击事件后要向系统发送消息 “我点击了” 的消息,消息是主动产生的。再发送到消息队列中。事件往往会将事件源包装起来。
事件驱动往往和轮询机制相关,它们通常被统称为 event loop。重点在于并不会给每一个事件分配一个轮询来探知其变化,而是设置一个中央轮询中心,用这个轮询中心去轮询每个注册的对象。轮询中心一旦检测到了注册其中的对象有事件发生,那么就通知对此事件感兴趣的对象。而对此事件感兴趣的对象此时会调用的方法被称为回调函数。
有时也把事件驱动按照实现方式的不同进行区分(个人并不认为很准确,但是很多人都这么说):
- 轮询方式
线程不断轮询访问相关事件发生源有没有发生事件,有发生事件就调用事件处理逻辑。
事件驱动方式 - 事件发生时主线程把事件放入事件队列,在另外线程不断循环消费事件列表中的事件,调用事件对应的处理逻辑处理事件。事件驱动方式也被称为消息通知方式,其实是设计模式中观察者模式的思路。
事件驱动模型可以用下图表示(来源于《Software Architecture Patterns》):
主要包括 4 个基本组件:
事件队列(event queue):接收事件的入口,存储待处理事件
分发器(event mediator):将不同的事件分发到不同的业务逻辑单元
事件通道(event channel):分发器与处理器之间的联系渠道
事件处理器(event processor):实现业务逻辑,处理完成后会发出事件,触发下一步操作
比如说在 Java 的 Socket NIO 模型中,SocketChannel 总是将自身注册为对可读、可写事件感兴趣,ServerSocketChannel 却往往将自己注册为对有一个新的 TCP 连接请求感兴趣。不同的类型的对象可以以不同的兴趣注册到同一个分发器中,分发器既需要能够辨别发生了的不同事件,又需要能够将不同的事件分派给不同的事件通道。因为分发器具备这种为有着不同兴趣的不同对象服务的能力,所以分发器仅仅需要占一个线程。另一个问题是事件处理器如何知道事件发生了?事件处理器就像人一样,人通过每天时不时地看看报纸、看看手机 APP,”时不时地看“这个动作时由人主动发出的,这是最关键的。处理器需要一个其独享的线程,在这个线程中进行检查是否发生了新的事件,这个线程在没有被通知时是阻塞的,一旦 Event Channel 传来了新的事件,事件处理器就不再阻塞。
所以,有一个单线程不阻塞地进行轮询事件队列,一旦发现事件发生了,就通过事件分发器,将包装好的事件通过事件通道传给事件处理器。而每个事件处理器也单独占据一个线程,如果此时没有事件传递过来,其就会阻塞,直到事件传递过来。
事件队列和事件处理器除了在各自的线程模型是否阻塞上有所区别以外,在实现者上也有所区别。通常事件队列包括分发器、事件通道都是由类库替我们完成的,而事件处理器的逻辑则需要更偏向业务的程序员完成。
更多相关内容 - 轮询方式
-
系统事件驱动的基本框架
2019-01-02 16:25:47事件驱动研究的经典论文,给出设计框架,稳定性证明等 -
基于事件驱动的多智能体系统蜂拥控制
2021-01-28 05:19:42提出一种基于事件驱动的控制策略来研究多智能体系统的蜂拥行为。针对实际系统中相对速度信息难以连续交换的情况,设计了由事件驱动机制触发速度信息交互的控制算法。理论上证明了所设计的事件驱动策略能使系统实现... -
浅析基于事件驱动会计信息系统的会计运用
2020-05-24 19:43:07通过创新基于事件驱动会计信息系统的建立,结合会计信息的收集处理过程强化新型会计信息系统在会计中的运用,指出基于事件驱动程序会计信息系统在实施过程中所面临的风险及应对对策。 -
一种虚拟化操作系统基于事件驱动的实时调度方法
2020-07-25 03:36:44提出了一种基于系统实时事件驱动和时间驱动相结合的调度方法,可以对虚拟化操作系统进行实时性改造,改进其调度算法的实时性,满足虚拟化操作系统在嵌入式实时系统中的应用。 -
JAVA简单模拟事件驱动系统
2010-12-22 21:43:53用JAVA简单模拟一个事件驱动系统 模拟消息传递 -
基于系统实时事件驱动和时间驱动相结合的调度方法
2020-10-19 11:41:50提出了一种基于系统实时事件驱动和时间驱动相结合的调度方法,可以对虚拟化操作系统进行实时性改造,改进其调度算法的实时性,满足虚拟化操作系统在嵌入式实时系统中的应用。实际改进测试表明,虚拟化操作系统的实时... -
Esper事件驱动架构
2017-08-21 17:38:17一个事件驱动系统典型地由事件消费者和事件产生者组成。事件消费者向事件管理器订阅事件,事件产生者向事件管理器发布事件。当事件管理器从事件产生者那接收到一个事件时,事件管理把这个事件转送给相应的事件消费者... -
Qp嵌入式系统的事件驱动型编程 中文第二版 完整
2015-05-21 11:03:45QP量子编程 UML状态图的实用c/c++设计 嵌入式系统的事件驱动型编程技术 中文第二版 完整版 -
事件驱动的程序设计方法在嵌入式系统中的应用
2013-09-12 15:05:29文章论述了有限状态机理论,结合软件分层的结构思想,详细分析了事件驱动的程序设计方法。结合实际项目油田原油油量计量 和防盗系统,分析了该系统远程监测终端软件的层次结构,系统状态和事件的划分方法,给出了... -
事件驱动模型
2020-05-22 00:00:52事件驱动模型的概念、作用、实现思路以及几种不同的实现方式。目录
1 概念
在一些应用场景中,我们希望程序是被“事件”触发运行的,并且程序在感知到不同的“事件”后能够产生不同的响应动作(例如常见的UI应用程序,在用户点击不同的按钮后会产生不同的动作效果),此时就需要应用程序能够实时“感知”其所关心的事件,并在事件发生后执行相应的操作。
在解决上述问题时,应用程序是由“事件”驱动运行的,这类程序在编写时往往可以采用相同的模型实现,我们可以将这种编程模型称为事件驱动模型。
个人理解:事件驱动模型其实是一种抽象模型,用于对由外部事件驱动系统业务逻辑这类应用程序进行建模。
2 作用
基于事件驱动的应用程序可以实时响应所关心的事件,实现实时检测、响应外部动作,这是事件驱动模型的基本功能和作用。在一些复杂的系统中,事件驱动模型还可很好地发挥以下作用:实现组件之间的松耦合/解耦、实现异步任务、跟踪状态变化。
- 实现组件之间的解耦
在复杂系统中,往往存在多个组件相互耦合的情况,如果将组件之间的耦合关系抽象成“事件(event)”,让事件担任组件之间的通信任务,就能而降低\解除组件之间的耦合关系。
参考以下示例
//示例1 经典实现,类A、B之间的耦合关系较强耦合 class A { void act1() {} void act2() {} //... } class B { A a; void action() { //TODO 根据业务逻辑判断需要触发a的哪个动作 } //.... }
在示例1的代码段中,类B对类A有较强的依赖,B需要根据不同的业务逻辑调用A的不同动作,若类A的实现有变化那么类B难免需要进行适配。如果将A、B之间的耦合关系抽象为事件,代码见示例2
//示例2 将A、B的耦合关系抽象为事件,以实现解耦 class Event { //... } class A { void notify(Event e) { //TODO 判断事件类型,触发响应动作 } //... } class B { A a; void action() { Event e = craeteEvent(); a.notify(e); } Event createEvent() { Event e = new Event(); //... return e; } //... }
此时B将更多的关注点转移到了Event,与A的关系仅限于B通知A需要处理业务,具体触发什么动作由A自己判断并触发。相比于示例1的实现,示例2的实现中引入了类Event辅助类A、B之间通信,类A与类B之间的耦合关系也更松弛。
个人理解:事件驱动模型,实际上是将组件之间的耦合关系转移到了“事件(Event)”上,但是对于某个领域而言事件(Event)一般具有通用性并且不会频繁变更实现逻辑,所以事件驱动模型可以很好地实现组件之间的解耦。
- 实现异步任务
在一些业务场景中,顺序、阻塞式地执行任务会遇到一些比较耗时的中间步骤,但是不希望整个流程都停下来等待这些中间步骤完成,而是触发一个异步操作然后继续执行当前任务,在收到异步操作处理完成的消息之后再执行相关的处理。
打一个比较容易理解的比方:上课的时候需要记学习笔记,但是笔记内容较多的时候,老师不会停下来等大家做完笔记再继续讲课,大家只能先记住“记笔记”这件事,等老师讲完课后在把笔记补上,有时候我们补完笔记还需要告诉老师“笔记已经做好了”,请老师检查笔记。
当然,也可以是多线程下的异步任务:如果有的同学具备一心二用的能力,他就可以在听课的同时做完笔记,然后告诉老师他已经完成了“记笔记”的任务。
在一些事件驱动模型的设计结构中,会存在“任务队列”用以存储需要处理的“事件(Event)”,这种结构的事件驱动模型就可以很好地实现上述业务场景。
使用事件驱动模型实现异步任务的一般思路是:当遇到耗时较大、没有同步执行要求的操作时,针对这个操作触发一个事件,将这个事件加入到任务队列中,直到有一个进程(线程)能够获取并执行这个任务,才开始执行这个任务。
- 跟踪状态变化
在存储实体模型的业务中通常需要修改实体模型的数据,对于部分业务场景需要存储、使用实体模型的历史变更记录,例如什么时间对实体数据做了什么修改。对于这类需求,事件驱动模型也可以提供很好的解决方案,我们可以认为每次修改实体数据都是一次事件,那么在修改实体数据后将这个事件存储到事件队列中即可实现跟踪状态变化的需求。
(待补充...)
对于事件驱动模型作用的的理解,可以参考:事件驱动架构设计
3 实现思路
事件驱动模型有很多种体现形式,如简单的事件触发机制、单线程异步任务、多线程异步任务等,但是各种技术中实现事件驱动模型的基本思路相同。
事件驱动模型的基本结构如图1所示
图 1 事件驱动模型基本结构 事件驱动模型包括三个基本要素:事件状态对象(Event)、事件源(EventSource)、事件监听器(EventListener)。
3.1 三要素
- 事件状态对象(Event)
Event作为事件的抽象,对事件本身进行了描述,携带着事件的详细信息(如在UI系统中,Event携带的信息有鼠标动作类型、鼠标坐标等信息)。在事件驱动模式中Event起着传递事件信息的作用,负责把被触发事件的详细信息传递给EventListener,以便EventListener作出正确的响应动作。
- 事件源(EventSource)
EventSource主要用于感知外部事件,将事件打包成Event并分发给EventListener处理。
个人理解:这里的EventSource实际上担任了两个职责:1)生成事件;2)派发事件。依据职责单一原则的描述EventSource应该只担任“生成事件”的职责,而“派发事件”的职责应当重新设计一个EventDispatcher类来担任,但是由于单应用场景下“派发事件”的业务逻辑通常比较简单,所以这里将EventDispatcher的职责也交由EventSource负责。
(PS:到底应该设计成EventSource还是 EventSource + EventDispatcher ,涉及到事件驱动模型的两种实现形式:以观察者模式实现、以发布订阅模式实现,3.3节会具体谈到。)
- 监听器(EventListener)
EventListener封装了响应事件的能力,它职责就是在感知到EventSource触发Event后,处理Event对象以响应事件。一般需要在EventSource预留注册EventListener的接口,以便在运行时向EventSource添加处理事件的监听器。
3.2 三要素之间的关系
关系对 关系 EventSource -- EventListener EventSource注册EventListener EventSource通知EventListener处理Event Event -- EventSource EventSource生成Event,并派发Event Event -- EventListener EventListener消费Event 3.3 常见的实现形式
事件驱动模型有两种实现形式:以观察者模式实现、以发布/订阅模式实现。下面先介绍一下关于观察者模式和发布/订阅模式的区别。详细内容可以参考发布订阅模式与观察者模式
观察者模式和订阅/发布模式的主要区别在于两者触发事件的机制不同,如图2所示(借同业绘制的对比图一用,侵删)
图 2 观察者模式与发布/订阅模式对比图 上图是为了对比观察者模式和订阅/发布模式两者之间的区别,所以图中各模块的名字遵循了规范的写法。本文的目的在于对比两个模式在实现事件驱动模型时的区别,为了方便后文描述,将上图各的名字作如下映射:
-
EventSource:表示Subject和Publisher。
Subject和Publisher在模型中担任的主要职责都是生成Event(Subject还担任了简单的分发Event的职责)。
-
EventDispatcher:表示Topic/EventChannel。
图中的“Topic/EventChannel”和3.1节讨论的EventDispatcher(调度器)担任的职责相同(调度Event),本人更倾向于使用“调度器”来描述这个模块l。
-
EventListener:表示Observer和Subscriber。
Observer和Subscriber在模型中担任的职责都是监听、处理Event。
由图2可见,订阅/发布模式直观上来看比观察者模式多了一个EventDispatcher模块,并且EventListener的依赖关系也从EventSource转移到了EventDispatcher上。观察者模式和订阅/发布模式存在这种直观上的差异,是因为两者解决问题的场景不同:
- 观察者模式关注的是事件发生后观察者能够获取到足够的数据。这种场景下Event种类单一,但是Event会被多个EventListener关注,Event中携带的信息更多的是观察者需要的数据。这种场景下,要求事件发生后EventSource能够通知所有EventListener,此时调度Event的逻辑很简单,不必设置独立的调度器执行调度任务。
(PS:如果需要实现异步任务,EventSource中会设计一个事件队列用于异步调度)
- 订阅/发布模式关注的是事件发生后能够准确地触发相应的动作。这种场景下Event种类多,每类Event只有多个EventListener关注,Event中携带的多是事件自身的一些信息(例如EventID之类),而很少携带其他数据。这种场景下,Event更像一个触发信号,不同的Event会触发不同的EventListener执行动作,此时调度Event的逻辑复杂,需要设置独立的调度器执行调度任务。
(PS:如果需要实现异步任务,EventDispatcher中会设计一个事件队列用于异步调度)
观察者模式和订阅/发布模式的具体差异对比见下表
观察者模式 发布/订阅模式 EventSource与EventListener
的耦合关系
松耦合 完全解耦 角色(除Event外) 2个
EventSource、EventListener
3个
EventSource、EventDispatcher、EventListener
EventSource个数 一个 可能存在多个 事件种类数 一种 多种 EventListener种类数 多种 多种 消息中间件 不存在 存在:EventDispatcher 事件与监听器对应关系 一个事件对应多个监听器 一个事件对应多个监听器 Event携带的内容 数据 一般不携带除描述Event自身信息以外的数据 应用场景 独立应用程序 多组件的应用程序、夸应用的系统 在具体的业务中是选择观察者模式还是发布/订阅模式来实现事件驱动模型,取决于具体的业务场景和对Event的抽象粒度。如果系统中只有一种Event的抽象,优先考虑使用观察者模式实现;如果系统中存在多种Event抽象,优先考虑发布/订阅模式实现。
对于Event该如何抽象也因人而异。例如在《HeadFirst Pattern》一书讲解观察者模式的那个例子,气象站检测到的数据有温度、气压、湿度等,如何对事件进行抽象就有两种思维:
1)认为事件就是气象数据变化,无论温度、气压还是湿度的一项或者多项有变化,都触发同一个事件。
2)认为温度变化、气压变化、湿度变化是三种不同的事件,当其中的一项数据变化时触发相应的事件,如果三项数据同时变化将会触发三个事件。
对于1)中的抽象结果,可能使用观察者模式更合适;而对于2)中的抽象结果,则使用发布/订阅模式更合适。可见对于相同的应用场景,不同的抽象方式会有不同的使用情景。
(PS:经过对观察者模式和发布/订阅模式的对比,容易发现本文之前举的例子(示例2和图2)其实都是以观察者模式实现的。)
个人理解:观察者模式和发布/订阅模式都可以实现事件驱动模型。在实现事件驱动模型时可以选用观察者模式和发布/订阅模式中更适合当前业务场景的模式组织编码,具体如何实现可以参考观察者模式或发布/订阅模式的资料,也可以参考后文给出的案例链接。
3.4 同步驱动和异步驱动
在第2节中我们已经了解了异步任务的含义,也对异步任务的实现思路做了简单介绍。相比于同步任务,异步任务的优势在于处理耗时长的任务时不会阻塞主线任务。
大家在比较同步任务、异步任务时,一般还会和多线程任务一起进行对比,本文不对这三种时序模式作太详细的介绍,这里借用一张比较经典的对比图(如图3)来解释一下三者的区别,如大家想了解更多可以查阅同步、异步、多线程等相关知识。
图 3 同步、异步、多线程对比 - 单线程同步模型:三个任务依次顺序执行,并且只有当某个任务完全执行完成后才能执行下一项任务,如果这三个任务之间不存在依赖关系,但是任务中存在阻塞操作(如IO操作),程序将会存在大量的等待时间,导致程序的运行速度变慢。
- 多线程模型:三个任务运行在不同的线程中,任务之间不会彼此影响。这种模型往往需要考虑多线程同步的问题,处理起来难度相对较大,并且对于每个任务而言线程仍然会存在等待时间,只是缩短了整个程序的等待时间、提高了CUP利用率。实现方式参考多线程相关知识。
- 异步模型:三个任务仍然在同一个线程中执行,只是在当前任务遇到阻塞操作时会让出资源,让其他任务先执行,如此交替执行。这种模式在遇到阻塞操作时不会等待,所以程序运行速度会快很多。异步模型的实现思路可以参考第2节的描述,需要维护一个任务队列,当遇到阻塞操作时将任务放到队列中,阻塞操作完成后将任务从队列中取出等待执行机会,在获得执行机会后执行回调函数继续处理任务。
(PS:这三种模型没有好坏之分,在开发时选用哪种模型取决于具体的业务场景。)
经过上述比较,我们可以清晰地认识到同步模型和异步模型在实现上的区别,异步模型需要借助任务/事件队列实现。
在事件驱动模型中,驱动事件的动作可以选择同步驱动或异步驱动。
同步驱动事件:生成事件、触发事件和处理事件是顺序执行的。EventSource在生成Event后立即通知EventListener,事件处理完成后返回处理结果。具体实现参考观察者模式的经典实现。
异步驱动事件:生成事件、触发事件和处理事件不是顺序执行的。EventSource在生成Event后将Event缓存在事件队列中,然后通知EventListener,事件处理完成后如果有必要再调用回调函数上报处理结果。有时我们会采用多线程的方式,由线程A向队列缓存Event由线程B消费Event。
基于异步驱动实现事件驱动模型时,还需要参考消息队列和生产者-消费者模式相关知识来维护事件队列。
4 经典实现
观察者模式
订阅/发布模式
UI框架
Netty
Spring 事件模型
Node.js
5 示例(点击链接查看)
- 基于观察者模式实现的事件驱动模型(同步 + 异步):事件驱动模型-观察者模式实现
- 基于发布/订阅模式实现的事件驱动模型(同步 + 异步):
-
软件架构-事件驱动架构
2021-02-21 21:02:31事件驱动架构是一种系统或组件之间通过发送事件和响应事件彼此交互的架构风格。当某个事件发生时,组件A不直接调用组件B,而只是发出一个事件。组件A不知道哪些组件监听并处理这些事件。事件驱动架构可以在进程内和...你好,我是看山。
本文源自并发编程网的翻译邀请,翻译的是 Jakob Jenkov 的 《软件架构》 中关于事件驱动的内容,虽然是 2014 年的文章,但是从软件架构层面上,并不过时。
以下是正文。
事件驱动架构是一种系统或组件之间通过发送事件和响应事件彼此交互的架构风格。当某个事件发生时,组件A不直接调用组件B,而只是发出一个事件。组件A不知道哪些组件监听并处理这些事件。事件驱动架构可以在进程内和进程间使用。比如,GUI框架中会大量使用事件驱动。【译者注:目前很多系统采用微服务架构,事件驱动使用的更加广泛了。】此外,正如我在并发模型教程 中所提到的,装配线并发模型(AKA reactive,非阻塞并发模型)也使用了事件驱动架构。
本文主要介绍进程之间的事件驱动架构,后文提到这个词的时候也是指进程交互方式。
进程间的事件驱动架构
事件驱动架构是一种架构风格,先将请求事件集中存放在一个或多个事件队列中,然后事件从这些事件队列转发到后端服务,处理这些事件。
因为事件可以被看做是消息流,所以事件驱动架构也被称为消息驱动架构或者流处理架构。流处理架构又可以被称为lambda架构。为了保证统一,后文会继续使用事件驱动这个名词。
事件队列
在事件驱动架构中,你会有一个或多个集中的事件队列,所有的事件被处理前,会先保存在集中的事件队列中。下面给出一个简单示例:
事件插入队列时是有序的,这样就可以顺序处理这些事件。
事件日志
写入事件队列时,消息可能写入到事件日志(通常是磁盘存储)中。如果发生系统崩溃,系统只需要重放事件日志即可恢复到崩溃前的状态。下面是一个事件驱动架构的示例,其中包括一个用于持久化事件的事件日志:
我们还可以通过备份事件日志,来备份系统状态。在将新版本的系统部署在生产环境之前,可以使用这个备份数据对其性能进行测试。或者,通过重放事件日志的备份,来重现某些错误。
事件收集器
请求都是通过网络传输,比如HTTP或者其他协议。为了保持一致,可以通过事件采集器接收来自不同来源的事件。下面是一个添加了事件收集器的事件驱动架构示例:
响应队列
有时,我们还需要向请求(即事件)返回响应,所以,很多事件驱动架构除了包含事件队列,还会有一个响应队列。下面是包含事件队列(入队队列)和响应队列(出队队列)的事件驱动架构示例:
如你所见,响应队列必须路由到正确的事件收集器。比如,如果HTTP收集器(本质上是web服务器)通过HTTP接收的请求发送到事件队列中,则该事件生成的响应可能也需要通过HTTP收集器发回客户端。
通常,响应队列不会持久化,也就意味着它不会写入事件日志,只有输入的事件才会持久化到事件日志中。
读事件 vs. 写事件
如果将所有传入的请求都认为是事件,就需要将这些事件都推送到事件队列中。如果事件队列是实现了持久化(持久化到事件日志中),就意味着所有事件都需要持久化。通常持久化都比较慢,如果我们能够过滤掉一些不需要持久化的事件,我们就能够提升队列的性能。
我们将事件持久化到事件日志的原因是,我们可以重放事件日志,并重建因为事件引起的系统状态变化。为了支持这个特性,实际上只需要持久化更改系统状态的事件。换句话说,我们只需要将事件分为读事件和写事件。读事件只读取系统数据,不会更改,写事件会更改系统数据。
通过根据读和写划分事件,我们只需要持久化写事件的消息即可。这将提升事件队列的性能,提升比例大小,取决于读写事件之间的比例。
为了将事件划分为读写事件,需要在事件到达事件队列之前,也就是事件收集器中进行区分。否则,事件队列无法知道到达的事件是否需要持久化。
还可以将事件队列拆分为两个,一个用于存储读事件的事件队列,一个用于存储写事件的事件队列。这样读事件就不会慢于写事件,事件队列也不需要检查每条事件是否需要持久化。读事件队列不需要进行持久化,写事件队列始终持久化事件。
下面是一个事件驱动架构的示例,其中事件队列分为读和写事件队列:
上图示例中箭头比较乱,但实际上创建3个丢列并在它们之间分发消息简单很多。
事件日志重放的挑战
事件驱动架构的一大优点是,在系统崩溃或系统重启情况下,只需要重放事件日志,就能够重建系统状态。在日志可以独立于时间和周边系统的情况下重放日志,这是一个很大的优势。
但是,完全独立于时间重放事件日志有时候很难实现。接下来介绍下事件日志重放的一些挑战。
处理动态数据
如前所述,写事件处理时可能会修改系统数据。有些情况,这种数据的修改受事件处理时动态数据的影响。比如,处理事件的日期和时间或者特定日期和时间的货币汇率。
这些动态数据会对事件重放造成困难。如果在不同的时间重放事件日志,处理该事件的服务可能会解析不同的动态值,比如其他的日期和时间或其他汇率。因此,在不同的日期重放事件日志,可能会出现重建系统数据与最初处理事件产生的数据不一致。
要解决动态数据的问题,可以让写事件队列将所需的动态数据标记在事件中。但是,要实现这种方案,需要事件队列知道每条事件消息需要哪些动态数据。这样会使事件队列的设计复杂化,每次需要新的动态数据时,事件队列都需要知道如何查找这些动态数据。
另外一种解决方案是,写事件队列只在写事件上标记事件的日期和时间。使用事件的原始日期和时间,处理事件的服务可以查找给定日期和时间对应的动态数据。比如,可以通过原始的日期和时间,查询当时有效的汇率。这就要求处理事件的服务需要基于日期和时间查询动态数据,但是这只是理想状态。
与外部系统的交互
事件日志重放的另一个挑战是与外部系统的协调。比如,事件日志中包含电商平台的订单,在第一次处理这个事件时,需要将订单发送到外部支付网关,以从客户信用卡中收费。
如果重放事件日志,就不希望再次为同一个订单向客户收费。因此,就不希望在事件重放时,将订单发送到外部支付网关。
事件日志重放解决方案
解决重放事件日志问题挺不容易的。有些系统没有问题,可以直接重放事件日志;有些系统可能需要知道原始事件的日期和时间;有些系统可能需要知道更多类似于事件原始处理过程中从外部系统获取的原始数据。
重放模式
在任何情况下,倾听写事件队列中事件的任何服务都必须知道传入事件是原始事件还是重放事件。这样,处理服务就能够确定如何处理动态数据或者如何与外部系统交互了。
多步骤事件队列
另外一个解决方案是采用多步骤事件队列。第一步,收集所有写事件;第二步,解析动态数据;第三步,与外部系统交互。如果需要重放事件日志,只需要跳过第一步和第二步,重放第三步即可。具体如何实现,需要取决于具体的系统设计。
你好,我是看山,公众号:看山的小屋,10 年老后端,Apache Storm、WxJava、Cynomys 开源贡献者。主业:程序猿,兼职:架构师。游于码界,戏享人生。
原文链接:Event-driven Architecture
翻译: https://www.howardliu.cn
译文链接: 软件架构-事件驱动架构
CSDN主页: http://blog.csdn.net/liuxinghao
CSDN博文: 软件架构-事件驱动架构 -
推荐一本有关嵌入式系统事件驱动编程的图书
2019-02-27 16:44:27《UML状态图的实用C、C++设计:嵌入式系统的事件驱动型编程技术(第二版)》《Practical UML Statecharts in C,C++:Event-Driven Programing for Embedded Systems, Second Edition》带书签中文合辑下载
https://download.csdn.net/download/zoomdy/10979234
压缩包内包含两个独立的pdf文件,分别是中文第2版和英文原书第二版。英文好的同学可以直接阅读英文版,英文不好的同学可以阅读中文版同时参考英文版。
英文原书第2版
《Practical UML Statecharts in C,C++:Event-Driven Programing for Embedded Systems, Second Edition》
中文第2版
《UML状态图的实用C、C++设计:嵌入式系统的事件驱动型编程技术(第二版)》 很可惜,该中文版没有正式出版。
-
基于事件驱动的医疗设备管理系统设计.rar
2021-09-20 02:47:03基于事件驱动的医疗设备管理系统设计.rar -
电信设备-基于事件驱动实时获取系统中进程信息的方法及系统.zip
2021-09-18 12:02:46电信设备-基于事件驱动实时获取系统中进程信息的方法及系统.zip -
事件驱动编程、消息驱动编程、数据驱动编程
2020-02-10 14:53:47事件驱动 基本概念 窗口/组件 事件 消息(队列) 事件响应(服务处理程序) 调度算法 进程/线程 非阻塞I/O 程序的执行可以看成对CPU,内存,IO资源一次占用 现代操作系统支持... -
什么是事件驱动架构(EDA)?
2020-05-21 01:03:56关于最终一致性 响应事件而不是“及时”查询权限系统会让我们更具有自主性,更有容错能力和弹性,但也有一点其他影响,会影响自治事件驱动系统的是“延迟”。 如果你立即注意到某一事件,你可以立即做出反应。例如... -
事件驱动和消息驱动的对比
2020-08-01 15:55:43(3)每收到一个请求,放入一个事件列表,让主进程通过非阻塞I/O方式来处理请求 上面的几种方式,各有千秋, 第(1)中方法,由于创建新的进程的开销比较大,所以,会导致服务器性能比较差,但实现比较简单。 第(2)... -
软件架构模式之事件驱动架构
2021-02-01 12:40:00我是架构精进之路,点击上方“关注”,坚持每天为你分享技术干货,私信我回复“01”,送你一份程序员成长进阶大礼包。事件驱动架构事件驱动架构(Event Driven Architect... -
事件驱动的详解
2019-01-21 14:58:58事件驱动和异步IO 通常,我们写服务器处理模型的程序时,有以下几种模型: (1)每收到一个请求,创建一个新的进程,来处理该请求; (2)每收到一个请求,创建一个新的线程,来处理该请求; (3)每收到一个请求,... -
什么是事件驱动
2018-03-07 23:23:58实际上,现代的程序大多是事件驱动的,比如多线程的程序,肯定是事件驱动的。早期则存在许多非事件驱动的程序,这样的程序,在需要等待某个条件触发时,会不断地检查这个条件,直到条件满足,这是很浪费cpu时间的。... -
事件驱动与异步IO
2017-10-20 10:01:02(3)每收到一个请求,放入一个事件列表,让主进程通过非阻塞I/O方式来处理请求上面的几种方式,各有千秋, 第(1)中方法,由于创建新的进程的开销比较大,所以,会导致服务器性能比较差,但实现比较简单。 第(2)种... -
事件驱动是什么?
2018-11-28 10:17:12当一个系统发送了事件消息通知其它系统在自身域中做改变时,会发生事件通知。事件通知的一个关键因素是源系统并不真正十分关心响应。通常源系统根本就不希望得到应答,或者如果有一个源系统关心的响应,这也是间接的... -
事件驱动型状态机EFSM介绍及C语言实现
2019-04-28 16:57:01有限状态机是一种用来进行对象行为建模的工具,其作用主要是描述对象在它的生命周期内所经历的状态序列,以及如何响应来自外界的各种事件。在计算机科学中,有限状态机被广泛用于建模应用行为、硬件电路系统设计、... -
消息驱动与事件驱动比较
2017-07-24 14:35:52简单记录自己对于 消息驱动 和 事件驱动的理解。关于这二者的具体区别,于实现上来说,二者都是 注册绑定,然后交付执行。消息驱动模型在注册的时候仅仅注册一个回调函数作为处理函数。 而事件驱动模型则需要注册... -
事件驱动(Spring自带的@EventListener)和消息驱动(RabbitMq)
2021-06-02 10:50:35消息驱动和事件驱动很类似,都是先有一个事件,然后产生一个相应的消息,再把消息放入消息队列,由需要的项目获取。他们的区别是消息是谁产生的 消息驱动:鼠标管自己点击不需要和系统有过多的交互,消息由系统(第... -
基于系统实时事件驱动和时间驱动相结合的调度方法 LMBench
2017-03-28 14:14:17http://embed.21ic.com/jiaocheng/sheji/201202/4458.html -
深入分析Spring事件驱动模型
2017-11-18 11:12:59聊一聊从观察者模式到Spring的事件驱动模型 -
事件驱动架构及应用
2016-05-12 14:58:53Gartner在2003年引入了一个新术语事件驱动架构(Event Driven Architecture,EDA), 主要用于描述一种基于事件的范例。EDA 是一种用于进行设计和实现应用和系统的方法—在这些应用和系统里, 事件所触发的消息可以在...