6

在有关事务隔离级别的 PostgreSQL 文档中,我们可以阅读以下内容:

虽然在主服务器上的可序列化事务中执行所有永久数据库写入将确保所有备用服务器最终达到一致状态,但在备用服务器上运行的可重复读取事务有时会看到一个瞬态状态,该状态与在主服务器上任何串行执行可序列化事务不一致。掌握。

以上文字在http://www.postgresql.org/docs/9.4/static/transaction-iso.html的底部

在什么情况下,在热备用上运行的可重复读取事务可能会看到不一致的瞬态?

4

2 回答 2

5

Geir Bostad 的回答是正确的;我的回应只是为了提供一个示例和可能的解决方法,因为人们经常难以理解这一点。除了另一个答案中引用的 Wiki 页面之外,还有一个单独的 Wiki 页面仅用于示例,其中包括一个“存款报告”示例,该示例将批次视为已关闭但尚无法查看该批次的最终详细信息。

热备是只读的,所以它只能看到暂时的序列化异常;数据最终会在一些后续事务中稳定到一致的状态。这与主服务器上的可重复读取事务可能发生的情况相同,而主服务器上的可序列化事务则不可能。为防止混淆,在热备份上不允许可序列化事务,因为(还)不能保证在那里看到真正的可序列化事务行为。一直在讨论向 WAL 流添加信息,以识别可以启动可序列化事务的点,而不会有看到异常的风险,DEFERRABLE类似于START TRANSACTION; 这个(或类似的东西)可能会在未来的某个版本中添加。

对于使用快照隔离的只读事务(包括在 Oracle 或 9.1 之前的 PostgreSQL 版本中标识为可序列化的事务),最常见的异常类型似乎是 SELECT 列表或汇总在事务中显示为“已关闭”的批处理,没有看到应该包含在批次中的所有工作。要看到这一点,关闭批处理的事务必须“重叠”(同时运行)一些修改批处理详细信息的事务,关闭批处理的事务必须首先提交,然后(在关闭批处理的事务已提交之后和修改批处理详细信息的事务之前提交)只读事务必须启动并获取其快照。

为了防止这种情况,最简单的技术是在主数据库上“提升冲突”,从读写依赖变为写-写冲突。例如,在上面引用的“存款报告”示例中,可以将 deposit_total 列添加到控制表中,当 deposit_no 增加时,AFTER 触发器将其设置为零,并且可以将 AFTER 触发器添加到收据表中以更新金额基于每张收据的金额。这将导致基于控制记录的写入冲突的序列化失败,从而阻止异常传播到副本。

于 2015-06-22T17:41:37.317 回答
4

看起来这可能发生在批处理和类似的应用程序中。

我在有关SSI的 wiki 页面中找到了有关该主题的一些信息,并从 postgresql-hackers 邮件列表中找到了一些背景详细信息,他们在其中讨论了如何处理热备用上的序列化。

凯文格里特纳在他的帖子中写道:

在我看来,最常见和最令人担忧的情况是批处理。这在金融应用程序中极为常见,并且往往也出现在许多其他地方。

[..]

但是,备用数据库上的查询在运行查询时可能会看到暂时的异常,如果在事务流中的同一点在主数据库上运行会导致序列化失败。这只会发生在两个并发事务中,一个 似乎第二个运行的事务,因为另一个无法读取它所写的内容, 首先提交

[..]

在 SSI 下,将取消其中一项交易以防止这种情况发生。我们的实现将始终允许关闭批处理的更新完成,并且细节的插入或选择将因序列化失败而回滚,具体取决于这些事务中操作的时间。如果插入失败,则可以重试,并将进入新批次——使忽略它的批次列表正常。如果取消了批处理详细信息的列表,那将是因为在识别问题之前插入到旧批处理中已提交,因此立即重试 select 将看到完整的批处理内容。

热备用不能真正参与主节点上的谓词锁定和事务取消。

于 2015-03-03T16:36:38.770 回答