问题
我正在使用 PostgreSQL v10 + golang,并且遇到了一个我认为非常常见的 SQL 问题:
- 我有一个表“计数器”,其中包含
current_value
和max_value
整数列。 - 严格来说,一旦
current_value >= max_value
,我就会放弃该请求。 - 我有几个 Kubernetes pod,对于每个 API 调用,它们可能会将“计数器”表中同一行(在最坏的情况下)的
current_value
增加 1(可以被认为是从分布式主机对同一数据库的并发更新)。
在我当前的幼稚实现中,对同一行的多个更新自然会相互阻塞(如果重要的话,隔离级别是“已提交读”)。 在最坏的情况下,每秒大约有 10 个以上的请求会更新同一行。这会造成瓶颈并损害性能,这是我无法承受的。
可能的解决方案
我想到了几个解决这个问题的想法,但它们都牺牲了完整性或性能。对于这个看似常见的问题,唯一一个保留两者的听起来不太干净:
只要计数器 current_value
与 max_value
的距离相对安全(delta > 100),就将更新请求发送到每秒刷新的 channel ,或者因此,由一个工作人员聚合更新并立即请求它们。否则(增量 <= 100),在事务上下文中进行更新(并遇到瓶颈,但仅适用于少数情况)。这将加快更新请求的速度,直到几乎达到限制,从而有效地解决瓶颈。
这可能有助于解决我的问题。但是,我忍不住认为有更好的方法来解决这个问题。
我在网上没有找到很好的解决方案,尽管我的启发式方法可行,但感觉不干净且缺乏完整性。
非常欢迎创造性的解决方案!
编辑:
感谢 @laurenz-albe 的建议,我尝试缩短行被锁定到事务的 COMMIT 之间的持续时间。将所有更新推送到事务末尾似乎已经成功了。现在我可以每秒处理超过 100 个请求并保持完整性!
最佳答案
每秒 10 个并发更新是少得离谱。只要确保事务尽可能短,就不会出现问题。
你最大的问题将是VACUUM
,因为大量更新对于 PostgreSQL 来说是最糟糕的工作负载。确保您创建的表的 fillfactor
为 70 左右,并且 current_value
未编入索引,以便获得热门更新。 p>
关于postgresql - Postgres : Optimising concurrent same row updates,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/55539927/