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