我试图了解事件源如何改变服务的数据架构。我已经做了很多研究,但是似乎无法理解应该如何通过事件源正确存储数据。
比方说,我有一项服务可以跟踪车辆运送包裹的情况。数据模型的当前非关系结构是每个文档代表一辆车辆,并且具有许多字段,这些字段代表出发地,目的地位置,包裹类型,包裹数量,车辆状态等。通常会查询此信息以获取信息被读到前端。当用户进行更改时,将对此文档进行适当的更改以进行更新。
使用事件源,似乎可以存储每个事件的快照,但是似乎有几种解释方法:
首先是我描述的文档存在多个版本,每次进行更改时,每个版本都会创建一个新快照。每个事件都会创建该文档的新版本并对其进行更改。这是让我包住头的最简单方法,但是我认为这是不正确的。
我的另一种解释是,每个事件都存储有关文档中已更改内容的特定信息。例如,当车辆状态从“公路”更改为“可用”时,将触发一个专门针对车辆状态变化的事件。假设它称为VehicleStatusUpdatedEvent,其中包含此事件的车辆ID号,新状态和时间戳。因此,此事件被存储并发布到消息队列。从队列中取出后,将对文档的当前版本进行适当的更改。我能理解这一点,但我认为我仍然有一些误解。我的理解是,事件源使我们能够在每次更改时都有数据快照,因此我们可以随时了解它的外观。我刚刚描述的内容会保留更改日志,但仍然只有文件的一个版本,因为事件仅包含整个文件的特定部分。
有人可以描述数据流和架构如何与事件源一起使用吗?使用我提供的车辆数据示例可能会帮助我更好地构建框架。我觉得我已经接近了解这一点,但是我错过了一些网上搜索似乎无法理解的基本知识。
答案 0 :(得分:2)
数据模型当前的非关系结构是每个文档代表一辆车
好的,让我们从那里开始。
在您描述的数据模型中,文档的存储破坏了早期的副本。
现在想象一下,相反,我们将文档存储在git存储库中。然后,保存文档也将保存元数据,并且该元数据将包含指向先前文档的指针。
当然,在这种情况下,我们可能有很多重复。因此,我们将存储一个补丁文档(请考虑JSON Patch)和指向原始补丁的元数据,而不是每次都存储完整的文档。
再次采用相同的想法,但是我们没有存储通用的补丁文档,而是使用特定于域的消息来描述模型发生了什么。
事件源实体的数据模型就是这样:文档转换的域特定描述列表。
当您需要重新构造当前状态时,请从一个已知的状态开始(该状态可能是文档在发生任何事情之前的“空”状态,然后将其上所有的补丁(事件)重播到该文档上)从那以后发生了。
如果您要进行时间查询,那么游戏是一样的,您可以重播事件直到感兴趣的时间点。
从本质上讲,当引用旧版本时,您是使用事件来重建文档的吗?
是的,完全正确。
那么还有“当前状态”文档吗?还是认为这是不良做法?
“取决于”。在一般情况下,没有当前状态文档。只有事件的写入顺序列表是“真实的”,其他所有内容都是由此得出的。
关于事件源的对话通常会导致考虑使用专用消息存储库来管理那些有序列表的持久性,并且消息存储库还不支持文档存储是很常见的。因此,尝试保持“当前版本”将需要提交到两个不同的存储。
在这一点上,设计人员通常会决定“最新版本”足够好,在这种情况下,他们会在交易边界之外建立最终一致的文档表示形式……或者他们决定当前版本很重要,然后考虑存储支持将当前版本与事件存储在同一事务中的解决方案(例如:使用RDBMS)。
使用事件生成所需快照的过程是什么?
如果要生成快照,那么通常会使用称为投影的模式来迭代事件,然后fold
或reduce
来创建文档。< / p>
大致上,您在某处有一个看起来像的函数
document-with-meta-data = projection(event-history-with-metadata)