所以我认为我有一个相当复杂的系统,它正在开始出现。写出所有表格太复杂了,但这里是一个简短的描述。
基本上我正在为帖子创建一个像 StackOverflow 这样的徽章系统。你有这些类型的表:
- 用户
- 帖子
- 事件(保存到数据库,以便您知道每个重要事件何时发生)
- user_statistics(徽章计数汇总等)
- post_statistics(帖子上的操作计数汇总,“已编辑 20 次”)
- user_badges(授予用户徽章)
- 徽章类型
然后假设您“更新帖子”。这是发生的事情:
- 帖子记录已更新
- 接下来会创建事件记录,上面写着“更新操作”,只有在它不存在时才会创建,否则它会重用相同的更新事件(以免防止向系统发送垃圾邮件)。它与帖子 ID 和用户 ID 相关联。
- 更新用户统计信息以计算新事件(如果已创建)。可能有多个统计信息需要更新,因为这些统计信息可能仅限于某些类别(例如特定语言的所有帖子)
- 如果统计数据达到阈值,则检查我们是否需要创建一个徽章或潜在的多个徽章,然后创建徽章。
- 可能会创建通知记录。
- 可能还有其他一些事情,例如提升站点上的权限,因为他们有更多的声誉,等等。
- 所有这一切都需要成功,所以没有什么可以做的(所有计数都是正确的,并且徽章被正确授予)。
您如何在 PostgreSQL 中适当地完成此任务?在我的具体情况下,似乎有大约 10 个表被查询,至少 5 个表被修改(创建或更新记录)。所有这些在理论上应该是原子的,在一个事务中,但是打包到一个事务中似乎很多,特别是如果你有这些“事件”在一秒钟内多次出现。
我能想到的唯一可能解决这个问题的初始方法是 使用队列和后台作业。上述每个步骤都将在事务之外按顺序完成,步骤之间可能存在时间间隔。所以会有一个中间状态,事情是不一致的。但最终(理论上似乎),队列将运行并重试直到成功,并进入正确的状态。这应该怎么做?
如果不是,是否可以在每个事件上进行单一交易的复杂性?我不知道,我不认为实施徽章和这些计数器的解决方案会变得如此复杂,但每个事件都有很多需要考虑和做的事情。基于您构建可扩展数据库系统的专业知识,我正在寻找任何指向正确方向的指针。
假设这个系统一定是这么复杂,因为我在理论上真的是在问如何处理复杂的事务需求。也就是说,如果您知道一种对徽章系统进行建模的理想方法,那会很高兴知道,但不会真正解决问题的主要部分。感谢您的帮助!
目前,就我的目的而言,一切都可以被认为适合单台机器,而不是分布在多个数据库中。
同意 Charlieface 在评论中的观点,原因如下:
“特别是如果你有这些“事件”在每秒多次出现“-如果整个事务只需要 10 毫秒的运行时间,你可以让这些事件每秒发生 100 次并且 0 阻塞争用。大多数查询在针对正确索引的表进行正确架构时,执行时间不应超过几毫秒到几百毫秒。
“可以在每个事件上进行这种复杂的单一交易吗? ” - 是的。但是,当有第三种选择 - 多个事务时,您似乎只提到了涉及全部或全部事务的解决方案。您应该只将需要立即在事务上保持一致的对象放在同一个事务中。因此,根据您描述的工作流程,我会说事务可以包装记录的更新
Post
和创建Event
。第二个事务可以只包装不同统计表的更新以及这些统计信息的相关操作,例如创建Badge
和创建Notification
给用户。第三个事务可以处理确保所有相关表更新的特权更改是原子的。此外,就 Charlieface 而言,汇总和统计数据通常不需要在 100% 的时间内 100% 准确。如果您遵循我之前观点的事务模式,并且在极少数情况下更新统计表的事务失败,您仍然应该每晚(或任何有意义的节奏 - 可以是每小时,可以是每周等)重新计算这些统计数据以解决任何后果的工作。这样您就可以两全其美:大多数情况下数据是原子准确的,在极少数情况下并非如此,最终会如此,而且通过将单个事务分解为多个将锁定所有事务的较小事务来提高工作流程性能当进程运行时,这些数据库对象的时间范围甚至更短。