查询流程疑问

【 TiDB 使用环境】生产环境
【 TiDB 版本】6.6
【复现路径】做过哪些操作出现的问题
【遇到的问题:问题现象及影响】两阶段提交是primary提交后返回提交成功。但此时secondary可能并未完成提交。这时候来查询相关的key,是不是只能查询到上一个事务提交的部分数据。
【资源配置】
【附件:截图/日志/监控】

数据隔离用的什么模式呢?
然后,你预想的场景是什么?

“secondary可能并未完成提交”,此时 secondary 的 Lock 还存在,其指向 primary。当新的事务查询,它会首先看到 Lock 存在,进而去查询 primary 的状态,如果发现已经提交,其会自动提交 secondary,最后再返回数据。所以不会存在“只能看到查询到上一个事务提交的部分数据”

TiDB 两阶段提交过程:

  1. TiDB 从当前要写入的数据中选择一个 Key 作为当前事务的 Primary Key。
  2. TiDB 从 PD 获取所有数据的写入路由信息,并将所有的 Key 按照所有的路由进行分类。
  3. TiDB 并发地向所有涉及的 TiKV 发起 prewrite 请求。TiKV 收到 prewrite 数据后,检查数据版本信息是否存在冲突或已过期。符合条件的数据会被加锁。
  4. TiDB 收到所有 prewrite 响应且所有 prewrite 都成功。
  5. TiDB 向 PD 获取第二个全局唯一递增版本号,定义为本次事务的 commit_ts
  6. TiDB 向 Primary Key 所在 TiKV 发起第二阶段提交。TiKV 收到 commit 操作后,检查数据合法性,清理 prewrite 阶段留下的锁。
  7. TiDB 收到两阶段提交成功的信息。
    你所说的的这种情况并不存在
1 个赞

这里tikv是先处理Primary Key的提交,提交成功后tidb收到提交成功。但此时secondary的key并未提交到tikv,来查询是查不到的。
根据楼上的回答,似乎是被动来查询时发现secondary的锁未被释放,查询primary状态后再提交,然后返回数据。是有查询被动提交与主动异步提交两个流程吗?

RC/SI级别似乎都有这个问题,在perlocator的primary提交完成,secondary异步提交未完成时间段内,该事务修改的KV对外似乎是部分可见的疑问

Shirly’s Blog (andremouche.github.io)
有段描述:
读取过程如下:

  1. 读取 key 时,若发现没有冲突的锁,则返回对应值,结束。
  2. 若发现了锁,且当前锁对应的 key 为 primary: 若锁尚未超时,等待。若锁已超时,Rollback 它并获取上一版本信息返回,结束。
  3. 若发现了锁,且当前锁对应的 keysecondary, 则根据其锁里指定的 primary 找到 primary所在信息,根据 primary 的状态决定当前事务是否提交成功,返回对应具体值。
2 个赞

tidb 只是引用了 Percolator 论文中的论点 ,对于乐观事务和悲观事务,在落地时参考了实际的应用场景,
不论是 2pc,还是 1pc,均以 primary key 提交为主。

不会出现你说的第三种状态,不然事务都没办法保证,后面咋玩? :upside_down_face:

你的问题,本质其实是想了解TiDB如何保证事务的一致性和隔离性。我先来回答,结论是不会。

下面请看解释:
你提到了两阶段提交的primary和secondary ,说明想了解的是一个包含多行数据的写操作事务。这里的primary准确来说是这个事务的主行 primary key,secondary是该事务中除了主行外的其他行secondary keys。

在2PC的第二阶段,主行先按照commit_ts清除锁信息和提交成功后,为了降低用户事务的延迟,会立即返回给用户说明当前的写事务已经提交成功,在用户侧此时事务已结束,在数据库侧数据也已经在tikv有了持久性(有故障也能自恢复)。在返回给用户事务已提交成功的同时,tikv也在并发地按commit_ts去对secondary keys提交,提交的时候包括清除lock CF的锁信息和写入提交信息到write cf。这个是写的基本过程。

然后你的问题是“这时候来查询相关的key,是不是只能查询到上一个事务提交的部分数据”,说明在primary key已提交而secondary keys未提交的过程,有一个读事务来读取相同primary key和secondary keys的数据。

  • 首先这个读事务是能读取到primary key的数据的,因为它已经提交且清理了锁信息;
  • 然后重点在于能否读到最新的secondary keys的数据,其实是会的。
    过程大概如下,这个读事务读到secondary keys时发现有锁,而且是secondary 的锁,然后就去查看它指向的主锁情况,发现主锁已经被清理主行已经提交,说明这个事务已经提交,所以对于自己而言是可以读到最新的数据的,此时它会和tikv系统交互一起完成secondary keys的提交和锁清理,保证事务彻底完成了提交,之后再返回secondary keys的数据。至此,这个读事务就能正确读取到最新的数据,而不会出现你说的只能读取部分数据的情况。
1 个赞

感谢耐心的解答,非常详细。
这里secondary keys的锁应该就是行锁吧,会阻塞其他对该行的提交操作。
THX.

这里的锁不是行锁,而是在 rocksdb ColumnFamily 的 LOCK 写入一个标识,

secondary keys的锁,就是会对每一个要更新的key-value 都分别加上锁,在rocksdb内部会给每个key在lock CF写入锁信息实现。

简单来看,对用户来说,效果可以理解为就是数据行的行锁

此话题已在最后回复的 60 天后被自动关闭。不再允许新回复。