amazon-web-services - DynamoDB - AWS 上的事件存储
问题描述
我正在 AWS 上设计一个 Event Store,我选择了 DynamoDB,因为它似乎是最好的选择。我的设计似乎相当不错,但我面临一些我无法解决的问题。
**该设计
事件由该对唯一标识(StreamId, EventId)
:
StreamId
:和aggregateId一样,意思是一个Event Stream对应一个Aggregate。EventId
:一个递增的数字,有助于将排序保持在同一事件流中
事件保留在 DynamoDb 上。每个事件映射到表中的单个记录,其中必填字段是 StreamId、EventId、EventName、Payload(可以轻松添加更多字段)。
partitionKey 是 StreamId,sortKey 是 EventId。
将事件写入事件流时使用乐观锁定。为此,我使用了 DynamoDb 条件写入。如果已经存在具有相同(StreamId,EventId)的事件,我需要重新计算聚合,重新检查业务条件,如果业务条件通过,最后再次写入。
事件流
每个事件流由 partitionKey 标识。查询所有事件的流等于查询 partitionKey=${streamId} 和 0 到 MAX_INT 之间的 sortKey。
每个事件流标识一个且只有一个聚合。如前所述,这有助于使用乐观锁定处理同一聚合上的并发写入。这也可以在重新计算聚合时提供出色的性能。
活动发布
利用 DynamoDB Streams + Lambda 的组合发布事件。
重播事件
这是问题开始的地方。将每个事件流仅映射到一个聚合(这导致拥有大量事件流),没有简单的方法可以知道我需要从哪些事件流中查询所有事件。
我正在考虑在 DynamoDB 中的某处使用一个额外的记录,它将所有 StreamIds 存储在一个数组中。然后我可以查询它并开始查询事件,但如果在我重播时创建了一个新流,我会丢失它。
我错过了什么吗?或者,我的设计是否完全错误?
解决方案
您可以使用 GSI 检索给定时间段内的事件。根据正在处理的事件数量,您可能需要编写 GSI 分片以避免热键。假设事件项小于 1KB,如果摄取率高于 1000 项/秒,则需要将它们分散到 GSI 上。如果事件大于 1KB,则需要将它们分散得更多。对于小于 1KB 的项目,将每秒的事件总数除以 1000。这将告诉您 GSI 需要多少分片才能跟上表格,例如假设您每秒摄取 5K 事件,您将需要 5 个分片。
当您将事件写入表时,添加一个名为“GSIKey”的新属性,并在插入事件时为该属性创建一个介于 0-4 之间的随机值。使用“GSIKey”作为分区键和时间戳作为排序键创建 GSI。当您需要获取给定时间范围内的所有事件时,请使用您正在查找的时间范围查询所有 5 个分片,然后简单地对结果集进行合并排序以生成按时间排序的事件列表。如果您每秒处理的事件少于 1000 个,那么您可以使用“0”作为 GSIKey 值,并在该分区中查询您需要的事件。
推荐阅读
- mongodb - 使用键和值创建对 mongodb 数据的反应路由获取请求,而不仅仅是 id
- excel - 如何使用vba为多列创建过滤器excel
- java - Netty 中的 io.netty.allocator.maxOrder 是什么?
- javascript - 使这个异步/等待逻辑工作的麻烦
- flyte - 是否有从字符串创建 blob 类型的示例?
- python - 熊猫:获取独特的元素然后合并
- javascript - document.addEventListener 不在 JEST 的覆盖范围内
- typescript - 如何在本机反应中解锁一个屏幕上的旋转
- javascript - 我无法在主机上启动 node.js
- xamarin.forms - 如何在 Xamarin Forms UWP 上设置深色主题?