Postgres:优化并发同行更新



问题

我正在使用PostgreSQL v10 + golang,并且有一个我认为非常常见的SQL问题:

  • 我有一个表"计数器",它有一个current_value和一个max_value整数列。
  • 严格来说,一旦current_value >= max_value,我想放弃请求。
  • 我有几个 Kubernetes pod,对于每个 API 调用,它们可能会将"计数器"表中同一current_value(在最坏的情况下)增加 1(可以认为是分布式主机对同一数据库的并发更新)。

在我当前和幼稚的实现中,同一行的多个 UPDATES 自然会相互阻止(如果这很重要,隔离级别是"读取提交")。 在最坏的情况下,我每秒大约有 10+ 个请求会更新同一行。这造成了瓶颈并损害了性能,这是我负担不起的。


可能的解决方案

我想了几个想法来解决这个问题,但它们都牺牲了诚信或性能。唯一保持两者的听起来不是很干净,因为这个看似常见的问题:

只要计数器current_valuemax_value(增量> 100)在相对安全的距离内,就将更新请求发送到一个通道,该通道将由工作线程每秒左右刷新一次,该辅助角色将聚合更新并立即请求更新。否则(delta <= 100),在事务上下文中进行更新(并遇到瓶颈,但对于少数情况)。这将加快更新请求的速度,直到几乎达到限制,从而有效地解决瓶颈。


这可能有助于解决我的问题。但是,我不禁认为有更好的方法来解决这个问题。

我在网上没有找到一个很好的解决方案,即使我的启发式方法有效,它感觉不干净,缺乏完整性。

非常欢迎创造性的解决方案!


编辑:

多亏了@laurenz建议,我试图缩短 UPDATE 之间的持续时间,其中行被锁定到事务的 COMMIT 中。将所有更新推送到交易结束时似乎已经完成了伎俩。现在我可以每秒处理超过 100 个请求并保持完整性!

每秒 10 个并发更新少得离谱。只要确保交易尽可能短,就不会有问题。

你最大的问题将是VACUUM,因为大量的更新是PostgreSQL最糟糕的工作量。请确保创建的表fillfactor为 70 左右,并且current_value编制索引,以便获得 HOT 更新。

最新更新