DynamoDB-AWS上的事件存储

时间:2019-04-19 13:57:32

标签: amazon-web-services amazon-dynamodb distributed-computing event-sourcing amazon-dynamodb-data-modeling

我正在AWS上设计一个事件存储,我选择了DynamoDB,因为它似乎是最好的选择。我的设计似乎不错,但是我遇到了一些我无法解决的问题。

**设计

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

  • StreamId:与gregationId相同,这意味着 one 聚合的 one 事件流。
  • EventId:一个递增的数字,有助于在同一事件流中保持顺序

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

partitionKey是StreamId,sortKey是EventId。

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

事件流

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

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

事件发布

事件是通过DynamoDB流+ Lambda的组合发布的。

重播事件

问题从这里开始。将每个事件流仅映射到一个聚合(导致具有大量事件流),没有容易的方法来知道我需要从哪个事件流中查询所有事件。

我正在考虑使用DynamoDB中某个附加记录,该记录将所有StreamIds存储在一个数组中。然后,我可以查询它并开始查询事件,但是如果在回放时创建了新的流,我会丢失它。

我想念什么吗?还是我的设计完全错误?

3 个答案:

答案 0 :(得分:1)

  

我想念什么吗?

并非如此;这是一个难题[tm]。

您的写用例通常只涉及模型内的单个引用-指向当前事件历史的指针。您的已读用例通常与分布在多个流中的数据有关。

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

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

取消协调,您就可以为每个流分配一个唯一的主机。

仔细查看Git object database并熟悉该商店底下的真实情况可能会很有用。我还发现Rich Hickey的演讲The Language of the System为区分valuesnamesreferences提供了有用的概念。

  

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

除非您有一些令人信服的商业理由要从头开始构建事件存储,否则我建议您改而研究Aurora,并从中获得多大的收益。它可能会为您节省您等待其他人为您提供经济高效的云原生事件存储设备所需的时间。

答案 1 :(得分:1)

您可以使用GSI检索给定时间段内的事件。根据所处理事件的数量,您可能需要编写GSI分片以避免出现热键。假设事件项小于1KB,如果摄取速率高于1000个项目/秒,则需要在GSI上分发它们。如果事件大于1KB,则需要将其扩展开。对于少于1KB的项目,请以每秒的事件总数除以1000。这将告诉您GSI需要与表保持同步的分片数量,例如假设您每秒接收5K事件,则需要5个分片。

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

答案 2 :(得分: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)。

我希望这会有所帮助。