CockroachDB读取事务

问题描述

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

  • Spanner的方法更简单-在提交写事务之前,Spanner选择所有涉及的分片上的最大时间戳作为提交时间戳,并为最大时钟错误添加一个称为 commit wait 的等待。从它的写事务返回之前。这意味着所有因果相关的事务(读取和写入)的时间戳值都将高于前一次写入的提交时间戳。对于读取的事务,我们选择服务节点上的最新时间戳。例如,如果在时间戳5处提交了一次写操作,并且最大时钟错误为2,则将来的写和只读事务的时间戳将至少为7。
  • 另一方面,
  • CockroachDB做的事情更复杂。在写入时,它在所有涉及的分片中选择最高的时间戳,但不等待。读取时,它将初始读取时间戳记指定为服务节点上的当前时间戳记,然后通过读取所有分片并重新启动读取事务来乐观地进行操作(如果任何分片上的任何键报告了写入时间戳记,这可能意味着不确定写入是否为因果关系)在读取事务之前。假定写时间戳小于读事务时间戳的键要么出现在读事务之前,要么与之并发。不确定性机制在比读取的事务时间戳更高的时间戳上起作用。例如,如果在时间戳8处提交了写操作,并且为读取事务分配了时间戳7,则我们不确定该写操作是在读取之前还是之后,因此我们以读取时间戳8重启读取事务。 / li>

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


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

  1. 一个用户阻止了另一个用户,然后发布一条消息,表示他们不希望被阻止的用户视为一个写事务。
  2. 被阻止的用户将其朋友列表和帖子加载为一项已读事务。

例如,请考虑朋友列表和帖子生活在不同的分片上。然后发生以下排序(假设最大时钟误差为2)

  1. 最初的帖子和朋友列表是在时间戳5提交的。
  2. 读取事务在时间戳7开始,它读取好友列表,该列表被视为在时间戳5提交。
  3. 然后在6点提交用于阻止朋友并发表帖子的写事务。
  4. 读取的事务将读取帖子,它被视为在时间戳6提交。

现在,由于读取事务在同一事务中看到旧的写入和较新的写入,因此事务违反了可序列化性。

我想念什么?

解决方法

CockroachDB通过称为timestamp cache的机制来处理此问题(这是一个不幸的名字;它并没有太多缓存)。

在此示例中,在第二步中,当事务在时间戳7读取朋友列表时,保存朋友列表的分片会记住它已在t = 7时为该数据提供了读取(读取事务请求的时间戳) ,而不是存在的数据的最后修改的时间戳记),并且它不再允许使用较低的时间戳记提交任何写操作。

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

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