CockroachDB 读取事务

CockroachDB read transactions

我一直在阅读 Google Spanner 和 CockroachDB 中实现的只读无锁事务。两者都声称通过使用系统时钟以无锁方式实现。在开始提问之前,这是我的理解(如果您了解两个系统中的机器或只了解 CockroachDB 中的机器,请跳过以下部分):

相关来源 - https://www.cockroachlabs.com/blog/living-without-atomic-clocks/ and https://static.googleusercontent.com/media/research.google.com/en//archive/spanner-osdi2012.pdf


鉴于此实现,CockroachDB 是否保证以下两个事务不会违反可串行性?

  1. 一个用户阻止了另一个用户,然后 post 发送一条他们不希望被阻止的用户看到的消息作为一个写入事务。
  2. 被阻止的用户将他们的朋友列表和他们的 post 作为一个读取事务加载。

例如,假设好友列表和 post 存在于不同的分片上。并且发生以下排序(假设最大时钟误差为 2)

  1. 最初的 post 和好友列表是在时间戳 5 提交的。
  2. 读取事务从时间戳 7 开始,它读取好友列表,它认为该列表是在时间戳 5 提交的。
  3. 然后在 6 点提交用于阻止朋友和制作 post 的写入事务。
  4. 读取事务读取 posts,它认为这是在时间戳 6 提交的。

现在,事务违反了可串行化性,因为读取事务在同一事务中看到旧写入和新写入。

我错过了什么?

CockroachDB 使用一种叫做 timestamp cache 的机制来处理这个问题(这是一个不幸的名字;它不是一个缓存)。

在这个例子中,在第二步,当事务在时间戳 7 读取好友列表时,保存好友列表的分片记住它已经在 t=7(请求的时间戳读取事务,而不是现有数据的 last-modified 时间戳)并且它不再允许任何写入以较低的时间戳提交。

然后在第三步中,当写入事务尝试在 t=6 写入并提交时,会检测到此冲突,并且写入事务的时间戳会被推到 t=8 或更高。然后该事务必须 refresh its reads 以查看它是否可以在 t=8 时提交 as-is。否则,可能会返回错误,必须从头重试交易。

在第四步中,读取事务完成,看到了数据在 t=7 时存在的一致快照,而写入事务的两部分都在 t=8 时处于“未来”状态。