使用事件采购和CQRS有哪些缺点?

haj*_*ime 30 cqrs event-sourcing

事件采购和CQRS是伟大的,因为它会赶走被卡住它的开发者一起工作的应用程序的生命周期,除非有一个大的数据迁移项目一个预建模的数据库开发人员.CQRS和ES还有其他好处,如扩展事件存储,审计日志等已经遍布互联网.

但有什么缺点呢?

以下是在研究和编写小型演示应用程序后我可以想到的一些缺点

  1. 复杂:有人说ES很复杂.但是我要说复杂的应用程序比复杂的数据库模型更好,在这种模型上你只能使用查询语言(多个连接,索引等)运行非常有限的查询.我的意思是像Scala这样的编程语言有非常丰富的集合库,它可以非常灵活地生成一些非常复杂的聚合,而且还有Apache Spark可以轻松查询分布式集合.但是数据库总是受限于它的查询语言功能,分发数据库比分布式应用程序代码更难(只需在另一台机器上部署另一个实例!).
  2. 磁盘空间使用率过高:事件存储最终可能会占用大量磁盘空间来存储事件.但是我们可以每隔几周安排一次清理并创建快照,也许我们可以在外部HD上本地存储历史事件,这只是因为我们将来需要旧事件吗?
  3. 高内存使用率:每个域对象的状态都存储在内存中,这可能会增加RAM的使用量,而且我们所有的RAM都是多么昂贵.大问题!!因为我很穷!任何解决方案?可能是使用Sqlite而不是在内存中存储状态?我是否通过在我的应用程序中引入多个Sqlite实例来使事情变得更复杂?
  4. 启动时间较长:失败或软件升级启动速度很慢,具体取决于事件的数量.但我们可以使用快照来解决这个问题吗?
  5. 最终的一致性:某些应用程序的问题.想象一下,如果Facebook使用CQRS的事件采购来存储帖子并考虑到facebook系统的繁忙程度,如果我发布帖子,我会在第二天看到我的fb帖子:)
  6. 事件存储中的序列化事件:事件存储将事件存储为序列化对象,这意味着我们无法查询事件存储中的事件内容.而且我们将来无法为该事件添加其他属性.解决方案是将事件存储为JSON对象而不是序列化事件?但这是个好主意吗?或者添加更多事件以支持对orignal事件对象的更改?

有人可以评论我在这里提出的不利因素,如果我错了就纠正我,并建议我可能错过任何其他的吗?

Dmi*_* S. 34

这是我对此的看法.

  1. CQRS + ES可以通过丰富的域对象,简单的数据模型,历史跟踪,对并发性问题的更多可见性,可伸缩性等,在复杂的软件系统中使事情变得更加简单.它确实需要以不同的方式思考系统,因此很难找到合格的开发人员.但CQRS使得跨开发人员分离职责变得更加简单.例如,初级开发人员可以完全使用读取方而无需触及业务逻辑.

  2. 数据副本肯定需要更多的磁盘空间.但是这些天存储相对便宜.可能需要IT支持团队进行更多备份,并规划在出现问题的情况下如何恢复系统.但是,如今的服务器虚拟化使其成为一个更加简化的工作流程.此外,在没有单片数据库的情况下,在系统中创建冗余要容易得多.

  3. 我不认为更高的内存使用率是一个问题.业务对象水合应按需进行.对象不应该保留对已经持久化的事件的引用.事件水化应该只在持久数据时发生.在读取方面,您没有通常在分层系统中发生的实体 - > DTO - > ViewModel转换,并且您不会进行任何类型的对象更改跟踪,而全功能ORM通常会这样做.大多数系统执行的读取比写入要多得多.

  4. 如果由于各种数据上下文的初始化而使用多个异构数据库,则较长的启动时间可能是一个小问题.但是,如果您使用像ADO .NET这样简单的东西来与事件存储进行交互,并使用微型ORM进行读取,那么系统将比任何全功能ORM"冷启动"更快.这里重要的是不要过度复杂化访问数据的方式.这实际上是CQRS应该解决的问题.正如我之前所说的,读取端应该为视图建模,而不会有重新映射数据的任何开销.

  5. 根据我的经验,两阶段提交可以很好地适用于不需要为数千个用户扩展的系统.您需要选择能够与分布式事务协调器配合使用的数据库.例如,PostgreSQL可以很好地读写单独的模型.如果系统需要针对大量并发用户进行扩展,则必须将其设计为最终的一致性.在某些情况下,您可能会使用不使用CQRS的聚合根或上下文边界来避免最终的一致性.它对域的非协作部分有意义.

  6. 如果为事件存储选择正确的数据库,则可以按序列化格式(如JSON或XML)查询事件.这应该仅用于分析目的.系统内部的任何内容都不应该通过聚合根id和事件类型之外的任何内容来查询事件存储.该数据将被索引并存在于序列化事件之外.


Sam*_*and 7

只是评论第5点.我被告知Facebook确实使用ES与最终一致性,这就是为什么你有时会看到一个帖子消失并在你发布后重新出现.

通常,您的浏览器访问的读取模型位于"靠近"位置,但在您发布帖子后,SPA会切换到与您的写入模型接近的读取模型.写模型(事件)和读模型之间的紧密接近意味着您可以看到自己的帖子.

然而,15分钟后,您的SPA切换回第一个更接近的读取模型.如果包含您帖子的事件尚未传播到该阅读模型,您将看到自己的帖子消失,但稍后会重新出现.


kag*_*oki 6

我知道这个问题被问到已经快 3 年了,但这篇文章仍然对某人有用。关键点是

  • 使用快照缩放
  • 数据的可见性
  • 模式改变
  • 处理复杂的域
  • 需要向大多数新团队成员解释


小智 5

事件溯源和 CQRS 很棒,因为它使开发人员摆脱了一个预先建模的数据库的困扰,除非有大数据迁移项目,否则开发人员必须在应用程序的整个生命周期中使用该数据库。

这是一个很大的误解。关系数据库正是为了模型的进化而发明的(多亏了简单的二维表而不是预定义的层次结构)。通过视图和过程确保数据访问的封装,逻辑和物理模型可以独立发展。这也是 SQL 用同一种语言定义 DDL 和 DML 的原因。一些 RDBMS 还允许将所有这些演进版本化和在线部署(持续交付)作为基于 Oracle 版本的重新定义。

大数据结构是预定义的,只能使用为此结构开发的代码读取。可以立即使用,但如果没有确切的版本、语言编译器或解释器,10 年后您将很难阅读它。


Car*_*ldi 5

我希望不要迟到尝试给出答案。在这几个月里,我对这个论点做了很多研究,目标是为我的架构中 ES 可以发挥作用的某些部分实现生产级解决方案

复杂: 实际上,它不应该复杂,它的使命是极其简单。如何?将所有复杂性从业务逻辑代码推向基础设施代码。数据访问应该由还不够成熟的框架来完成。尽管如此,ES/CQRS 竞赛中仍然没有明显的赢家,也许是因为这仍然是一种小众/时髦的方法(?)所以一些团队正在推出自己的解决方案或采用一些现成的技术,例如 Axon

高磁盘空间使用率:我会说更多,我会说*可能无限*磁盘使用率。但如果你选择 ES,你也有充分的理由容忍这个明显的缺点。让我们给出其中一些:

  1. 审核日志:数据存储是一个事件日志,我们已经知道了。金融应用程序或每个关键任务/安全都可能需要一个集中的审计日志,以便能够说明哪个时刻做了什么。ES 提供了此功能...您还可以使用一些对业务有意义的元数据来装饰您的事件条目(例如,与某些 API 消费者身份相关的事务 ID、操作的严重性级别...)

  2. 高并发性:在某些系统中,逻辑资源状态会被许多客户端以并发方式改变。这些是游戏、物联网平台等等。记录事件而不是更改状态表示可能是提供事件总顺序的明智方法。另一种方法是将同步工作委托给数据库。但如果你喜欢 ES,这不是你想要的

  3. 分析假设您拥有大量具有大量商业价值的数据,但您仍然不知道哪些数据。多年来,我们通过使用不同的信息模型(OLAP 多维数据集)转换数据组织来从应用程序信息中提取知识。事件存储再次提供类似的开箱即用的东西。事件日志是信息表示的最原始形式,您可以通过多种方式处理它们,批量处理或对存储的事件做出反应

高内存使用率:我认为一旦你构建了投影,它应该是相同的

更长的启动时间:如果读取端缓存其投影并“记住”最后的更新事件,则它不应重新应用整个事件序列。快照是缓解措施,但如果您做了很多快照,也许您对 ES 做出了错误的选择。我认为这个问题在微服务生态系统中很小,可以在不中断服务的情况下屏蔽启动时间。事实上,当您应用 ES/CQRS 时,您可以充分利用它,因此微服务

最终一致性:这要归咎于 CAP 定理,而不是 ES。许多非 ES/CQRS 必须处理这个问题,但有很多场景这不是一个真正的问题。这些都是 ES 非常适合的场景。您可以将 ES 和非 ES 服务混合到同一个平台中

事件存储中的序列化事件:如果非序列化事件表示很重要,您可以使用面向文档的数据库,但如果您这样做是为了对事件负载进行查询,那么您就错过了 ES/CQRS 的要点。ES意味着将所有数据操作从数据库端转移到应用程序层,其中每个部分都快速变化,并且都是无状态的。这增强了可扩展性和容错能力,并提供了塑造团队组织的方法,例如让前端男孩/女孩轻松地用 JavaScript 编写他/她的 BFF。

我希望将这些原则付诸实践并取得良好成果,并利用这种令人兴奋的方法的好处