使用事件溯源来摆脱关系型数据库?

4
最近我读了一些关于CQRS和事件溯源的文章。虽然前者对我来说似乎是一种高度复杂和有风险的解决方案,用于修复性能不佳的业务和设计不良的数据访问层和数据模型,但后者似乎是解决许多问题的方案。
使用事件溯源需要解决的问题:
  1. 摆脱关系数据库和对象关系映射(ORM)工具,如NHibernate和Entity Framework。在编程领域中几乎没有人想要关注诸如索引、表/索引碎片化或规范化、如何设计关系数据以及如何编写/配置ORM(这是一门科学)等问题。
  2. 将业务模型和内存中的“数据库”合并,一个实体/聚合服务将所有相关项保留在内存中,并通过简单地将CUD事件转储到某个地方来维护完整性,而无需太多痛苦。旧项目可以从内存中驱逐出去并转储到NoSQL(或其他)存储器中,并用于聚合计算、报告、搜索,如果必要,可以重新激活。如果我理解正确,像VoltDB这样的内存数据库也使用类似的事件转储方式,但它们仍然是关系数据库,与业务逻辑分离。
  3. 这也会使并发更加容易:不再需要锁定(可能导致完全系统死锁)或乐观锁定,具体取决于数据是否同时发生了变化(或者是相当复杂的DB代码),而可以在代码中实现合并规则。
  4. 历史记录:不再需要实现审计功能、墓地表或“删除”标记列,或者可能需要已删除数据仍然被要求的情况。
  5. 数据重复/搜索/报告:使用全文索引而不是追踪缺失的关系索引,创建适当的查看区域,按所需格式为用户准备数据,而不是在关系数据库中使用丑陋的复制例程,带有触发器、后续存储过程或甚至是程序代码将数据复制到半打不同的表中。
  6. 版本控制:在许多模块运行时使用许多不同的关系数据库版本非常麻烦,每个版本都有不同的表和列,并需要适当的ORM映射。在单层模型中,通过接受任何对象格式(通常是无模式或松散模式NoSQL文档,表示为JSON或XML)的事件转储,可能会更容易。也可能通过“数据模式更改事件”链升级旧数据(而不是必须维护关系DB的迁移脚本)。
N层业务模型/关系数据库/ORM混乱问题
十年前或更长时间以前的n层方法可能是一个业务层和数据访问层。为了保持分离非常严格,许多关系特性被省略,在业务层中实现:关系完整性、规范化,而数据库则是我所说的“垃圾场”:看起来像一个玩弄SQL Server Management Studio或Access的孩子。极度非规范化、多态引用(“外键”列引用不同的源表,由“ReferenceSource”标记标识),滥用同一表格用于不同类型的业务对象和将数据复制到许多其他表格(再从那里转移到其他地方),因为性能不好,这应该改善查询。ORM使用也没有对象引用,仅缩减为单个对象加载和保存操作。加载聚合(实体/表行图)将遍历该图并为每组子实体发送一个查询。
当性能变差,并且可能出现孤立引用导致严重问题时,可能会尝试实现经典的关系设计,但是将成长的系统适应完整的数据重新设计是不可能的(没有人愿意为此付费),几乎没有人知道如何映射对象关系甚至在ORM中优化加载。这样的尝试仅限于设计的少数地方,可能使数据模型和访问更加难以维护。
在n层的基础上使用CQRS?
为了获得可接受的性能,可能会为某些模块构建单独的SQL查询,绕过具有单个对象迭代访问的业务模型。由于存在大量重复数据,并且可以立即访问应用程序,因此整个结构突然被称为事实上的CQRS(只要它不是像Google或Stackoverflow一样的“大数据”工作负载,这些都可以通过良好实现的关系数据模型和ORM使用来处理),并且在关系表中组成了大量重复的数据。
比不合适的表格格式更好的东西?
好的,我阅读了CQRS,虽然我不喜欢之前描述的“CQRS”的使用,但事件存储而不是关系数据库的概念看起来非常有用:成功地强制引入最初的、最先进的关系数据库设计和OR映射是不可能的,即使是这样,也将极其昂贵。实际上,普通的面向对象编程比大多数数据库表格更加“规范化”,因为需要将所有内容压缩到表格格式中或为对象图/聚合创建大量表格。我同意:必须手动处理搜索索引和碎片整理、模式管理和数据历史记录跟踪,就像石器时代的IT一样,就像在现代汽车和电动高速列车旁边运行福特T型车和蒸汽机车一样。
有什么好的经验吗?
使用事件源(不一定是完整的CQRS)的经验如何?它是否消除了关系数据库的许多问题?我真的期待着一种集成所有业务逻辑并且可能足够快以使单独的查询模块可以被省略的内存数据库!
2个回答

3
尽管CQRS、ES和DDD经常一起使用,但它们是独立的概念,单独使用也非常强大。
CQRS(Command Query Responsibility Segregation):这是一种通用的软件设计模式。其思想是将改变状态(命令)的事物与不改变状态(查询)的事物分开。在许多系统中,查询会修改数据库的状态,这使得开发人员很难理解正在发生的事情。想象一下进行查询以查找某些信息,然后意识到由于查询而更改了信息。
CQRS禁止这些行为。命令(不能返回信息)改变状态,查询(返回信息)不能修改状态。这样,您就可以确定代码的哪些部分是幂等的(因此可以随意调用而没有副作用),哪些部分会改变状态。
DDD(Domain Driven Design):这是一种“数据结构”的设计方法。它不规定数据库访问技术或许多技术细节。它提供指导方针和概念,以使应用程序中的数据结构更加响应实际用户需求。它还简化开发(尽管比简单地拼凑一些东西更费力)。
ES(Event Sourcing):事件溯源是一种数据存储策略,它将数据存储从“状态”(数据在当前时间点的实际值)转移到“过渡”(数据在其生命周期内发生的更改),这些更改称为“事件”。
使用ES有几个优点。
首先,它允许业务存储更多关于之前发生的事情的信息(对数据科学家来说是一个福音)。在传统系统中,许多信息会因数据更新而丢失,除非这些更新被明确记录,否则这些信息将永远消失。这在ES中不会发生。
其次,存储所有事件使调试变得更加简单,因为现在开发人员可以从数据处理的开始跟踪数据的处理过程。长时间以前发生的数据更新(并且将被另一个更新覆盖并且丢失)但却破坏了处理的更新可以被识别和修复。此外,修复的影响甚至可以延伸到错误事件和最后事件之间发生的所有计算。在传统系统中,这是不可能的,因为我们只存储最新状态。
虽然理论上可以编写一个不使用CQRS或DDD的事件溯源系统,但这样做要困难得多。

3

这个问题有很多细节,因此不可能给出特定而实际的答案。如果你正在寻找一个答案,那么它就是:

取决于你的领域。

CQRS/ES/DDD并不适合用来解决所有问题 - 它不是万能药。如果领域表明CRUD/NTier足够好,那么你应该使用它们。你在问题中列出的所有关注点都是基础或系统属性,并没有提到应该指导你选择工具或实践的最重要的事情;你想要构建什么?


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接