事件驱动架构
事件驱动架构(Event Driven Architecture)是一种分布式异步架构模式,用于创建可伸缩的应用程序,可用于小规模或大规模的应用程序,是解耦复杂系统组件的一种处理手段。
事件驱动架构模式主要包含两种实现方式,分别是调停者拓扑(Mediator Topology),代理者拓扑(Broker Topology)。Mediator 拓扑结构需要在一个事件通过 Mediator 时精心安排好具体的步骤,而 Broker 拓扑结构无需 Mediator ,而是由你串联起几个事件。
本文主要参考:Software Architecture Patterns > Chapter 2. Event-Driven Architecture
事件驱动架构
调停者拓扑
调停者拓扑(Mediator Topology,或译为:中介者拓扑) 需要编排多种事件,需要在一个事件通过 Mediator 时安排好具体的步骤,适合有多个步骤的事件。(有点工作流的感觉)
比如在交易系统中,每个请求流程必须经过特定的步骤,如验证、订单、配送,以及通知买家等。在这些步骤中,有些步骤是串行,有些可以并行完成。
通常,架构主要包含4种组件:
- 事件队列(Event Queue)
- 调停者(Mediator)
- 事件通道(Event Channel)
- 事件处理器(Event Processor)
调停者(Mediator)是一个事件中枢处理单元,知道事件的处理流程,但不执行具体的事件业务处理逻辑。根据事件的特征对初始事件进行拆分编排为处理事件并进行分发。处理事件之间没有明显的顺序依赖,各自独立。
事件处理器(Event Processor)是一组各自独立的组件,彼此之间没有依赖,自包含,不依赖于其他 Processor 的处理结果,这是他们的显示著特征。
客户端创建事件,并将其发送到事件队列,调停者接收初始事件后编排成处理事件异步发送给事件通道。事件通道将处理事件传递给事件处理器,事件最终由事件处理器处理完成(或事件处理器监听事件通道接收事件处理业务逻辑)。
这里有两种事件:初始事件 和 处理事件。Mediator 将初始事件编排成处理事件,它没有具体的业务逻辑,只是一个协调者,负责将初始事件转化成一个或多个处理事件。
调停者不会处理也不知道任何业务逻辑,它只编排事件。事件调停者知道每种事件类型的必要步骤。业务逻辑或者处理发生在事件处理器中,事件通道、消息队列或者消息主题用于传递事件给事件处理器。事件处理器是自包含和独立的,解耦于架构。理想情况下,每种事件处理器应只负责处理一种事件类型。
通常,企业服务总线、队列或者集线器可以用作事件调停者。有一些开源的框架实现了这种架构,如 Spring Integration, Apache Camel, 或者 Mule ESB。面对复杂的业务场景往往要考虑引入这种企业服务总线的解决方案。其本质就是事件驱动。
示例:以一个处理保险流程的例子来说明,如图:
Event Mediator 接收到一个 Relocation Event 原始事件之后,折分成 Change Address(变更地址),Recal Quote(重新报价),Update Claims(更新索赔),Adjust Claims(调整索赔),Notify Insured(通过被保险人)。这些 Event 彼此独立,经由各自的 Event Channel 发送到不同的 Event Processor 处理。
代理者拓扑
代理者拓扑(Broker Topology):不同于调停者拓扑(Mediator Topology),它没有中心的 Mediator,不使用任何集中的编排,而是在事件处理器之间使用简单的队列或者集线器,事件处理器知道处理事件的下一个事件处理器。
代理者拓扑(Broker Topology)主要由 Event Processor 和 Event Channel 构成,较为简单,事件之间可能彼此是相互关联的。例如,一个 Event Processor 的处理结果是下一个 Event Processor 需要消费的事件,每个 Processor 必须完成自己的工作,其他 Processor 才能开始执行,整个事件处理过程像一条彼此相扣的链条,只有整个流程结束才能形成一个完整的业务逻辑。(类似于职责链或管道模式)。
示例:同样以一个处理保险流程的例子来说明,如图:
应用示例:
新浪微博的早期架构中,微博发布使用同步推模式,用户发表微博后系统会立即将这条微博插入到数据库所有粉丝的订阅列表中,当用户量比较大时,特别是明星用户发布微博时,会引起大量的数据库写操作,超出数据库负载,系统性能急剧下降,用户响应延迟加剧。
后来新浪微博改用异步推拉结合的模式,用户发表微博后系统将微博写入消息队列后立即返回,用户响应迅速,消息队列消费者任务将微博推送给所有当前在线粉丝的订阅列表中,非在线用户登录后再根据关注列表拉取微博订阅列表。(很多场景里面我们引入MQ来解耦,现在淘宝的架构基本上是异步走MQ了)。
事件驱动架构分析
事件驱动架构因其分布式和异步的性质,实现相对复杂。需要面对很多问题,比如网络分区、调停者失败、重新连接逻辑等。
由于这是一个分布式且异步的模式,多个分布式系统之间的交互,系统之间的稳定调用、业务的延迟敏感性等都是要必须考量的因素,尤其是在业务逻辑拆分成多个分布式执行单元之后,他们不再是一组完整的原子执行单元,而是变成了分布式事务,就比较麻烦,得需要一个事务协调器(分布式事务),加剧了这程架构模式设计的复杂度。因而在设计这种架构时,Event 是否能够独立完成,是否要依赖于其他事件,是否是一组无法分割的事务单元都在影响着事件的拆分粒度。
事件驱动架构度量:
- 敏捷性:事件和事件处理器之间解耦,且可独立维护,敏捷性强。变化可以快速、轻松地完成,而不会影响整个系统。
- 易于部署:由于架构是解耦的,因此很容易部署。组件可以独立部署,并且可以在调停者上注册。部署在代理者拓扑上也相当简单。
- 可测试性:虽然独立测试组件很容易,但测试整个应用程序很有挑战。因此端到端的测试是很难的。
- 性能:事件驱动架构性能非常好,因为它是异步的。此外,事件通道和事件处理器可以并行工作,因为它们是解耦的。
- 可伸缩性:事件驱动架构的伸缩性非常好,因为组件之间解耦,组件可以独立扩展。
- 可开发性:这种架构的开发不是很容易。需要明确定义契约,错误处理和重试机制得处理得当。