什么是Event?

An event represents a fact, something happened; and it is immutab.

事件代表着事实,代表着过去发生的某件事情,是不可变的。

既然事件代表着在过去某一时刻发生的某个事情,那么那必然具备一些基本的要素,就像现实生活中发生某件事情也具备时间、地点等几个要素。事件的基本要素包含time、source、key、header、metadata和payload。

Event vs Message

日常开发中我们接触到的和事件最接近的应该是消息,这两者也比较容易混淆,难以说清楚它们的界限:什么是事件,而什么是消息?

A message is an item of data that is sent to a specific destination. An event is a signal emitted by a component upon reaching a given state.

上面是我觉得的解释是比较好的,消息是发送到特定目标的数据项,而事件是标识某个组件达到了某个状态。消息更关注于行为,即“要做一件什么事情”——要把某一条消息发送到服务端;而事件关注于事实,即“发生了什么事情”。

消息没有特定的意图(no special intent),可以承载任何数据,那么也可以用消息来承载事件,所以消息是事件的超集(事件可以认为是一类加上了一些特定限制的消息)。

Event vs Command

还有一类日常中使用的远程调用的方式Command,通常我们执行一个RPC调用都是执行一个Command。Command和Event的区别在于Command着重于要做什么,用于传递一个要执行某个动作的请求。

因为Command具有以下特性:

  • 意味着行为即将发生,但是还没发生
  • 可能被拒绝:可能被拒绝执行,或者因为某些原因无法执行
  • 有明确的源(发起者)和目标(执行者)

结合和Message及Command的差异,总结一下Event具备的特征:

  • 代表着已经发生的事情->已经发生的事情不可改变
  • 事件有特定的一些属性,表明特定的含义,事件是消息的子集
  • 事件有明确的源,但没有明确的目标

CloudEvents

因为事件无处不在,DB中的数据发生了一次变更是一个事件,几台机器宕机了也是一个事件,并且每个发布者对事件的描述是不一致的,导致难以在一个大规模的范围内使用事件。

  • 没有统一的标准去描述事件意味着开发者需要为每一个事件源编写逻辑
  • 没有统一的标准去描述事件意味着没有通用的类库、工具、基础设置来支持事件的处理、分发
  • 没有统一的标准去描述事件意味无法进行移植,可能无法跨平台的去使用

其实在每个特定的系统中我们都会制定事件的标准来解决这个问题,比如CDC(Change Data Capture)的场景中,类似Canal(https://github.com/alibaba/canal)这样的产品都会将DB中的变更事件封装成特定的Java对象,而这个对象实际就是事件的标准。面对这个问题,CNCF(Cloud Native Computing Foundation)站在更高的角度来抽象事件,而不是局限在特定的系统或者领域,制定了CloudEvents标准。

每个符合规范的CloudEvent都需要包含必须(REQUIRED)的属性,并且可以包括多个非必须(OPTIONAL)的属性。这些属性描述了事件,并且独立于事件的数据进行序列化,这样就可以在不必进行事件数据反序列化的情况下对事件进行检查。

REQUIRED Attributes

  • id: String类型,标识Event,必须保证Source+ID能唯一确定一个Event
  • source:URI-reference类型,事件发生的“源”
  • specversion:String类型,标识事件使用的CloudEvents Spec版本
  • type:String类型,描述事件的类型

OPTIONAL Attributes

  • datacontenttype:String类型,Event内容的类型,例如"application/xml"
  • dataschema:URI类型,指明Event内容的Schema信息
  • subject:String类型,Event的Subject信息
  • time:Timestamp类型,事件发生的时间

Example

{
"specversion" : "1.0-rc1",
"type" : "com.github.pull.create",
"source" : "https://github.com/cloudevents/spec/pull",
"subject" : "",
"id" : "A234-1234-1234",
"time" : "2018-04-05T17:31:00Z",
"comexampleextension1" : "value",
"comexampleothervalue" : ,
"datacontenttype" : "text/xml",
"data" : "<much wow=\"xml\"/>"
}

什么是Event-Driven?

在讨论Event-Driven之前需要弄清楚Event-Driven的概念,这里就需要理清楚Event-Driven和Request-Driven的关系。

上面这张图来源于《Build Services on a Backbone of Events》一文,比较清楚的描述了Request-Driven和Event的区别:

  • Request-Driven包含Command和Query两种,Command意为执行命令,会导致状态的变更;而Query仅查询数据,不会导致状态变更。Request-Driven是希望执行某段业务逻辑。
  • Event-Driven则是事件驱动,事件在状态变更后触发,是业务逻辑执行完后导致的状态变更的通知。

日常我们使用的RPC服务都可以理解为是Request-Driven,都是请求执行某个命令;而日常使用的消息中间件都是Event-Driven。如果由Event来驱动执行逻辑,那么称为Event-Driven的应用。一个应用往往即会处理RPC请求,也会订阅消息,那么它有一部分是Request-Driven的,有一部分是Event-Driven的(除非是Function或者是特定领域的简单的应用——比如做消息的转换,很少会有一个纯粹的Event-Driven的应用)。没有必要过分纠结一个应用是否是纯粹的Event-Driven的,更重要的是理解Event-Driven的思想,将它融入到架构的思想中来把业务系统做的更好。

什么是Event-Driven Architecture?

Event-Driven Architecture是一种用于构建可扩展的分布式异步处理模式,由高度解耦的、单一职责的事件处理器组成。

Event-Driven Architecture模式有两种主要的结构:Mediator Topology和Broker Topology。Mediator Topology多用于需要有多个编排步骤的事件处理,而Broker Topology用于链式的事件处理。

Mediator Topology

Mediator Topology用于Event需要多个步骤进行处理,且需要一些编排能力的场景。比如一个Event进来之后,系统需要决定处理的顺序,以及其中哪些步骤可以并发的执行。Mediator Topology中有四个核心的组件:event -queue、event-mediator、event-channel、event-processor。整个流程通过客户端发送一个Event到event-queue开始,然后由event-queue将Event传输到event-mediator,event-mediator收到初始的Event之后通过异步的发送额外的Event到event-channel来完成编排,event-processor从event-channel接收Event并执行特定的业务逻辑来完成处理。

在Event-Driven Architecture中会有成百上千Queue,Event-Driven Architecture并不绑定Queue的实现,它可以由MQ实现,也可以由其他组件实现。

在Mediator模式下有两类Event,一类是initial event,一类是processing event。initial event是外部输入的初始Event,processing event是由Mediator产生的,由Event Processor处理的Event。

event-mediator的职责是编排initial event,对于initial event的每个处理步骤event-mediator发送一个processing event给event-channel,event-mediator并不执行任何真正的业务逻辑。

event-channel用于event-mediator将Event异步的投递给event-processor处理,event-channel可以使用message queue或者message topic实现。message topic是更常用的,因为event可以被投递给多个event processor处理。

event-processor包含了用于处理processing event的业务逻辑。event-processor是应用中用于执行特定任务的、自包含的、独立的、高度解耦的组件。明确event-processor是单一职责的非常重要,event-processor执行任何一个任务不应该依赖于其他event-processor的处理。

上图是用户通过保险公司投保并修改地址的例子。首先event-mediator收到初始事件,然后执行change address操作(发送Processing Event: change address event给ConsumerProcessor处理),再之后并发的执行RecalcQuote和UpdateClaims事件,接着执行AdjustClaims调整报价,最后执行Insured的通知。

Broker Topology

区别于Mediator Topology,Broker Topology没有中心式的event-mediator,Event在event-processor之间以一种链式的结构流转,在事件流相对简单,不需要集中编排的场景下这种模式是非常适用的。

在Broker Topology下只有两个核心的组件:broker和event-processor。Broker可以是中心式的,也可以是分布式的,包含事件流中所需要的所有event-channel。Broker中的event-channel可以是message queue或者message topic,也可以是它们的组合。

Broker Topology结构如上图所示,在图中没有一个event-mediator来编排event,仅有event-processor来处理event并在处理完成之后产生新的event来表示它刚刚执行的操作。

同样以Mediator中的例子来看的话,在Broker模式下的处理流程如下:

其中ChangeAddress的Processor直接处理Event,处理完毕后产生一个ChangeAddress完成的事件,然后由QuoteProcess和ClaimsProcess订阅这个事件并执行各自的处理逻辑(这一步是并发的),之后AdjustProcess会订阅UpdateClaims的Event,而NotificationProcess会同时订阅RecalcQuote和UpdateClaims的Event。

总结

Event-Driven Architecture在某些方面是具有天然优势的,在另一些方面则对现行的开发模式增加了负担,比如:

  • 敏捷度:EDA模式中event-processor都是解耦的且单一职责的,所以再进行变更时会非常容易,能够快速的变更完成业务,所以有较好的敏捷性。
  • 易于部署:EDA模式是非常容易部署的,特别是Broker的模式,因为各个组件是相互独立的。
  • 可测试性:EDA模式的测试相对于REQUEST驱动的模式会复杂很多,因为需要构建各个Event并且都是异步的。
  • 性能:EDA模式各个组件独立解耦,且异步执行,这大大提升了系统的性能。
  • 可伸缩性:EDA进行了组件的解耦,所以天然的具备的非常好的伸缩性,可以根据各个组件的性能执行不同的伸缩策略。
  • 易于开发:EDA模式下,比如Broker模式每个event-processor只需要处理自己关注的事件,并决定是否产出一个新的事件,逻辑开发是简单的,但是如何将event-processor组合起来完成整个业务是相对复杂的。

Event-Driven Architecture是相对复杂的架构,因为它天然是异步的、分布式的。当选择采用Event-Driven来处理业务逻辑时,如何划分event-processor是非常重要的,因为event-processor是独立的,需要避免将带有事务语义的逻辑拆分到多个event-processor中。统一事件标准也是非常重要的,因为event-processor会随着业务的变化而不断的增长,使用统一的标准将降低event-processor之间的交互及新event-processor的接入成本。

Event-Driven Architecture思考的更多相关文章

  1. Event Driven Architecture

    在微服务中使用领域事件   稍微回想一下计算机硬件的工作原理我们便不难发现,整个计算机的工作过程其实就是一个对事件的处理过程.当你点击鼠标.敲击键盘或者插上U盘时,计算机便以中断的形式处理各种外部事件 ...

  2. 【转】Event Driven Programming

    FROM: http://lazyfoo.net/tutorials/SDL/03_event_driven_programming/index.php Event Driven Programmin ...

  3. event driven的一些概念

    1. event :Something that happens during your application that requires a response. 2.event object:Th ...

  4. JS运行机制之 Event Loop 的思考

    先举个栗子,如下: for (var i = 0; i < 5; i++) { setTimeout(function() { console.log('i: ',i); //一秒之后输出几乎没 ...

  5. event driven model

    http://www.jdon.com/eda.html http://blog.csdn.net/gykimo/article/details/9182287 事件代表过去发生的事件,事件既是技术架 ...

  6. Domain Driven Design and Development In Practice--转载

    原文地址:http://www.infoq.com/articles/ddd-in-practice Background Domain Driven Design (DDD) is about ma ...

  7. 基于“事件”驱动的领域驱动设计(DDD)框架分析

    摘抄自 从去年10月份开始,学了几个月的领域驱动设计(Domain Driven Design,简称DDD).主要是学习领域驱动设计之父Eric Evans的名著:<Domain-driven ...

  8. [转] DDD领域驱动设计框架分享

    从去年10月份开始,学了几个月的领域驱动设计(Domain Driven Design,简称DDD).主要是学习领域驱动设计之父Eric Evans的名著:<Domain-driven desi ...

  9. Disruptor——一种可替代有界队列完成并发线程间数据交换的高性能解决方案

    本文翻译自LMAX关于Disruptor的论文,同时加上一些自己的理解和标注.Disruptor是一个高效的线程间交换数据的基础组件,它使用栅栏(barrier)+序号(Sequencing)机制协调 ...

随机推荐

  1. windbg分析一次大查询导致的内存暴涨

    项目上反馈了一个问题,就是在生产环境上,用户正常使用的过程中,出现了服务器内存突然暴涨,客户有点慌,想找下原因. 讲道理,内存如果是缓慢上涨一直不释放的话,应该是存在内存泄漏的,这种排查起来比较困难, ...

  2. cc40a_demo_Cpp_智能指针c++_txwtech

    //40_21days_Cpp_智能指针c++_cc40a_demo.cpp_txwtech //智能指针.auto_ptr类//*常规指针-容易产生内存泄漏,内存被占满,程序就死机,或者系统死机// ...

  3. CRC16冗余循环检测计算器-好用。modbus RTU

    开始使用 http://cht.nahua.com.tw/index.php?url=http://cht.nahua.com.tw/software/crc16/&key=Modbus,%2 ...

  4. 如何从OutLook正确取得定期会议的时间?(待解决)

    背景: 用Microsoft.Office.Interop.Outlook取得日历项,然后根据业务要求筛选. 现象: 如果是定期会议,使用AppointmentItem.Start/End取得的是该定 ...

  5. C/S C# WPF锐浪报表教程

    前言:锐浪报表是一种中国式报表的报表开发工具.博主使用锐浪报表有一段时间了,积累了一些经验希望能帮助你快速掌握并使用 第一章:集成项目 首先我们先去锐浪报表官网下载并安装锐浪报表. 创建WPF应用程序 ...

  6. 多语言工作者の十日冲刺<2/10>

    这个作业属于哪个课程 软件工程 (福州大学至诚学院 - 计算机工程系) 这个作业要求在哪里 团队作业第五次--Alpha冲刺 这个作业的目标 团队进行Alpha冲刺--第二天(05.01) 作业正文 ...

  7. 【Java】HashMap实现原理---数据结构

    作为一个程序猿,特别是Java后端的,应该全部人都用过HashMap,也都知道HaspMap是一个用于存储Key-Value键值对的集合.与此同时我们把每一个键值对也叫做 Entry. 而这些Entr ...

  8. C#数据结构与算法系列(十五):排序算法(SortAlgorithm)

    1.介绍 排序是将一组数据,以指定的顺序进行排序的过程 2.分类 内部排序法:指将需要处理的所有数据都加载到内部存储器中进行排序 外部排序法:数据量过大,无法全部加载到内存中,需要借助外部存储进行排序

  9. scheduler的调度规则

    对爬虫的请求进行调度管理 允许接收requests并且会调度一个request去下载,且具有去重机制 优先级和队列不会被调度器执行(调度器不管优先级的问题),用户使用字段给每个Request对象,可以 ...

  10. mdcChipSet中mdcChip事件selectedChange

    项目中遇到一个问题,由于每个mdcChip上都有一个change事件,所以想在change事件中操作执行最新被选中的item时,就会遇到一些麻烦. 如何解决呢? 全局设置一个变量,例如:mark 然后 ...