Tun*_*ble 1 postgresql postgresql-bdr
显然只有行的新值在更新时在节点之间发送。那么怎么会有可检测的冲突呢?节点 A 从节点 B 接收更新,从节点 C 接收不同的更新。A 怎么知道发生了冲突?B 和 C 更新不是以某种明确定义的顺序进行的?
“last-update-wins”是什么意思?更新有时间戳吗?在哪种情况下它依赖于同步时钟?或者它只是意味着最后一次到达节点 A 的更新会获胜?
概括
Last Update Wins 意味着基于提交时间(需要相当同步的时钟),而不是节点看到更新的时间。所以应该是全局一致的。
没有任何可检测的更新/更新冲突(约束违规除外)。如果是的话,他们将很难解决。
冲突解决是逐行的,而不是逐个事务的。另见http://sdf.org/~riley/blog/2016/01/04/is-bi-directional-replication-bdr-in-postgres-transactional/
手册对此进行了大量讨论。
是的,提交带有时间戳。冲突解决使用提交时间戳,而不是单个元组插入/更新/删除的时间戳。请参阅track_commit_timestamps
postgres 文档。
在您的示例中,节点 A 可能会也可能不会看到冲突。如果 B 的更新首先发生(根据 B 的时钟),并且 B 的更新在 C 之前到达 A,则 A 不会看到冲突。但是,如果 C 的更新在 B 之前到达 A,并且 B 发生得更早,那么当 B 的更新到达 A 时,A 需要知道丢弃它,因为它已经应用了更新的更新。否则它会变得与 B 的状态不一致(它将在收到 C 的更新时应用 C 的更新)和 C(它用自己的较新的更新覆盖了 B 的旧更新)。
因为它是一个松散耦合的复制系统,没有全局锁管理器、快照管理器、事务管理器等,所以没有一个“现在”的概念,也没有一个全局一致的状态。或者至少由于延迟和复制滞后它是模糊的。您会看到这样的系统(有些不正确)被称为“AP”,因为CAP的“可用性”和“分区容限” 。它是一个最终一致的系统,其节点间保证比股票 PostgreSQL 更弱。您可以同时UPDATE
在两个不同的节点上创建一个元组。您可以INSERT
将相同的键放入两个不同节点上的 -UNIQUE
约束列(或相同PRIMARY KEY
)中。等等。
当节点复制和同步时,需要解决这些冲突,以便所有节点具有相同的结果并且不会导致错误。我们不能仅仅因为 xacts 已经在它们的原始节点上提交而出现 ERROR,而我们无法“取消提交”它们;即使我们这样做了,我们也不应该这样做,因为本地节点上的其他 xacts 可能已经使用这些提交的更改作为其他计算的输入,所以我们被它们困住了。
所以我们必须做一些事情,比如选择两个插入中最新的。我们为此使用提交的时间戳。它通过协议消息发送,并由 postgres 记录以用于本地提交。
旧行值对此无关紧要。例如,我们只关心某个对等节点更新了表“x”,但我们最近更新了它,因此我们假设应该保留较新的更新。否则,当我们的更改复制到对等节点时,它会应用我们的更改,如果我们也应用了他们的更改,我们将有不同的最终状态。为了获得一致的结果,我们必须放弃他们的变化。
类似地,如果插入了两个新行,我们必须始终选择其中之一以在它们在同一个 PK 上发生冲突时保留。我们根据记录的提交时间戳选择两行中最新的。
所以是的,它依赖于时钟。时钟不必完全同步,但大致正确是可取的,否则在解决冲突时可能会用明显较旧的元组覆盖较新的元组,即选择错误的“最后”更新。手册应该更多地讨论时钟同步。
在某些情况下,可以访问旧行值会很好,但不会让您确定正确的结果是什么。您仍然必须选择多个可能的“正确”结果之一。考虑一下:
给定的表
CREATE TABLE x (
id integer primary key,
y integer not null
);
INSERT INTO x (id, y) VALUES (1, 1);
Run Code Online (Sandbox Code Playgroud)
两个节点运行
UPDATE x SET y = y + 1 WHERE id = 1;
Run Code Online (Sandbox Code Playgroud)
同时。两者都会产生一个新的带有 value 的本地行y = 2
。现在每个都复制到另一个。
如果我们知道旧值是 1 而新值是 2,我们可能会说“好吧,呃,两个节点上的正确结果都是 3”。
但是我们无法知道一个或两个节点没有运行
UPDATE x SET y = 2;
Run Code Online (Sandbox Code Playgroud)
而不是y = y + 1
. 所以它可能希望最终结果是 2,而不是 3。唯一知道的方法是了解应用程序逻辑。BDR 不能仅根据新旧元组进行区分。
所以我们真的不需要旧的元组值。