事件源和CQRS非常棒,因为它让开发人员陷入了一个预建模型数据库,开发人员必须在应用程序的生命周期内使用该数据库,除非有大数据迁移项目。 CQRS和ES还有其他好处,如扩展事件存储,审计日志等已经遍布互联网。
但有哪些缺点?
以下是我在研究和编写小型演示应用程序后可以想到的一些缺点
有人可以评论我在这里提出的不利因素,如果我错了就纠正我,并建议我可能错过任何其他人吗?
答案 0 :(得分:32)
以下是我对此的看法。
CQRS + ES可以通过丰富的域对象,简单的数据模型,历史跟踪,对并发性问题的更多可见性,可伸缩性等等,在复杂的软件系统中简化操作。它确实需要以不同的方式思考系统,因此很难找到合格的开发人员。但CQRS使得跨开发人员分离职责变得更加简单。例如,初级开发人员可以完全使用读取方而无需触及业务逻辑。
数据副本肯定需要更多磁盘空间。但是这些天存储相对便宜。可能需要IT支持团队进行更多备份,并规划在出现问题的情况下如何恢复系统。但是,如今的服务器虚拟化使其成为一个更加简化的工作流程。此外,在没有单片数据库的情况下,在系统中创建冗余要容易得多。
我不认为更高的内存使用率是一个问题。业务对象水合应按需进行。对象不应该保留对已经持久化的事件的引用。事件水化应该只在持久数据时发生。在阅读方面,您没有实体 - > DTO - >通常在分层系统中发生的ViewModel转换,并且您不会对全功能ORM通常执行的任何类型的对象更改跟踪。大多数系统执行的读取次数远远多于写入。
如果由于各种数据上下文的初始化而使用多个异构数据库,则较长的启动时间可能会有轻微问题。但是,如果您使用像ADO .NET这样简单的东西来与事件存储进行交互,并使用微型ORM进行读取,那么系统将比任何全功能ORM“冷启动”更快。这里重要的是不要过度复杂化访问数据的方式。这实际上是CQRS应该解决的问题。正如我之前所说,读取方应该为视图建模,而不会有重新映射数据的任何开销。
根据我的经验,两阶段提交可以很好地适用于不需要为数千个用户扩展的系统。您需要选择能够与分布式事务协调器配合使用的数据库。例如,PostgreSQL可以很好地读写单独的模型。如果系统需要针对大量并发用户进行扩展,则必须将其设计为最终的一致性。在某些情况下,您可能会使用不使用CQRS的聚合根或上下文边界来避免最终的一致性。它对域的非协作部分有意义。
如果为事件存储选择正确的数据库,则可以按序列化格式(如JSON或XML)查询事件。这应该仅用于分析目的。系统内部的任何内容都不应该通过聚合根id和事件类型之外的任何内容来查询事件存储。该数据将被索引并存在于序列化事件之外。
答案 1 :(得分:5)
只是评论第5点。我被告知Facebook确实使用ES与最终一致性,这就是为什么你有时会看到一个帖子消失并在你发布后重新出现。
通常,您的浏览器访问的读取模型位于“靠近”位置,但在您发布帖子后,SPA会切换到与您的写入模型接近的读取模型。写模型(事件)和读模型之间的紧密接近意味着您可以看到自己的帖子。
然而,15分钟后,您的SPA切换回第一个更接近的读取模型。如果包含您的帖子的事件尚未传播到该阅读模型,您将看到自己的帖子消失,但稍后会重新出现。
答案 2 :(得分:1)
事件源和CQRS很棒,因为它使开发人员摆脱了一个预先建模的数据库的困扰,除非存在大型数据迁移项目,否则开发人员必须在应用程序的整个生命周期内使用该数据库。
这是一个很大的误解。关系数据库是完全为模型的发展而发明的(这要归功于简单的二维表,而不是预先定义的层次结构)。通过确保数据访问封装的视图和过程,逻辑和物理模型可以独立发展。这也是为什么SQL用相同的语言定义DDL和DML的原因。一些RDBMS还允许将所有这些演化版本作为基于Oracle Edition的重新定义进行版本控制和在线部署(连续交付)。
大数据结构是预定义的,并且只能使用为此结构开发的代码读取。可以,当立即食用时可以,但是十年后,如果没有确切的版本以及语言编译器或解释器,您将很难阅读它。
答案 3 :(得分:0)
我知道问这个问题已经快3年了,但this article仍然可能对某人有用。重点是
答案 4 :(得分:0)
我希望不要晚于尝试给出答案。在这几个月中,我对该参数进行了很多研究,目的是为我的体系结构中某些对ES有意义的部分实施产品级解决方案
复杂:实际上,它不应该复杂,它的任务是致命的简单。怎么样?将所有复杂性从业务逻辑代码扩展到基础结构代码。数据访问应由尚未成熟的框架完成。 ES / CQRS竞赛中仍然没有明确的赢家,也许是因为它仍然是利基/时髦方法(?),因此,一些团队正在推出自己的解决方案或采用一些现成的技术,例如Axon
高磁盘空间使用量:我会说更多,我会说*潜在无限*磁盘使用率。但是,如果您选择使用ES,您也有充分的理由容忍这种明显的漂移。让我们给一些:
审核日志:数据存储区是事件日志,我们已经知道了。财务应用程序或每个关键任务/安全性至关重要的人员,可能需要集中审核日志,以说明谁在哪个时刻做出了什么。 ES提供了这种开箱即用的功能...您还可以使用一些具有业务可预测性的元数据来装饰事件条目(例如,与某些API使用者身份相关联的交易ID,操作的严重性级别...)
高并发性:在某些系统中,许多客户端以并行方式更改逻辑资源状态。这些是游戏,物联网平台等。记录事件而不是更改状态表示可能是提供事件总顺序的明智方法。另一种方法是将同步化内容委托给DB。但这不是您想要的ES
Analytics(分析)假设您拥有大量具有大量业务价值的数据,但您仍然不知道哪个。多年来,我们通过将数据组织与不同的信息模型(OLAP多维数据集)进行转换,从应用程序信息中提取知识。事件存储再次提供了类似的功能。事件日志是最原始的信息表示形式,您可以采用多种方式来批量处理或对存储的事件做出反应
内存使用率高:我认为一旦建立投影就应该一样
更长的启动时间:如果读取端缓存其预测并“记住”最近的更新事件,则不应重新应用整个事件序列。快照是一种缓解措施,但是如果您做很多快照,则可能是ES的错误选择。我认为,在微服务生态系统中,这个问题很小,可以在不中断服务的情况下屏蔽启动时间。实际上,在应用ES / CQRS时,您可以充分利用它,从而使微服务
最终的一致性:为此,而不是ES指责CAP定理。许多非ES / CQRS必须处理此问题,但是在很多情况下这并不是真正的问题。这些是ES非常适合的场景。您可以将ES和非ES服务混合到同一平台中
事件存储中的序列化事件:如果具有非序列化事件表示形式很重要,则可以使用面向文档的数据库,但是如果这样做是为了对事件有效负载进行查询,则可以缺少ES / CQRS的要点。 ES意味着将所有数据处理从DB端移到应用程序层,其中每个部分都会快速更改,并且所有操作都是无状态的。这样可以增强可伸缩性和容错能力,并提供塑造团队组织的方法,例如让前端男孩/女孩轻松地用javascript编写他/她的BFF。
我希望将这一原则付诸实践,并从这种令人兴奋的方法中受益。