CQRS & Event Sourcing — 解决检索应用程序状态问题的一剂良方

现在,每个开发人员都很熟悉MVC标准体系结构设计模式。大多数的应用程序都是基于这种体系结构进行创建的。它允许我们创建可扩展的大型企业应用程序,但近期我们还听到了另外的一些有关于CQRS/ES的相关信息。这些方法应该被放在MVC中一起使用吗?他们可以解决什么问题?现在,让我们一起来看看CQRS/ES是什么,以及他们都有哪些优点和缺点。

CQRS — 模式介绍

CQRS(Command Query Responsibility Segregation)是一种简单的设计模式。它衍生与CQS,即命令和查询分离,CQS是由Bertrand Meyer所设计。按照这一设计概念,系统中的方法应该分为两种:改变状态的命令和返回值的查询。Greg young将引入了这个设计概念,并将其应用于对象或者组件当中,这就是今天所要将的CQRS。它背后的主要思想是应用程序更改对象或组件状态(Command)应该与获取对象或者组件信息(Query)分开。

下面,将通一张图来说明应用程序中有关CQRS部分的组成结构:

Commands(命令)—表示用户的操作意图。它们包含了与用户将要对系统执行操作的所有必要信息。

  • Command Bus(命令总线):是一种接收命令并将命令传递给命令处理程序的队列。
  • Command Handler(命令处理程序):包含实际的业务逻辑,用于验证和处理命令中接收到的数据。Command handler负责生成和传播域事件(Event)到事件总线(Event Bus)。
  • Event Bus(事件总线):将事件发布给订阅特定事件类型的事件处理程序。如果存在连续的事件依赖,事件总线可以使用异步或者同步的方式将事件发布出去。
  • Event Handler(事件处理程序):负责处理特定类型的事件。它们的职责是将应用程序的最新状态保存到读库中,并执行终端的相关操作,如发送电子邮件,存储文件等。

Query(查询):表示用户实际可用的应用程序状态。获取UI的数据应该通过这些对象完成。

下面我们将介绍有关CQRS的诸多优点,它们是:

  • 我们可以给处理业务逻辑部分和处理查询部分的开发人员分别分配任务,但需要小心的是,这种模式可能会破坏信息的完整性。
  • 通过在多个不同的服务器上扩展Commands和Query,我们可以进一步提升应用程序的读/写性能。
  • 使用两个不同的数据库(读库/写库)进行同步,可以实现自动备份,无需额外的干预工作。
  • 读取数据时不会涉及到写库的操作,因此在使用事件源是读数据操作会更快。
  • 我们可以直接为视图层构建数据,而无需考虑域逻辑,这可以简化视图层的工作并提高性能。

尽管使用CQRS模式具有上述诸多的优点,但是在使用前还需要慎重考虑。对于只具有简单域的简单项目,其UI模型与域模型紧密联系的,使用CQRS反而会增加项目的复杂度和冗余度,这无疑是过度的设计项目。此外,对于数据量较少或者性能要求较低的项目实施CQRS模式不会带来显著的性能提升。

Event Sourcing — 案例研究

有这样一个案例,我们想要检索任何一个域对象的历史状态数据,而且在任何时间都可以生成统计数据。我们想要检查上个月、上个季度或者过去任何时间的状态汇总。想要解决这个问题并不容易。我们可以在特定的时间范围内将额外的数据保存在数据库中,但这种方法也存在一些缺点。我们不知道范围应该是什么样子,以及未来统计数据需要哪些数据项。为了避免这些问题,我们可以每天为所有聚合创建快照,但它们同样会产生大量的冗余数据。

Event Sourcing(ES)似乎是目前解决这些问题的最佳方案。Event Sourcing允许我们将Aggregate(聚合)状态的每一个更改事件保存在Event Store的事件存储库中。通过Command Handler将事件写入到事件存储库中,并处理相关的逻辑。要创建Aggregate(聚合)对象的当前状态,我们需要运行创建预期域对象的所有事件并对其执行所有的更改。下面我们将通过一张图来说明这一架构设计方式:

下面我们将列举一些使用ES的优点:

  • 时间穿梭机:可以及时重建特定聚合的状态。每个事件都包含一个时间戳。根据这些时间戳可以在特定的时间内运行事件或者停止事件。
  • 自动审计:我们不需要额外的工作就可以检查出在特定的时间范围内谁做了什么以及改变了什么。这和可以显示更改历史记录的系统日志不同,事件可以告知我们每次更改背后所对应的操作意图。
  • 易于引入纠正措施:当数据库中的数据发生错误时,我们可以将应用程序的状态回退到特定的时间点上,并重建当时的应用程序状态。
  • 易于调试:如果应用程序出现问题,我们可以将特定事件内的所有事件取出,并逐条的重建应用状态,以检查应用程序可能出现问题的地方。这样我们可以更快的找到问题,缩短调试所需的时间。

Aggregates

Aggregate(聚合)一词在本文中多次被提及,那它到底是什么意思?Aggregate(聚合)来自于领域驱动设计(DDD)的一个概念,它指的是始终保持一致状态的实体或者相关实体组。我们可以简单的理解为接收和处理Command(包含Command Handler)的一个边界,然后根据当前状态生成事件。在通常情况下,Aggregate root(聚合根)由一个域对象构成,但它可以由多个对象组成。我们还需要注意整个应用程序可以包含多个Aggregate(聚合),并且所有事件都存储在同一个存储库中。

总结

CQRS/ES可以作为特定问题的解决方案。它可以在标准N层架构设计的应用程序的某些层中进行引入,它可以解决非标准问题,常规架构中我们所拿到的是最终状态,在很多情况下,固然当前状态很重要,但我们还需要知道当前状态是如何产生的。CQRS和ES两种概念应该一起使用吗?事实表明,并没有。我们想要统计任何时间范文内的域对象状态,而写库只能存储当前状态。引入CQRS并没能帮助我们解决这一问题。在下一章节中,我们将引入Axon框架,Axon框架时间了CQRS/ES,用于解决某些域对象的一些特定问题,尤其是收集历史统计数据。我们将阐述如何使用Axon框架实现CQRS/ES并实现与Spring Boot应用程的整合。

作者:LukaszKucik
链接:https://www.nexocode.com/blog/posts/cqrs-and-event-sourcing/
译者:谭朝红

译文:(译)CQRS & Event Sourcing - 解决检索应用程序状态问题的一剂良方

著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

cmd管道无法接收特定程序返回值_CQRS amp; Event Sourcing — 解决检索应用程序状态问题的一剂良方...相关推荐

  1. cmd管道无法接收特定程序返回值_渗透不会反弹shell?来教你写一个cmd的shell

    渗透不会反弹shell?来教你写一个cmd的shell 包含的库: #include #include #include #include #include #pragma comment(lib, ...

  2. Stackoverflow热门问题(二十二)-如何在Windows cmd中得到程序返回值?

    文章首发及后续更新:https://mwhls.top/2873.html 新的更新内容请到mwhls.top查看. 无图/无目录/格式错误/更多相关请到上方的文章首发页面查看. stackoverf ...

  3. 如何获取程序返回值,退出码,错误码

    在c/C++语言程序设计中,我们可能经常性的需要进行错误处理,异常处理等问题. 关于异常部分,主要就是C++异常了. 今天我们主要谈论c语言方面的一些问题:如何获取程序返回值,退出码,错误码. 1如何 ...

  4. 易语言取linux命令返回值,易语言取程序返回值写法

    公告: 为响应国家净网行动,部分内容已经删除,感谢读者理解. 话题:易语言取程序返回值写法回答:在易语言中,程序包括"处理程序"都有六部分组成.一.程序名,就是程序的名称,程序名不 ...

  5. java 中调用window系统中的文件,或者执行命令(shell、.CMD、.EXE)并获取返回值

    原文:http://blog.csdn.net/ligaoyang/article/details/6755327 测试能拿返回值,但是在getErrorStream里, import java.io ...

  6. 【C 语言】C 项目开发代码规范 ( 形参合法性判断 | 函数返回值局部变量 | 函数中不用全局变量 | 函数中使用局部变量接收形参 | 函数返回值 | 形参作返回值 | 形参返回值处理 )

    文章目录 一.C 项目开发代码规范 一.C 项目开发代码规范 上一篇博客 [C 语言]字符串模型 ( 键值对模型 ) 中 , 完成了字符串的 键值对 查找功能 , 代码不太规范 ; C 项目开发代码规 ...

  7. JDBC和JPA调用储存过程 接收存储过程有返回值

    ============jdbc========================================== --java代码:一个输出参数-- String connURL = null; ...

  8. Flutter路由管理和接收页面的返回值

    Flutter使用Navigator进行路由管理. 跳转页面 使用Navigator的push方法进行跳转.可以看到总共有6个push方法 1.push(route) 通过路由跳转 通过路由进行跳转 ...

  9. c语言void返回什么意思,C语言程序返回值是void什么意思?

    满意答案 ansjc 2014.11.02 采纳率:44%    等级:6 已帮助:206人 void的使用 下面给出void关键字的使用规则: 规则一 如果函数没有返回值,那么应声明为void类型 ...

  10. 程序返回值的数据结构

    2014年3月5日 08:36:13 主要是判空处理 如果没有的到想要的值,返回时可以这样(有键无值) $a = array('k1' => 0,'k2' => 0,'k3' => ...

最新文章

  1. 5、(字符串类型)CHAR、VARCHAR、TEXT、ENUM、SET
  2. 找工作java还是python有用_你觉得学 Python 还是 Java 更好找工作?
  3. zen3架构_全新Zen3架构,AMD发布最新Ryzen5000系列处理器
  4. harbor pull 失败
  5. Eclipse Plug-in Hello world
  6. sharedpreferences使用方法_细数 SharedPreferences 的那些槽点 !
  7. mysql安装版卸载_MYSQL安装与卸载(一)
  8. Element menu
  9. 利用python进行数据分析——第13章 python建模库介绍
  10. 这3件事发生后,我彻底给 Python“跪了”!
  11. 欢迎界面java_Linux命令行欢迎界面美化
  12. 【计算机毕业设计】基于SpringBoot的物流管理系统
  13. 插入导频法实现载波通信matlab,插入导频法.ppt
  14. 微信小程序-image标签
  15. 小程序服务器获取appid,微信小程序小程序appid如何获取
  16. 水果店怎样开业吸引人流量,水果店怎样开业吸引人
  17. 稳压二极管TVS二极管
  18. 概率函数(密度函数)
  19. Echarts 柱状图,带背景色且数值显示在最顶部
  20. 机器学习-有监督无监督

热门文章

  1. 转: gob编解码
  2. 20、自动装配-@Autowired@Qualifier@Primary
  3. [JZOJ100047] 【NOIP2017提高A组模拟7.14】基因变异
  4. (63)通信协议之一json
  5. 【BZOJ 4516】生成魔咒
  6. Android中Bitmap,byte[],Drawable相互转化
  7. hibernate的各种保存方式的区别 (save,persist,update,saveOrUpdte,merge,flush,lock)等
  8. Silverlight 5 强袭 !! 圣临王者之三端大一统
  9. 最舒服的颜色搭配值,很有用哦,特别是做设计的!!
  10. minicap和minitouch安装