DynamoDB - AWS上的事件存储

问题描述 投票:0回答:3

我在AWS上设计了一个Event Store,我选择了DynamoDB,因为它似乎是最好的选择。我的设计似乎相当不错,但我面临一些我无法解决的问题。

**该设计

事件由(StreamId, EventId)对唯一标识:

  • StreamId:它与aggregateId相同,这意味着一个Aggregate的一个事件流。
  • EventId:一个增量数字,有助于保持同一事件流中的排序

事件在DynamoDb上持久存在。每个事件映射到表中的单个记录,其中必填字段是StreamId,EventId,EventName,Payload(可以轻松添加更多字段)。

partitionKey是StreamId,sortKey是EventId。

在将事件写入事件流时使用乐观锁定。为实现这一目标,我正在使用DynamoDb条件写入。如果已经存在具有相同(StreamId,EventId)的事件,我需要重新计算聚合,重新检查业务条件,如果业务条件通过,最后再次写入。

事件流

每个事件流由partitionKey标识。查询所有事件的流等于查询partitionKey = $ {streamId}和sortKey在0和MAX_INT之间。

每个事件流标识一个且仅一个聚合。这有助于使用乐观锁定处理同一聚合上的并发写入,如前所述。这也可以在重新计算聚合时提供出色的性能。

出版活动

利用DynamoDB Streams + Lambda的组合发布事件。

重播活动

这是问题的起点。让每个事件流只用一个聚合映射(导致有大量的事件流),没有简单的方法可以知道我需要从哪个事件流中查询所有事件。

我想在DynamoDB中使用一个额外的记录,它在一个数组中存储所有StreamIds。然后我可以查询它并开始查询事件,但如果在重播时创建了一个新流,我将丢失它。

我错过了什么吗?或者,我的设计完全错了吗?

amazon-web-services amazon-dynamodb distributed-computing event-sourcing amazon-dynamodb-data-modeling
3个回答
1
投票

我错过了什么吗?

并不是的;这是一个难题[tm]。

您的写入用例通常仅涉及模型中的单个引用 - 指向当前事件历史记录的指针。您的读用例通常涉及跨多个流分布的数据。

通常这种方式的工作方式是持久性存储不仅维护已编写的更改,还维护支持读取的索引。例如,Eventide's postgres message store依赖于在表中插入行时发生的索引。在Event Store的情况下,索引的更新被写为与流的更改相同的序列化“事务”的一部分。

表达相同想法的另一种方式:查询实际上比写入更粗糙,存储设备隐式提供您期望的协调保证。

消除协调,你有类似于为每个流分配唯一主机的东西。

仔细查看Git object database并熟悉该商店内真正发生的事情可能会有所帮助。我还发现Rich Hickey的演讲The Language of the System提供了有用的概念来区分valuesnamesreferences

我选择了DynamoDB,因为它似乎是最好的选择

除非你有一些令人信服的商业理由从头开始建立你的活动商店,我鼓励你改为看看Aurora,看看你能走多远。它可能会为您提供等待其他人为您组建经济高效的云原生事件存储设备的时间。


1
投票

您可以使用GSI检索给定时间段内的事件。根据正在处理的事件数,您可能需要在GSI中写入分片以避免热键。假设事件项目小于1KB,如果摄取率高于1000项/秒,则需要在GSI上展开它们。如果事件大于1KB,您需要将它们分散开来。对于小于1KB的项目,取每秒事件总数除以1000.这将告诉您GSI需要多少分片才能跟上表格,例如:假设您每秒摄取5K事件,则需要5个分片。

将事件写入表时,添加一个名为“GSIKey”的新属性,并在插入事件时为该属性创建0-4之间的随机值。使用“GSIKey”作为分区键创建GSI,使用时间戳作为排序键。当您需要获取给定时间范围内的所有事件时,查询您正在查找的时间范围的所有5个分片,然后简单地合并排序结果集以生成时间排序的事件列表。如果您每秒处理的事件少于1000个事件,那么您可以使用“0”作为GSIKey值,只需查询一个分区即可获得所需的事件。


0
投票

原始答案:你能详细说明“聚合”吗?它与EventID相同,还是一个独特的项属性?

您需要存储事件和汇总吗?

您的活动耐久性要求是什么?

如果<14天,将在Kinesis中存储事件是您的选择吗?正如Rick Houlihan指出的那样,您的设计可能会遇到热分区或热键问题,这需要您增加DynamoDB表上的RCU / WCU。 Kinesis解决了这个问题。使用它将使您能够专注于您的应用程序逻辑。

如果您愿意,我很乐意为您提供帮助,如果您可以分享更多细节。

4/23更新:

让我提出另一个替代方案供您考虑:CloudWatch Logs。 CloudWatch日志组将等同于您的事件表。您的每个流都将映射到CloudWatch日志流。

您需要考虑上面针对DynamoDB表描述的条件写入等效逻辑。

CWL的优势在于您将避免上面提到的热键问题。缺点是:(1)您需要考虑针对CWL的解决方案。 (2)DynamoDB提供的读取P99延迟<10 ms,写入时<20 ms。 CWL读写操作要高得多(想想10s到100s或ms)。

我希望这能有所帮助。

© www.soinside.com 2019 - 2024. All rights reserved.