暂无图片
暂无图片
暂无图片
暂无图片
暂无图片

第 5 章:OceanBase 事务引擎 5.2 并发控制

406

5.2 并发控制

快照管理

OceanBase 是基于 MVCC 和行锁实现数据库中的并发控制,涉及如下两种不同类型的快照。

  • 语句快照:读写语句开始执行时获取的版本号。

  • 事务提交快照,有如下两类:

    • 参与者的 Prepare 版本号(Prepare Version)。

    • 事务最终提交的 Commit 版本号(Commit Version),Commit Version 是所有参与者 Prepare Version 中的最大值。

具体如下表所示:

名称用途
Read Snapshot语句快照
Prepare Version事务 prepare version(即 2PC 参与者 prepare log timestamp)
Commit Version事务的 commit version(所有参与者 prepare log timestamp 最大值)
Local Timestamp Service1.X 版本提供的本地时钟服务
Global Timestamp Service2.X、3.x 版本提供的全局一致的时钟服务,事务支持外部一致性


索引结构

OceanBase 采用了 B-Tree、Hash 双索引结构,B-Tree 可以支持范围查询,Hash 可以提供更快的单点查询。

数据结构

图中各名词解释如下。

  • Row:ObMvccRow,多版本行。

  • Insert、update、delete 等:对应的结构为 MvccTransNode,多版本的修改的数据结构。

  • ObTransCallbackMgr:单个事务 MvccRow 回调的管理链表,回调涉及解锁回调和提交回调,解锁回调会将行锁解开,提交回调会给数据填上 commit 版本号。

MvccRow 具体格式

MvccRow

图中各名词解释如下。

  • Row lock:行锁。

  • List head:多版本数据的头指针,指向当前行最新的修改。

  • Max commit version:当前行最新成功事务的 commit version。

  • Compaction node:多版本数据修改到一定数量之后会做一次 compact,用于查询优化。OceanBase 数据库中默认修改六次后会做一次 compact,该值由配置项 row_compaction_update_limit 控制。

  • Commit version:事务提交版本号。

事务对行操作的时序

时序

图中各名词解释如下。

  • Register lock cb:用于事务 commit 成功之后,通过 cb 找到 trans node,触发解行锁。

  • Register commit cb:类似 lock cb,用于回填版本号,修改 trans node 状态 INIT->COMMIT。

  • Get prepare version:取 max(gts,max_log_ts) 作为该参与者的 prepare version。

  • Set prepare version:记录当前参与者的 prepare version,用于读写并发控制。

  • Commit cd:事务提交后的回调,找到对应的 trans node。

  • Unlock cd:事务提交后解除行锁。


读写并发

读写并发

读写并发时读不阻塞写;如上图,T1 结束之后 T2 才开始 prepare,T2 commit version 需要保证大于 T1 read snapshot。


写读并发

有关写读并发,根据读事务发生的时间不同,分为以下几种情况:

情况一

如上图,T1 的读事务发生在 T2 get prepare version 之后,T1 read snapshot = 250,由于 T2 没有提交,因此读不到 T2 的修改,但 T2 的 commit version = 200。导致 RC 的原则被打破:T1 没有读到 commit version <= 250 的所有修改。

OceanBase 有关该异常的解决方法为增加 before prepare 这一动作,由于 T1 read snapshot > T2 prepare_version,并且 T2 commit version 尚未知道,此时 T1 执行会被卡住,不会返回结果给客户端。

但这一操作还有一个问题,如下图,若 T1 的读事务执行过程中,T2 开始 prepare,如果此时 T2 的 prepare version 依旧是 200,参照情况一的解决方法进行,将导致 T1 的读取一直被卡住,对于读写会产生一定的影响。

情况二

此时的解决方法是让读语句尽快的知道 T2 的 prepare version,并保证 T2 的 prepare version 大于读语句的读快照,使读语句无法读到 T2 的修改,从而让读语句尽快结束。因此我们对该过程做了如下优化:

  1. T1 读取之前,推高 max readable ts 更新。

  2. T2 prepare_version = max(max_readable_ts, gts,…)。

若 T1 的读事务发生时,T2 已 commit 完成,此时 T1 read snapshot 根据 T2 commit version 大小关系,决定是否可以读取,如下图所示:

情况三

总结

T1 读取过程中,T2 的状态与 T1 相应处理逻辑:

  • T2 未 prepare,T1 不需要读该事务的数据,即读写并发。

  • T2 已 prepare 尚未 commit,但 T1 read_snapshot > T2 prepare_version,T1 等待 T2 事务提交。

  • T2 commit 完成,T1 read_snapshot 根据 T2 commit version 大小关系,决定是否可以读取。


写写并发

写写并发

写写并发在 RC 级别需要解决 Lost update 的问题,同时在 RR 级别下也需要进行对于不可串行化的判断。

  • RC:Lost update 检测与处理

    OceanBase 里的 update 更新包含 table_scan 和 update 两个动作,table_scan 过程中没有加锁,所以会出现丢失更新的情况,因此,在 update 过程中,如果出现 read_version < MvccRow 上的 max_commit_version 的情况,则出现 transaction set consistency(TSC),报错 ret=-6001,重试当前 SQL。

  • RR:不可串行化判断

「喜欢这篇文章,您的关注和赞赏是给作者最好的鼓励」
关注作者
【版权声明】本文为墨天轮用户原创内容,转载时必须标注文章的来源(墨天轮),文章链接,文章作者等基本信息,否则作者和墨天轮有权追究责任。如果您发现墨天轮中有涉嫌抄袭或者侵权的内容,欢迎发送邮件至:contact@modb.pro进行举报,并提供相关证据,一经查实,墨天轮将立刻删除相关内容。

评论