利用发布订阅模式来解耦不同架构层级,亦可用于解决隔离业务之间的交互
优点:
松耦合
横切关注点
可测试性
事件驱动
发布订阅模式发布者通过调度中心将消息发送给订阅者。调度中心解决发布与订阅者之间的关系,保证消息可以送达订阅者手中。
发布者与订阅者互不相识,发布者只管向调度中心发布消息,而订阅者只关心自己订阅的消息类型
多订阅者保序执行在常见的发布订阅模式中,的确很少见到类似的说法。但在实际业务中我们会有类似的需求,一个消息由调度中心协调多个订阅者按照顺序执行消息,同时还可以将上一个订阅者处理过的消息传递给下一个订阅者。这样既可以保留发布订阅模式的特性,又有了顺序执行逻辑的特性。
一个小思考:如果 EventBus 的配置支持动态调整的话,是否业务的执行顺序也可以被动态排列组合?
换句话说它或许可以为进程内工作流提供了一个可能性
Event Sourcing(事件溯源)一种事件驱动的架构模式,可以用于审计和溯源
基于事件驱动架构
以事件为事实
业务数据由事件计算产生的视图,可以持久化也可以不持久化
CQRS(命令查询的责任分离)CQRS 是一种架构模式,能够使改变模型与查询模型的实现分离
Event Sourcing & CQRS事件溯源可以与 CQRS 很好的配合
在 Command Handler 中持久化事件到 Event Store 的同时实时计算一个最终视图给 View DB 用于查询展示
在 Query 中既可以通过 View DB 获取最新状态,也可以通过 Event Store 来重放事件来校验 View 或用于更严谨的业务
SagaSaga 是一个长活事务被分解成可以交错运行的子事务集合。其中每个子事务都是一个保持数据库一致性的真实事务
每个 Saga 由一系列 sub-transaction Ti 组成
每个 Ti 都有对应的补偿动作 Ci,补偿动作用于撤销 Ti 造成的结果
两种执行顺序
T1, T2, T3...[Tx retry]...,Tn
T1, T2, ..., Tj, Cj,..., C2, C1
两种恢复策略
backward recovery,向后恢复,补偿所有已完成的事务,如果任一子事务失败。即上面提到的第二种执行顺序,其中 j 是发生错误的 sub-transaction,这种做法的效果是撤销掉之前所有成功的 sub-transation,使得整个 Saga 的执行结果撤销
forward recovery,向前恢复,重试失败的事务,假设每个子事务最终都会成功。适用于必须要成功的场景,执行顺序是类似于这样的:T1, T2, ..., Tj(失败), Tj(重试),..., Tn,其中 j 是发生错误的 sub-transaction。该情况下不需要 Ci
BuildingBlocks 的类视图作为接口标准,BuildingBlocks 中并没有过多的干涉实现方式,它只保留了最基础的功能流程限制,以达到最小 EventBus 的功能集合。至于最终是基于接口还是特性来实现订阅关系的,交还给 Contrib 自行决定。
事件用于本地事件的发布/订阅
IEvent:事件接口,IEvent<TResult>为带返回值的基础事件接口
IEventHanldler<TEvent>:事件处理器接口,ISagaEventHandler<TEvent>为 Saga 的实现提供了基础接口要求
IMiddleware<TEvent>:中间件接口,允许在事件执行前挂载预处理动作和时间执行后的收尾动作
IEventBus:事件总线接口,用于发送事件,并提供订阅关系维护和附加功能执行
集成事件用于跨进程事件的发布/订阅
IntegrationEventLog:集成事件日志,用于实现本地消息表的消息模型
IIntegrationEventLogService:集成事件日志服务接口
ITopic:发布/订阅的主题
IIntegrationEvent:集成事件接口
IIntegrationEventBus:集成事件总线,用于跨进程调用的事件总线
CQRS用于使改变模型与查询模型的实现分离
IQuery<TResult>:查询的接口
IQueryHandler<TCommand,TResult>:查询处理器接口
ICommand:可用于增删改等指令的接口
ICommandHandler<TCommand>:指令处理器接口
Event Bus要完成上述的这些功能,我们需要借助于 EventBus,它需要有以下基础功能
接收事件
维护订阅关系
转发事件
接收与转发事件这两个功能其实可以合并为一个接口,由发布者调用 Publish,再由 Event Bus 根据订阅关系转发即可
维护订阅关系在.Net 项目中,我们常见的用于扫描自动注册的方式是接口和特性