事件驱动架构模式是一种非常流行的分布式异步架构模式,经常被用与构建高可伸缩性的应用程序。当然它也适合小型应用,复杂应用和规模比较大的应用。这种架构模式由一系列高度解耦的、异步接收和处理事件的单一职责的组件所组成。
事件驱动架构由两个主要的拓扑组成,分别是调停者拓扑和代理者拓扑。调停者拓扑通过一个中央的调停者来编排各种处理步骤。然而代理者拓扑适用于那些当你想将事件链式的聚在一起但不使用中央调停者的情况。由于这两种模式特性以及实现均不一样,所以理解哪一个模式最适合你的实际情况是非常重要的。
调停者拓扑
调停者拓扑适合那些有很多步骤需要处理,并且需要按照某种程度的编排来处理的事件。举个例子,一个处理股票交易的事件首先需要你首先验证交易的本身合法性,然后检查这个股票交易是否合规,然后把股票交给股票代理商,计算佣金,然后通过代理商将股票移送给客户。这些步骤都需要一个编排中心来决定这些步骤的顺序,并且决定哪些能是串行的,哪些是并行的。
调停者拓扑主要有4个主要的架构组件组成:事件队列(Event Queue)、调停者(Mediator)、事件通道(Event Channel)和事件处理器(Event Processor)。
事件流通过客户端发送到消息队列,事件队则传递消息到调停者。调停者接收到队列传递过来的原始消息,然后编排成异步的消息发送到事件通道,事件通道则通过事件处理器执行处理过程的每一步。事件处理器则监听事件通道,根据自身不同的业务逻辑来处理从调停者接受的事件。图2-1说明了事件驱动架构中通用的调停者拓扑架构:
通常来说可以形成拥有十几个到几百个事件队列的事件驱动的体系结构。这种架构并没有规定事件队列组件如何实现,可以是一个消息队列,一个 Web Service终端,等等,或者任何包含这些方式的组合。
这种模式有两种事件类型:初始化事件和待处理事件。初始化事件是调停者接受到的原始事件,待处理事件是由调停者生成的事件,并由事件处理器接收。
事件调停者的责任就是编排传递进来的初始化事件。对于初始化事件的每一步,调停者都会通过事件通道发送一个具体的待处理事件。然后被事件处理器接收并处理。很重要的一点需要记住,事件调停者并不处理任何的业务逻辑,它只是知道处理这些初始化时候需要哪些步骤。
事件通道被事件调停者用来异步传递待处理消息到事件处理器。事件通道可以是一个消息队列(点对点),也可以是一个消息主题(发布/订阅),尽管消息主题的传输模式被调停者拓扑广泛使用,以便待处理事件能够同时被多个事件处理器处理(每个事件处理器根据接受的事件处理的任务是不同的)。
事件处理器包含了处理待处理事件的业务逻辑。每一个事件处理器相对于整个应用程序来说都是自包含的,独立的,高度解耦的,并且只处理指定的任务。然而每一个事件处理器的划分粒度可以从细粒度(比如只计算一个订单的销售税)到粗粒度(比如处理保险理赔)。但是无论怎样,记住重要的一点,每一个事件处理器都只处理单个业务任务并且不依赖其他事件处理器的结果。
事件调停者可以有多种方式来实现。作为一个架构师,你应该了解每一种实现的选项以便选择一个更适合你的需求的实现。
最简单和最通用的调停者实现就是用开源的集成中心,比如Spring Integration, Apache Camel或者Mule ESB。这些开源的集成中心的事件流通常都是Java实现或者通过DSL(领域特定语言)来实现。对于更复杂的调解与编排,可以通过与开源的BPEL引擎比如Apache ODE相结合,使用BPEL(业务流程执行语言)来实现。
BPEL是标准的类XML的语言,用来描述处理初始化事件需要的数据和步骤。对于那些更复杂的应用程序,可以使用业务流程管理,比如jBPM实现。
理解你的需求并且选择合适的实现对于使用这种拓扑结构的事件驱动架构的成功起着决定性的作用。与使用BPM只是来解决简单的路由逻辑一样,使用开源的集成中心来处理非常复杂的业务流程的编排,必然会也会导致失败。
为了阐明事件调停者是如何工作的,假设你向一家保险公司投保了并且现在打算搬家。在这种情况下,初始的事件可能会叫做“重新安置事件”。事件调停者处理这个“重新安置事件”的步骤包含在图2.2中。对于每一个初始化的事件步骤而言,事件调停者会创建一系列的待处理事件(比如“修改地址”,“重新计算报价”等待),发送这些待处理事件到事件通道并且等待相应的事件处理器处理(比如客户处理器,报价处理器等)这个处理过程会一直等到所有的步骤都处理完成才结束。在重新计算报价和更新索赔之间有个小棒,表示这可以并行地处理。