在 CQRS 设计的应用程序中选择用于存储事件的 NoSQL 数据库

Choosing a NoSQL database for storing events in a CQRS designed application

我正在寻找关于如何选择 NoSQL 数据库引擎以在 CQRS 设计的应用程序中存储所有事件的很好的、最新的 "decision helping" 解释。

我目前是 NoSQL 周围所有事物的新手(但正在学习):请清楚并毫不犹豫地以(几乎太多)精确的方式解释您的观点。这个post可能值得像我这样的其他新人

此数据库将:

我听说过用于 CQRS 事件存储的 HBase,但也许 MongoDB 适合?甚至是 Elasticsearch(不会赌那个……)?为了一致性和可用性,我也对 RDBMS 持开放态度。但是分区容差部分呢?

真的迷路了,需要论据才能做出中肯的选择

我有 MongoDBworking, in production implementation 作为 Event store。它由 CQRS + Event sourcing 基于网络的 CRM 应用程序使用。

为了一次性持久化多个事件(所有事件或其中 none 个事件)提供 100% 无事务但类似事务的保证,我使用 MongoDB document 作为 events commit,事件为 nested documents。如您所知,MongoDBdocument level locking.

对于并发,我使用乐观锁定,对每个 Aggregate steam 使用 version 属性。 Aggregate stream 由 dublet (Aggregate class x Aggregate ID).

标识

事件存储还使用 sequence 在每个 commit 上按相对顺序存储提交,在每次提交时递增,使用乐观锁定进行保护。

每个 commit 包含以下内容:

  • aggregateId : 字符串,可能是 GUID,
  • 聚合类:字符串,
  • version:整数,为每个 aggregateId x aggregateClass 递增,
  • 序列,整数,每次提交递增,
  • 创建时间:UTCDateTime,
  • authenticatedUserId:字符串或空,
  • 事件:EventWithMetadata
  • 列表

每个 EventWithMetadata 包含 event class/type 和作为字符串的有效负载(实际事件的序列化版本)。

MongoDB 集合具有以下索引:

  • aggregateId, aggregateClass, version 作为 unique
  • events.eventClasssequence
  • sequence
  • 用于查询优化的其他索引

这些索引用于执行一般事件存储规则(不会为相同版本的 Aggregate 存储事件)和查询优化(客户端可以 select 只有某些事件 - 按类型 - 来自所有流).

如果您剥离事件的全局排序(sequence 属性)并将该责任转移到 event publisher 但这会使事情变得复杂,因为 event publisher 需要与 event store 保持同步(即使在失败的情况下!)。我建议只在需要时才这样做。

此实现的基准(在 Intel I78GBRAM):

  • 总聚合写入时间为:7.99,速度:每秒写入 12516 个事件
  • 总聚合读取时间为:1.43,速度:每秒读取 35036 个事件
  • 总读取模型读取时间为:3.26,速度:每秒读取 30679 个事件

我注意到 MongoDBcounting 事件存储中的事件数量上很慢。我不知道为什么,但我不在乎,因为我不需要这个功能。

我建议使用 MongoDB 作为 event store

https://geteventstore.com/是专门为事件流设计的数据库。

他们非常重视真相(您的事件)来源的一致性和可靠性,我自己使用它来 read/write 每秒处理数千个事件。

我有一个 .NET Core 事件源实施项目https://github.com/jacqueskang/EventSourcing

我从使用 entity framework 核心的关系数据库(SQL 服务器和 MySQL)开始。 然后搬到 AWS 所以我写了一个 DynamoDB 扩展。

我的经验是关系数据库可以完美地完成这项工作,但这取决于要求和您的技术堆栈。如果您的项目是基于云的,那么最好的选择可能是云提供商的无 sql 数据库,如 AWS DynamoDB 或 Azure CosmosDB,它们性能强大并提供附加功能(例如 DynamoDB 可以触发通知或 lambda 函数)