在事件存储中保留每个聚合的最新版本的快照

时间:2015-12-08 16:59:03

标签: cqrs event-sourcing

我们目前正在使用SQL支持的事件存储(典型的2表实现),并且团队中的一些人担心即使我们仅将事件存储用于写入,事情可能会变慢一些,因此提出了一个建议,而不是在这里和那里添加快照,以实际维护每个聚合在其最新状态(以JSON格式)的完全一致(具有事件流)快照。系统上的所有查询都将最终在读取端完成,典型的SQL数据库将以ES(写入)端的最终一致性方式进行更新。

拥有这样的系统可以让我们享受拥有Event Store的好处,同时完全消除任何可能的性能问题。我们目前没有使用任何“时间旅行”功能,虽然很快就会结束。

这是一个好方法吗?有一些东西让我感到不舒服。例如,如果我们需要某种时间旅行功能,那么在每个聚合的事件流中不存在快照将证明是性能灾难。当然,我们可以同时拥有每个聚合实例的最新当前快照以及整个事件流中的快照。

如果我们决定沿着这条路线前进,我们是否应该为同一聚合上的事件更新创建给定聚合事务的快照更新,或者我们应该只更新事件并以最终一致的方式更新快照?

这种方法的缺点是什么?有没有人尝试过类似的东西?

1 个答案:

答案 0 :(得分:6)

在为系统添加不必要的复杂性之前,您应该运行自己的基准测试。当需要查询并应用数千个事件来重建事件流中的聚合时,我们注意到了一些性能问题,其中JSON到对象反序列化是最大的性能瓶颈。如果您的每个聚合事件只有很少的事件(例如,<100),您可能不会注意到实践中的任何重大差异。

大多数事件存储记录每个n事件/提交的快照,例如每50-100个事件,并在汇编时查询最新快照并应用自上次快照以来丢失的事件。如果您还在快照数据库中保留所有旧快照,则时间旅行功能将与通常的查询一样快,并且您只需要稍微多一点的持久性空间,这在现在很便宜。

快照应该始终从原始事务中写出(并且可以在另一个线程中生成),因为如果缺少最后一个快照,它是非关键的,但是您希望不希望业务事务失败到期快照写入事务中的错误。

根据您通常的系统正常运行时间和数据大小,在内存或分布式缓存/格式或其他数据库(非SQL)中保存快照可能有意义。