什么是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. 开源一款超实用的 Dubbo 测试工具,已用半年,感觉很有feel~

    不知道你是否在工作中有遇到过类似情况: dubbo接口调试复杂,需要通过telnet命令或者通过consumer调用来触发. telnet语句参数格式复杂,每次编写都要小心谨慎,一旦出错又需重来. 复 ...

  2. 2.K8S的核心资源管理方法

    目录 1.1陈述式资源管理方法 1.1.1.管理名称空间资源 1.1.2.管理Deployment资源 1.1.3.管理Service资源 1.1.4.kubectl用法总结 1.2.声明式资源管理方 ...

  3. WeChair项目Alpha冲刺(7/10)

    团队项目进行情况 1.昨日进展    Alpha冲刺第七天 昨日进展: 前端:页面修改和完善,安排页面美化 后端:和前端成功交互,数据解密成功 数据库:修改数据表属性,与后端部署数据库交互 2.今日安 ...

  4. disruptor架构二

    小故事:Disruptor说的是生产者和消费者的故事. 有一个数组.生产者往里面扔芝麻.消费者从里面捡芝麻. 但是扔芝麻和捡芝麻也要考虑速度的问题. 1 消费者捡的比扔的快 那么消费者要停下来.生产者 ...

  5. Django的F查询和Q查询,事务,ORM执行原生SQL

    F查询和Q查询,事务及其他   F查询和Q查询 F查询 在上面所有的例子中,我们构造的过滤器都只是将字段值与某个我们自己设定的常量做比较.如果我们要对两个字段的值做比较,那该怎么做呢? Django ...

  6. script写在head与写在body中的区别

    咱先说将Javascript写在head里面的情况吧,如果你要在这里面去操控DOM元素,是会报错的,因为浏览器是先执行head标签里面的内容,在执行时你的DOM元素还没有生成.(使用了windows. ...

  7. ES6躬行记 笔记

    ES6躬行记(18)--迭代器 要实现以下接口## next() ,return,throw 可以用for-of保证迭代对象的正确性 例如 var str = "向

  8. dart快速入门教程 (3)

    3.运算符 运算符本质上就是代表某运算规则的符号,例如: + ,这个符号,代表着数学运算里面的加法,按照加法法则进行运算即可,同理,学习运算符就是掌握这些规则而已 3.1.算术运算符 算术运算符主要包 ...

  9. Js中各种类型的变量在if条件中是true还是false

    如果操作数是一个对象,返回true如果操作数是一个空字符串,返回false如果操作数是一个非空字符串,返回true如果操作数是数值0,返回false如果操作数是任意非0数值(包括Infinity),返 ...

  10. 序列推荐(transformer)

    目录 Attention演进(RNN&LSTM&GRU&Seq2Seq + Attention机制) LSTM GRU Seq2Seq + Attention机制 Attent ...