事件溯源,保持读取端一致
Event sourcing, hold read side consistent
我是 ES 的新手,只是想在脑海中对所有内容进行排序。我听说 ES 实际上正在解决写入和读取数据库之间的一致性问题(肯定会有一些延迟)。但是我还是不太明白怎么办?
如果命令进入域并聚合根触发事件以更新事件存储,同样的事件正在发送到更新读取端??但是如果消息丢失了怎么办,我们将有过时的阅读面。
是 projections
唯一的解决方案吗?所以不是从事件更新,而是读取边遍历事件存储并再现聚合(从开始或从某个快照)。但在这种情况下,它可能违反了一些规则,因为读取端应该很简单并且它不应该知道域。而且通常读取端是一个单独的应用程序,所以她不知道聚合。
当然我们也可以使用 rabbitMQ
或其他一些消息代理来不丢失消息,实际上我认为我们需要。但我也读到它使它保持一致 "you can use rabbit or ES",但是 ES 如何自己使它保持一致??
I have heard that ES is actually solving the consistency issue between
write and read database
据我所知,事件源与 read/write 与您的数据库之间的一致性无关。 read/write 之间的一致性实际上更多地与您使用的数据库类型有关,例如主要是 ACID 的关系数据库与通常是最终一致性的非关系数据库。
ES 不是这个意思,而是 ES : "Capture all changes to an application state as a sequence of events" Martin Fowler.
ES 就像时间机器一样工作,它允许您将应用程序的状态更改为过去的特定日期时间。
Benjamin 对事件溯源的目的完全正确。
我的回答旨在添加更多细节。
第一个:
阅读模型和预测不应该代表聚合状态。
投影是事件源系统为 CQRS 构建读取模型的方式。 CQRS 本质上假设写入和读取模型通常服务于不同的目的,因此对于读取端使用另一个模型是非常有意义的。
因此,您经常会发现多个投影构建不同的、用途狭窄的模型,针对特定的查询需求。
第二个:
"solving consistency issues" 您的意思可能是在事件源系统中,每个状态转换都表示为一个事件(或多个事件)。因此,写入始终是事务性的。您选择作为事件存储的数据库应该支持(可以使用某些库或其他工具)实时订阅,这将允许您在投影中接收新事件,按顺序。对于新的预测,它将从头开始读取并最终实时读取。订阅通常需要在全局事件流中保持当前处理位置,因此当投影重新启动时,它会从它最后知道的点开始接收事件。
通过这样做,您将保证写入模型中的每个状态转换都将反映在读取模型中。这可能就是您在原始问题中的意思。
第三个:
现在,以上所有这些都意味着您不能(仅)使用消息总线将事件传递给投影。经纪人不提供顺序保证,并且可以多次传递一条消息。此外,消息代理不会保留历史记录,因此您无法随意构建新的预测。
但是,这并不意味着您完全不能使用经纪人。一些预测不需要排序并且是幂等的。但是通过代理发布的事件的提要是相同的订阅,因此您可以获得有保证的交付并且可以在必要时阅读过去的事件。
第四个:
CQRS 并不意味着独立的数据库。有时,使用 CQRS 仅意味着您为领域对象使用了一些持久层,因此您可以读取和写入聚合。但是对于查询,你随便查询就行了,想怎么查询就怎么查询。数据库视图是 CQRS 的技术示例。
快到了:
投影需要几乎没有逻辑,这是事实。这里的要点是尽可能确保幂等性,因此投影通常不应使用基于旧值和事件信息计算新值的操作。
但是投影会知道您的域。您系统中的所有内容都应该知道您的域。
最后一个:
您绝对可以使用不同的数据库进行写入和读取模型,而无需使用事件溯源。您只需要选择一个支持更改源的数据库。 SQLServer、Postgres、CosmosDb等数据库都有这样的功能。
P.S。我建议花一些时间研究这些概念。我可以指向书库,它有 CQRS 和事件源示例:https://github.com/PacktPublishing/Hands-On-Domain-Driven-Design-with-.NET-Core
我是 ES 的新手,只是想在脑海中对所有内容进行排序。我听说 ES 实际上正在解决写入和读取数据库之间的一致性问题(肯定会有一些延迟)。但是我还是不太明白怎么办?
如果命令进入域并聚合根触发事件以更新事件存储,同样的事件正在发送到更新读取端??但是如果消息丢失了怎么办,我们将有过时的阅读面。
是 projections
唯一的解决方案吗?所以不是从事件更新,而是读取边遍历事件存储并再现聚合(从开始或从某个快照)。但在这种情况下,它可能违反了一些规则,因为读取端应该很简单并且它不应该知道域。而且通常读取端是一个单独的应用程序,所以她不知道聚合。
当然我们也可以使用 rabbitMQ
或其他一些消息代理来不丢失消息,实际上我认为我们需要。但我也读到它使它保持一致 "you can use rabbit or ES",但是 ES 如何自己使它保持一致??
I have heard that ES is actually solving the consistency issue between write and read database
据我所知,事件源与 read/write 与您的数据库之间的一致性无关。 read/write 之间的一致性实际上更多地与您使用的数据库类型有关,例如主要是 ACID 的关系数据库与通常是最终一致性的非关系数据库。
ES 不是这个意思,而是 ES : "Capture all changes to an application state as a sequence of events" Martin Fowler.
ES 就像时间机器一样工作,它允许您将应用程序的状态更改为过去的特定日期时间。
Benjamin 对事件溯源的目的完全正确。
我的回答旨在添加更多细节。
第一个:
阅读模型和预测不应该代表聚合状态。
投影是事件源系统为 CQRS 构建读取模型的方式。 CQRS 本质上假设写入和读取模型通常服务于不同的目的,因此对于读取端使用另一个模型是非常有意义的。
因此,您经常会发现多个投影构建不同的、用途狭窄的模型,针对特定的查询需求。
第二个:
"solving consistency issues" 您的意思可能是在事件源系统中,每个状态转换都表示为一个事件(或多个事件)。因此,写入始终是事务性的。您选择作为事件存储的数据库应该支持(可以使用某些库或其他工具)实时订阅,这将允许您在投影中接收新事件,按顺序。对于新的预测,它将从头开始读取并最终实时读取。订阅通常需要在全局事件流中保持当前处理位置,因此当投影重新启动时,它会从它最后知道的点开始接收事件。
通过这样做,您将保证写入模型中的每个状态转换都将反映在读取模型中。这可能就是您在原始问题中的意思。
第三个:
现在,以上所有这些都意味着您不能(仅)使用消息总线将事件传递给投影。经纪人不提供顺序保证,并且可以多次传递一条消息。此外,消息代理不会保留历史记录,因此您无法随意构建新的预测。
但是,这并不意味着您完全不能使用经纪人。一些预测不需要排序并且是幂等的。但是通过代理发布的事件的提要是相同的订阅,因此您可以获得有保证的交付并且可以在必要时阅读过去的事件。
第四个:
CQRS 并不意味着独立的数据库。有时,使用 CQRS 仅意味着您为领域对象使用了一些持久层,因此您可以读取和写入聚合。但是对于查询,你随便查询就行了,想怎么查询就怎么查询。数据库视图是 CQRS 的技术示例。
快到了:
投影需要几乎没有逻辑,这是事实。这里的要点是尽可能确保幂等性,因此投影通常不应使用基于旧值和事件信息计算新值的操作。
但是投影会知道您的域。您系统中的所有内容都应该知道您的域。
最后一个:
您绝对可以使用不同的数据库进行写入和读取模型,而无需使用事件溯源。您只需要选择一个支持更改源的数据库。 SQLServer、Postgres、CosmosDb等数据库都有这样的功能。
P.S。我建议花一些时间研究这些概念。我可以指向书库,它有 CQRS 和事件源示例:https://github.com/PacktPublishing/Hands-On-Domain-Driven-Design-with-.NET-Core