【架构学习】事件驱动架构模型的分析

1,027 阅读6分钟

「这是我参与2022首次更文挑战的第28天,活动详情查看:2022首次更文挑战

事件驱动架构

事件驱动架构是一个流行的分布式异步架构,目标是高伸缩性. 可适应小型程序或大型程序. 事件驱动架构是由高度解耦且目标单一的组件组成, 这些组件上,接收和处理都是异步的.

这种架构模式包含两个主要的拓扑(mediator和broker). mediator下面简称协调者,broker简称中间件.

协调者拓扑的应用场景: 需要一个中央协调者来协调一个事件中的多个步骤, 换句话说,一个事件中的多个步骤需要进行编排时,用中央协调者.

当不想使用中央协调者拓扑,可以将事件组成一个事件链, 这叫做中间件拓扑.

这两种拓扑的特征和实现策略均不一致,只有了解这两种拓扑 才能为实际的场景选出合适的架构.

协调者拓扑 Mediator Topology

如果一个事件有多个步骤,这时需要为事件编排处理过程, 这种场景适合用协调者拓扑. 在编排的过程中,需要确定步骤执行的顺序,已经哪些需要串行, 哪些可以并行.

协调者拓扑的事件驱动架构,有4个主要的组件:

  • 事件队列
  • 事件协调者
  • 事件通道
  • 事件处理者

一个事件处理流程如下: 客户端发送事件到事件队列; 事件队列将事件传递给事件协调者; 事件协调者接收事件,并编排,发送额外的异步事件给事件通道; 事件处理者监听事件通道,并处理业务逻辑.

一个事件驱动架构中,通常有十几或几百个事件队列. 架构模式中并未指定事件队列组件的实现,所以可以是一个消息队列, 或是一个web服务端点,或是消息队列和web服务端点的组合.

这里的事件有两种类型:初始事件和处理中的事件. 初始事件是事件协调者接收到的原始事件,处理中的事件是由 事件协调者生成,并有事件处理者接收的事件.

事件协调者负责将初始事件编排为多个步骤,每个步骤都会发送 一些包含指定任务的事件给事件通道,这些事件会被事件处理者接收. 事件协调者不执行事件对应的业务逻辑.

通过事件通道,事件协调者可以异步传递事件给事件处理者, 事件通道可以是消息队列或消息主题(message topics), 消息主题应用的会更加广泛,因为通过消息主题,可用多个消息处理者来 "处理中的消息".

事件处理者组件包含了应用程序的业务逻辑.组件具有以下特点: 自包含/独立/高解耦.组件只执行一个特定的任务. 组件的颗粒度可粗可细,细的可以只计算丢包率,粗的可以计算火箭升空角度. 总的来说,一个组件最好只做一个业务任务,不要依赖其他的组件.

事件协调者的实现方式众多,最简单最常用的方式是开源的集成中心, eg:spring integration,apache camel,mule esb. 这些开源库通常是通过java或dsl实现,如果要处理更复杂的协调和编排, 可以使用bpel语言写的bpel引擎,开源的有apache ode. 一般越大型的程序,编排会越复杂,可以使用业务处理管理器bpm, jBPM就是一个例子.

需求和正确和时间协调者匹配是成功的关键. 开源的集成中心不适合处理非常复杂的业务,bpm也只适合简单路由逻辑.

中间件拓扑 Broker Topology

中间件拓扑没有消息协调者,相反消息流流经一个个事件处理组件, 通过轻量级的中间件,这就像链式一样.

如果事件相对简单,又不想用事件编排,中间件拓扑就非常适用.

使用中间件拓扑时,组件有两类:一类是事件处理组件,一类是中间件. 中间件可以是集中式,也可以是联邦式.中间件包含事件流中的事件通道.

中间件内部的事件通道可以是消息队列,也可以是消息主题,或两者的组合.

事件处理组件除了执行事件处理,还会发布一个表示执行完成的新事件. 这个新事件作为其他事件处理组件的输入.处理完之后可能会有多个输出. 在这个链上不断传递,直到没有新的事件产生,表示初始事件执行完成.

中间件中没有协调者,是由事件处理组件直接接收.

中间件,类似于接力赛.

注意事项

相比分层架构模式的实现,事件驱动会复杂一些,这是因为异步分布式的关系. 分布式架构的几个问题也需要考虑:远端可用性,响应丢失,中间件重连逻辑, 协调者重连逻辑.

另外要考虑的是选择事件驱动架构模式时,单个业务流程是缺少原子事务的. 原因是事件处理组件是高解耦且还是分布式的, 在他们之间维护事务单元非常困难. 所以在使用事件驱动架构时,需要想好事件是否可以独立, 事件处理的颗粒度如何抉择.

如果需要拆分出一个单独的单元来处理跨事件处理组件的事, 特别是这个单元做的是不可分割的事务,那么这个架构设计不适合应用程序.

事件驱动架构最难的就是对事件处理组件约定的创建/维护/治理. 每个事件都有自己的约定,使用此模式时确定标准的数据格式非常重要, 还需要从一开始就建立对约定版本的控制.

模式分析

具体的分析看附录

整体灵活性

高,事件处理组件是单一目标,完全解耦(意味着隔离), 所以整体的变更不会影响到现有组件.

部署难度

低,组件独立意味单独部署,单一组件的变更不会影响之前的部署. 中间件拓扑比协调者拓扑部署简单,因为事件协调者和事件处理是紧凑的.

可测试性

低,单个组件的测试不困难,但需要测试客户端生成事件,顺序还有要求. 模式的异步特性让测试变得复杂.

性能

高,消息基础设施不够好,会导致性能不好. 异步模式就是提高性能的,换句话说:解耦+并发的消耗远小于 消息的排队和出队.

可伸缩性

高,事件处理组件的独立和解耦,是高可伸缩性的保障, 每个组件都可伸缩.

开发难度

高,这个模式需要解决一些异步带来的复杂问题, 约定的创建/对无响应事件处理组件的处理/对中间件失败的处理. 这些都是很复杂的问题.