前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >与我一起学习微服务架构设计模式6—使用事件溯源开发业务逻辑

与我一起学习微服务架构设计模式6—使用事件溯源开发业务逻辑

作者头像
java达人
发布2019-11-18 21:44:23
1.1K0
发布2019-11-18 21:44:23
举报
文章被收录于专栏:java达人java达人

使用事件溯源开发业务逻辑

事件溯源是构建业务逻辑和持久化聚合的另一种选择,它将聚合以一系列的方式持久化保存,每个事件代表聚合的一次状态变化。应用通过重放事件来重新创建聚合的当前状态。

好处:

  • 保留聚合的历史记录(审计和监管)
  • 可靠地发布领域事件(微服务架构)

弊端:

  • 有一定学习曲线
  • 查询事件存储库通常很困难,这需要CQRS模式
传统持久化技术的问题

对象与关系的阻抗失调

关系数据库的表格结构模式与领域模型及其复杂关系的图状结构之间,存在基本的概念不匹配问题。

缺乏聚合的历史

只存储聚合的当前状态,聚合更新后先前的状态丢失

实现审计功能将非常繁琐且容易出错

这是项耗时的工作,记录审计的代码可能会和业务逻辑代码偏离

事件发布是凌驾于业务逻辑之上

不支持发布领域事件,开发人员必须自己处理事件生成的逻辑。

事件溯源

事件溯源通过事件来持久化聚合

事件溯源采用基于领域事件的概念来实现聚合的持久化,将每个聚合持久化为数据库中的一系列事件。

应用程序从事件存储中检索并重放事件来加载聚合。

1、加载聚合的事件

2、使用其默认的构造函数创建聚合实例

3、调用apply()方法遍历事件

事件代表状态的改变

事件必须包含执行状态更改所需要的数据

聚合方法都和事件相关

业务逻辑通过调用聚合根上的命令方法来处理对聚合的更新请求。命令方法通常会验证其参数,而后更新一个或多个聚合字段。

基于事件溯源的应用程序的命令方法则会生成一系列事件,并应用于聚合以更新其状态。

使用乐观锁处理并发更新

乐观锁通常使用版本列来检测聚合自读取以来是否已更改。只有当前版本和应用程序读取聚合时版本一致,此UPDATE语句才会成功。

事件溯源和发布事件

可以将事件溯源作为可靠的事件发布机制。将这些持久化保存的事件传递给所有感兴趣的消费者。

使用轮询发布事件

关于确定新事件,让事件发送方记录它已处理的最后一个eventId,使用select语句查询新事件,问题在于事务可以按照与生成事件不同的顺序提交,事件发布方可能意外跳过事件,解决方案是向EVENTS表添加一个列,以跟踪事件是否已发布。

使用事务日志拖尾技术来可靠地发布事件

使用快照提升性能

长生命周期的聚合可能有大量事件,可定期持久保存聚合状态的快照。应用通过加载最新快照以及仅加载快照后发生的事件来快速恢复聚合状态。

幂等方式的消息处理

基于关系型数据库事件存储库的幂等消息处理

将message ID插入PROCESSED_MESSAGES表,作为插入EVENTS表的事件的事务的一部分,以检测和丢弃重复消息。

基于非关系数据库事件存储库的幂等消息处理

NOSQL的事件存储库事务模型功能有限,简单的解决方案是消息的ID存储在处理它时生成的事件中,通过验证聚合的所有事件中是否有包含该消息的ID来做重复检测。

领域事件的演化

事件的结构经常随着时间的推移而变化,应用程序可能需要处理多个事件版本。

事件结构的演化

服务的领域模型随着时间的推移而发展,向事件添加字段,不大可能影响接收方。但更改字段名词等操作不向后兼容。

通过向上转换来管理结构的变化

事件溯源应用可以使用类似Flyway的方法处理向后兼容的更改。从事件存储库加载事件时,将各个事件从旧版本更新为新版本。

事件溯源的好处
  • 可靠地发布领域事件
  • 保留聚合的历史
  • 最大程度避免对象与关联的“阻抗失调”问题
  • 为开发者提供一个“时光机”
事件溯源的弊端
  • 有一定学习曲线
  • 基于消息传递的应用程序的复杂性(消息代理确保至少一次成功传递,这意味着非幂等的事件处理程序必须检测并丢弃重复事件)
  • 处理事件的演化有一定难度
  • 删除数据存在一定难度
  • 查询事件存储库很有挑战性

实现事件存储库

使用事件溯源的程序将事件存储在事件存储库,事件存储库是数据库和消息代理功能的组合。

一些专用事件存储库:如Event Store、Lagom、Axon、Eventuate。

如Eventuate Local包含一个存储事件的事件数据库(MySQL),一个向订阅者传递事件的事件代理(Kafka),以及一个将事件数据库中存储的事件发布到消息代理的事件中继。

同时使用Saga和事件溯源

使用事件溯源实现协同式Saga

事件溯源的事件驱动属性使得实现基于协同式的Saga非常简单,当聚合被更新,它会发出一个事件。不同聚合的事件处理程序可以接受事件,并更新聚合。事件溯源代码提供了Saga所需的机制,包括消息传递的进程间通信、消息去重等。

但问题在于,事件体现处理双重目的,使用事件来表示状态更改,但是使用事件实现Saga协同,需要聚合即使在没有状态更改也必须发出事件。

最好使用编排式来实现复杂的Saga。

创建编排式Saga

基于事件溯源的业务逻辑与基于编排的Saga相结合更具挑战性。

当关系型数据库作为事件存储库时,应该如何创建Saga编排器

它可以在同一个ACID事务中更新事件存储库并创建Saga编排器。

当非关系型数据库作为事件存储库时,应该如何创建Saga编排器

使用基于NOSQL的事件存储库的服务很可能无法以原子方式更新事件存储库并创建Saga编排器。服务必须具有一个事件处理程序,该事件处理程序将创建Saga编排器来响应聚合发出的领域事件,它必须处理重复事件,至少一次消息传递意味着可以多次调用创建Saga的事件处理程序。

实现基于事件溯源的Saga参与方

命令式消息的幂等处理

Saga参与方在处理消息时生成的事件中记录消息ID。在更新聚合之前,Saga参与方通过在事件中查找消息ID来验证它之前是否处理过该消息

以原子方式发送回复事件

Saga编排器可以订阅聚合发出的事件,但这方法存在两个问题。

1、Saga命令可能不会实际改变聚合的状态,聚合不会发出事件

2、需要Saga编排器区别处理使用事件溯源的Saga参与方与不使用事件溯源的Saga参与方。

更好的方法是让Saga参与方继续向Saga编排器的回复通道发送回复消息。

基于事件溯源的Saga编排器

使用事件溯源持久化Saga编排器

可使用以下事件持久化Saga:

  • Saga编排器被创建
  • Saga编排器被更新

可靠地发送命令式消息

Saga编排器使用两步命令:

1、Saga编排器发送SagaCommandEvent,这些事件存储在事件存储库中

2、事件处理程序处理SagaCommandEvents并将命令式消息发送到目标消息通道。

这两步法可确保命令至少发送一次。

保证唯一的SagaCommandEvent的ID被用作命令式消息的ID,重复的消息具有相同的ID,接收重复命令式消息的Saga参与者将使用前述机制丢弃它。

确保只处理一次回复消息

Saga编排器还需要检测并丢弃重复的回复消息,可以将回复消息的ID存储在处理回复时发出的事件中,然后它可以确定消息是否重复。

本文参与 腾讯云自媒体分享计划,分享自微信公众号。
原始发表:2019-11-10,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 java达人 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 使用事件溯源开发业务逻辑
    • 传统持久化技术的问题
    • 事件溯源
      • 使用乐观锁处理并发更新
        • 事件溯源和发布事件
          • 使用快照提升性能
            • 幂等方式的消息处理
              • 领域事件的演化
                • 事件溯源的好处
                  • 事件溯源的弊端
                  • 实现事件存储库
                  • 同时使用Saga和事件溯源
                    • 使用事件溯源实现协同式Saga
                      • 创建编排式Saga
                        • 实现基于事件溯源的Saga参与方
                          • 基于事件溯源的Saga编排器
                          相关产品与服务
                          对象存储
                          对象存储(Cloud Object Storage,COS)是由腾讯云推出的无目录层次结构、无数据格式限制,可容纳海量数据且支持 HTTP/HTTPS 协议访问的分布式存储服务。腾讯云 COS 的存储桶空间无容量上限,无需分区管理,适用于 CDN 数据分发、数据万象处理或大数据计算与分析的数据湖等多种场景。
                          领券
                          问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档