postgre如何一致地跟踪SQL数据库表中的所有新行



我要做的事情

我正在开发一个web服务,它在多个服务器实例中运行,所有实例都访问同一个RDBMS(PostgreSQL(。虽然数据库是持久性所必需的,但它包含的数据很少,这就是为什么每个服务器实例都有一个所有数据的缓存。此外,该应用程序非常简单,因为它只在相当简单的表中插入新行,并以预定的方式从所有服务器实例中选择数据(没有更新或更改……只有插入和读取(。

目前的实施方式

基本上我有一张大致如下的表格:

id BIGSERIAL,
creation_timestamp TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
-- further data columns...

服务器每隔几秒钟就会做这样的事情(伪代码(:

get all rows with creation_timestamp > lastMaxTimestamp
lastMaxTimestamp = max timestamp for all data just retrieved
insert new rows into application cache

我遇到的问题

应用程序在更新缓存时跳过某些行。我分析了这个问题,发现问题是由以下方式引起的:

  1. 一个服务器实例正在事务上下文中创建一个新行。从相关联的序列(id=n(中检索新行的id,并设置creation_timestamp(具有值ts_1(
  2. 另一个服务器在不同事务的上下文中执行相同的操作。该事务中的新行得到id=n+1和creation_timestamp ts_2(其中ts_1<ts_2(
  3. 事务2在事务1之前完成
  4. 其中一个服务器执行"select all rows with creation_timestamp>lastMaxTimestamp"。它得到第n+1行,但不是n1行。它将lastMaxTimestamp设置为ts_2
  5. 事务1完成
  6. 一段时间后,步骤4中的服务器再次执行"select all rows with creation_timestamp>lastMaxTimestamp"。但是由于lastMaxTimestamp=ts_2和ts_2>ts_1,因此永远不会在该服务器上读取行n

注意:CURRENT_TIMESTAMP在事务期间具有相同的值,即事务开始时间。

因此,应用程序将不一致的数据放入其缓存,并且无法根据插入时间戳或序列id获取新行。事务隔离级别并不会真正改变这种情况,因为问题本质上是由事务2在事务1之前完成造成的。

我的问题

我是不是错过了什么?我认为必须有一种简单的方法来获取RDBMS的所有新行,但我无法想出一个简单的解决方案。。。至少用一个一致的简单解决方案。由于性能原因,不能接受广泛的锁定(例如表(。简单地试图确保从该序列中获取所有id似乎是a(一个复杂的解决方案,b(不容易做到,因为在事务期间可能会发生回滚(这将导致序列id不被使用(。

有人有解决方案吗?

经过大量搜索,我找到了合适的关键词来搜索。。。"事务提交时间戳"导致各种事务时间戳跟踪和系统列,如xmin:

https://dba.stackexchange.com/questions/232273/is-there-way-to-get-transaction-commit-timestamp-in-postgres

这篇文章有一些更详细的信息:

关于Postgres track_commit_timestamp(pg_xact_commit_time stamp(的问题

简而言之:

  • 您可以打开postgresql选项来跟踪提交的时间戳,并比较这些时间戳,而不是事务中的current_timestamps/clock_timestaps
  • 然而,它似乎只在事务完成时才被跟踪,而不是在提交时,这使得解决方案不是防弹的。还有其他需要考虑的问题,例如事务id(xmin(滚动
  • 逻辑解码/复制是寻找合适解决方案的方法

感谢所有试图帮助我找到答案的人。我希望这个总结对将来的人有用。

最新更新