CockroachDB事务剖析-第二篇

本篇主要是讲述一些事务实现过程中的细节补充,比较琐碎,很多时候需要结合代码才能理解。

KV GC

CockroachDB后台任务定期扫描store的kv,MVCC数据最多保留25hour(默认配置,可以调整),不过最新的一条记录一定会保存不受这个限制。未push的TXN记录最多保留1hour,未提交的write intent最多保留2hour。

cockroachDB的事务记录中并不保存事务的提交记录,因此GC的时候分别处理这两个逻辑,同时也意味着cockroachDB的事务没有明显的条目限制。

Timestamp cache

timestamp cache缓存最近读写的key和以及其事务记录信息,用于事务冲突检查。timestamp cache有大小限制,内部采用page轮转的方式淘汰old的page。

timestamp cache存在一个低水位线和高水位线,HLC.time低于低水位线的key会被丢弃,不会缓存。高水位线用来修正dumped的事务的提交时间戳。

lease holder发生lease切换的时候,需要重置timestamp cache的低水位线。

Latch manager

核心作用是具有重叠操作区间的读写并发控制,它允许读操作的并发,写操作是串行进行的。

每次读写操作的时候都需要申请一个看门狗,来保证在操作完成以前,如果本操作是写操作,那么阻塞一切操作,如果本操作是读操作,阻塞写操作。

Range Lease

range副本存在两个逻辑上独立的角色lease holder, leader holder.其中leader holder是raft leader所在的副本,它具备唯一的提交raft log的权利。lease holder的存在主要是解决以下几个问题:

1. 管理range的分裂,合并

2. 本地读写,降低网络开销

CockroachDB中会保证lease

holder和leader holder是同一个节点,这通过两个流程保证,一个是当发生lease转移的时候,如果新的lease holder不是leader holder会主动发起transferLeader,另一个是在提交raft log的时候,发现lease holder不是leader holder的时候会主动设置成候选人状态,发起选举。保证提交一定是本地提交。

Lease holder对写操作会先在本地完成,然后才提交raft。这样做的好处就是如果本地执行失败,那么无需raft,直接返回给客户端即可。

在副本应用raft log的时候,会检查是否是当前lease holder提交的日志,如果是,那么不需要再次执行。

另一个好处就是read本地读取是安全的。不会因为当lease holder和leader holder不是同一个副本的时候,出现不能满足快照读。

3. 解决脑裂问题

参阅通过 raft 的 leader lease 来解决集群脑裂时的 stale read 问题

refresh timestamp

CockroachDB事务中维护一个refresh timestamp,这个字段的存在的逻辑是这样的。如果一个事务在执行过程中发生了retry错误,那么已经prepare的数据需要refresh到新的timestamp。检查在旧的事务提交时间到refresh timestamp之间如果本事务涉及到的读写数据在这个时间间隔内有新的写,那么refresh失败。这样保证refresh事务时,保证SSI隔离的正确性。

对于事务,cockroachDB没有限制事务的大小,但是如果发生了refresh并且refresh失败同时refresh涉及的key的总size超过256 * 1000(并不是具体的key的size的总和,而是span的总和)。

CockroachDB为什么放弃SI隔离级别

问题来源于一个PR storage: SNAPSHOT isolation violation with write timestamp cache #26460

举例来说,如下场景:

并发的发起以下三个事务

INSERT INTO kv VALUES ($1, 1) ON CONFLICT DO UPDATE SET v = v+1

DELETE FROM kv

SELECT * FROM kv

那么存在这样一种执行顺序

1. Read for INSERT

2. DELETE

3. Write for INSERT. The WriteTooOld flag is set and the transaction restarts.

4. Read for INSERT, seeing the outcome of the delete.

5. Write for INSERT

问题出在第三步,insert的时候检查timestamp cache发现有一个更大的提交时间戳导致insert事务需要restart。事务restart的时候会重置事务的提交时间戳(也是事务中读操作使用的时间戳)为这个冲突的时间戳+1,因此事务重试的时候读取到了后来发生的delete的记录,破坏了快照隔离。

笔者个人认为这个问题是cockroachDB自己设计的问题,应该是受限与固有的逻辑框架,修改起来比较费力,幸运的是SSI隔离级别不受影响,因此暂时搁置了。

你可能感兴趣的:(CockroachDB事务剖析-第二篇)