繁体   English   中英

坚持“平衡”实体的架构正确方法

[英]Architecturally correct way to persist "balance" entity

假设我们的应用程序中有balance实体,它由数据库中的一行表示。 它更新了不同的操作,如depositwithdrawal等。

现在我有一个压力测试,它连续创建一个deposits并在之后立即删除它。 理想情况下,我希望在测试结束时拥有 0 余额 - 因此每次创建的deposits都会增加balance ,比如 +1cu,并且删除它会相应地减少 -1cu

但是发生的事情是:

  • 如果事务的隔离级别 <= READ_COMMITED - 不会发生错误,但结果余额= 0。因为这些事务会覆盖彼此所做的更改。 这是非常糟糕的——我们要么赔钱,要么空手而归

  • 如果事务的隔离级别 >= REPEATABLE_READ - 我们仍然有余额,= 0 和控制台中的一堆错误。 因为有些交易没有成功。 除非我指定@Retryable ,在这种情况下 balance == 0,但控制台仍然出错,这可能没问题。 @Retryable也有默认为 3 的maxAttempts参数。感觉我不能确定这个“3”是否总是足够。

将平衡作为一个表行感觉不对。 但是总是将它重新计算为所有可能操作的总和也很奇怪。

我试图添加额外的表格来收集所有即将发生的平衡变化,然后再应用它们,但仍然面临单行瓶颈

TLDR

如何使用 Spring 和 PostgreSQL 设置余额持久性? 该案例是否有任何最佳实践或模式?

我建议您始终重新计算总和,并使用基于时间戳的分区和汇总表来提高性能。

这个想法是你有一个按时间戳分区的actions表(包含存款和取款),“当前”分区将只有一组有限的数据,即最近 N 个月的数据。 然后,在新的一个月开始时,您可以添加一个新分区,从而将旧数据移动到该分区。 作为创建分区的事务的一部分,您还在汇总表中创建一行,其中包含例如(year, month, balanceDelta)

最后,您像select sum(a.balance) + (select sum(st.balanceDelta) from summarization_table st) balance from actions a查询。

从长远来看,为了进一步提高性能,您还可以预聚合多个月份。

总的来说,我认为像 TimescaleDB(PostgreSQL 扩展)这样的方法与其连续聚合一起使用是最具扩展性和最简单的,但不确定您是否可以安装该扩展。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM