问题
我正在使用PostgreSQL v10 + golang,并且有一个我认为非常常见的SQL问题:
- 我有一个表"计数器",它有一个
current_value
和一个max_value
整数列。 - 严格来说,一旦
current_value >= max_value
,我想放弃请求。 - 我有几个 Kubernetes pod,对于每个 API 调用,它们可能会将"计数器"表中同一行的
current_value
(在最坏的情况下)增加 1(可以认为是分布式主机对同一数据库的并发更新)。
在我当前和幼稚的实现中,同一行的多个 UPDATES 自然会相互阻止(如果这很重要,隔离级别是"读取提交")。 在最坏的情况下,我每秒大约有 10+ 个请求会更新同一行。这造成了瓶颈并损害了性能,这是我负担不起的。
可能的解决方案
我想了几个想法来解决这个问题,但它们都牺牲了诚信或性能。唯一保持两者的听起来不是很干净,因为这个看似常见的问题:
只要计数器current_value
与max_value
(增量> 100)在相对安全的距离内,就将更新请求发送到一个通道,该通道将由工作线程每秒左右刷新一次,该辅助角色将聚合更新并立即请求更新。否则(delta <= 100),在事务上下文中进行更新(并遇到瓶颈,但对于少数情况)。这将加快更新请求的速度,直到几乎达到限制,从而有效地解决瓶颈。
这可能有助于解决我的问题。但是,我不禁认为有更好的方法来解决这个问题。
我在网上没有找到一个很好的解决方案,即使我的启发式方法有效,它感觉不干净,缺乏完整性。
非常欢迎创造性的解决方案!
编辑:
多亏了@laurenz建议,我试图缩短 UPDATE 之间的持续时间,其中行被锁定到事务的 COMMIT 中。将所有更新推送到交易结束时似乎已经完成了伎俩。现在我可以每秒处理超过 100 个请求并保持完整性!
每秒 10 个并发更新少得离谱。只要确保交易尽可能短,就不会有问题。
你最大的问题将是VACUUM
,因为大量的更新是PostgreSQL最糟糕的工作量。请确保创建的表fillfactor
为 70 左右,并且current_value
未编制索引,以便获得 HOT 更新。