关于数据库:带着问题读-TiDB-源码Hive-元数据使用-TiDB-启动报错

14次阅读

共计 4453 个字符,预计需要花费 12 分钟才能阅读完成。

《带着问题读源码系列》- 开篇

在 TiDB 社区沉闷较久的搭档们应该晓得,过来咱们有被称为 24 章经的《TiDB 源码浏览系列文章》,也有面向 TiKV 的《TiKV 源码解析系列文章》以及《Deep Dive TiKV 系列文章》。这些系列文章的内容十分深刻,可能帮忙大家从十分细节的原理动手理解 TiDB 以及 TiKV 的实现形式和根底原理。

然而在 TiDB 社区中沉闷的许多搭档还须要更简略,并且同本人每天工作中应用 TiDB 时遇到的问题更相干的源码阅读文章。本文是《带着问题读源码系列》的第一次尝试,在定位并解决用户所遇到的一个简略问题的过程中,对相干的代码一并进行介绍。心愿可能从不同的视角,以不同的问题颗粒度来帮忙大家更好的学习 TiDB 和 TiKV 的源码。

AskTUG 上有许多用户日常应用 TiDB 过程中遇到的问题反馈,这些问题都可能成为同本文相似的源码解析素材。如果本文可能为大家发明价值,那么咱们肯定致力将《带着问题读源码系列》继续建设成同前辈们一样受大家欢送的源码浏览系列。

问题

近期在 AskTUG 论坛接到用户反馈应用 TiDB 作为 Hive metastore 数据库时设置 SERIALIZABLE 事务隔离级别失败。并且用户依据文档倡议进行 SET GLOBAL tidb_skip_isolation_level_check=1 操作后依然无奈依照预期解决问题。思考到知乎在一年前就已正式上线并始终应用着 4.0.x 系列的 TiDB 作为 Hive metastore 的数据库,而用户依照阐明文档操作依然无奈顺利在 TiDB 上部署 Hive metastore 意味着很可能 TiDB 在不同的版本间产生了不兼容的行为扭转。接下来就让咱们一起从问题的排查动手,学习理解相应性能背地的源代码。

验证流程

在 tiup 的帮忙下咱们可能十分轻松的启动多个不同版本的 TiDB 对事务隔离级别的行为进行测试和验证。

首先咱们先启动 5.0.0 版本的 TiDB 集群筹备测试

接下来咱们应用 tiup 提醒的连贯命令应用 mysql client 连贯上测试集群,在设置完 SET GLOBAL tidb_skip_isolation_level_check=1 之后应用 SET TRANSACTION ISOLATION LEVEL SERIALIZABLE 验证行为合乎预期。阐明 TiDB 5.0 系列的行为同 4.0 统一,可能撑持 Hive metastore 的运行。

接下来咱们启动 5.1.0 版本的 TiDB 集群筹备测试

同样咱们应用 mysql client 连贯上测试集群,在设置完 SET GLOBAL tidb_skip_isolation_level_check=1 并重建链接确保设置失效后,应用 SET TRANSACTION ISOLATION LEVEL SERIALIZABLE 依然会收到错误报告。阐明从 TiDB 5.1 系列开始行为同以往版本不统一,无奈满足 Hive metastore 的要求。

问题剖析

首先咱们须要 checkout 一份最新 TiDB 代码(git hash: 649ed6abc9790cfdd2a17065118379d8abcc7595)查看事务隔离级别校验相干逻辑。为了疾速定位到相干逻辑所在的代码,咱们能够在 TiDB 代码的根目录下对字符串 SERIALIZABLE 进行文本检索,疾速定位到可能与此有关的代码文件。

咱们发现实际上蕴含字符串 SERIALIZABLE 的文件有两个,而其中对隔离级别进行判断进行解决的文件只有 sessionctx/variable/varsutil.go 这一个文件。关上文件后咱们发现这里正是对隔离级别进行判断并依据 tidb_skip_isolation_level_check 设置决定是否通过的逻辑。

咱们能够同行为合乎预期的 5.0 版本 TiDB 代码(git hash: 53251a9731da02ad9ee5abed9f27a14c7dea33a4)进行比照来疾速定位两者间行为不同是由那些变动引起的。同样咱们通过字符串匹配疾速定位到 sessionctx/variable/sysvar.go 和 sessionctx/variable/session.go 两个文件都存在对隔离级别进行条件解决的状况。

这两个不同的查看逻辑十分相似,都是试图获取 TiDBSkipIsolationLevelCheck 变量的设置,依据设定值决定是否予以放行。当咱们将这里的逻辑同 master 代码中的逻辑进行比照时咱们发现他们实质上的区别十分小。5.0 中应用了一个内置工具函数 GetSessionSystemVar 来获取变量值,而 master 代码则间接拜访 SessionVars 的 systems 变量表进行拜访来获取 TiDBSkipIsolationLevelCheck 变量的以后值。进一步查看 5.0 中 GetSessionSystemVar 的实现咱们发现这个工具函数负责在 session 变量未设置时进一步到全局变量表中进行查找并将查找到的后果搁置在 SessionVars 的 systems 变量表中供后续查找应用。

依据目前的线索猜想,在 5.1 某次代码重构试图将两个类似的反复隔离级别查看逻辑合并成一个通用逻辑的时候绕过了工具函数间接拜访 systems 变量表。这种形式拜访变量表不具备从前工具函数主动回退全局变量设定的能力。理解到这里修复非常简单,只需应用以后 TiDB 中相似工具函数 GetSessionOrGlobalSystemVar 来读取 TiDBSkipIsolationLevelCheck 的变量值就能复原预期行为。

修复并实现构建后再次测试 TiDB 的行为已合乎预期。

提交修复

依据 TiDB 社区规范的代码奉献流程,咱们首先创立一个新的 Issue 对发现的问题、复现形式以及冀望的行为做清晰的形容。

创立完 issue 后咱们就能够将修复逻辑提交到本人 fork 的仓库并创立 PR,创立过程中须要依据理论状况填充 PR 信息模版。

创立实现后 CI 零碎会对提交的 PR 进行一系列的负责查看并执行必要的测试,除了这些零碎自动化的验证之外。其余社区贡献者会对 PR 进行 code review,在有足够来自于 TiDB Reviewer 及以上权限的贡献者对 PR 点赞后变更才可能被合并到我的项目骨干中。

在 PR 提交后不久就失去了 @morgo 的 review 反馈,反馈切中时弊的指出了问题背地的真正起因是 PR #24836 中对 TiDBSkipIsolationLevelCheck 变量初始化行为的谬误变更,去掉 TiDBSkipIsolationLevelCheck 变量定义中的 skipInit: true 初始化字段即可确保 session 初始化时正确的将 global 变量值复制到 session 中,让后面的隔离级别查看逻辑行为恢复正常。依据这个线索进行代码批改并理论测试证实体现合乎预期,接下来让咱们持续剖析 skipInit 相干的源码探个到底。

代码中所有对 skipInit 变量的读取操作都封装在上图的 SkipInit 函数中,从下图中咱们能够看到 SkipInit 办法用于在初始化新的 session 变量 cache 的过程跳过局部变量。

接下来 newSessionCache 被更新到 session 变量中并通过下图中的 GetSessionCache 办法对外提供拜访。

而 GetSessionCache 办法只有一个调用方 loadCommonGlobalVariablesIfNeeded,到这里 skipInit 对系统变量初始化流程的影响就十分清晰了。

当 session 创立实现后,没有标记为 skipInit 的变量都会以变量的初始值的模式更新到会话变量表中,也就是后面提到的 systems 变量表中。当咱们将 TiDBSkipIsolationLevelCheck 的 skipInit 复原为 false 之后,全局变量 tidb_skip_isolation_level_check 可能在这个初始化的过程中被正确的复制到用户会话,使得调整会话事务隔离级别的行为合乎用户预期。

在问题失去解决后,大家可能还会问在什么样的状况下 skipInit 须要被设置成 true。在引入这个性能的 PR #24836 中咱们能够得悉局部不适宜在初始化过程中复制到会话中的变量会利用这个标记实现黑名单性能。而在这次重构过程中 TiDBSkipIsolationLevelCheck 被谬误的设置在黑名单中导致了 5.1 开始版本行为的异样。

What problem does this PR solve?

Problem Summary:Currently the builtinGlobalVariable feature is a source of bugs because even though a sysvar is added, it is not automatically copied to new sessions. This behavior is also not MySQL compatible, where it is expected a sysvar of session scope should be copied on session init.Fixing the full incompatibility is a little bit more complicated, but this takes the initial step of inverting from an allow list to a deny list, but is otherwise functionally compatible.This also includes the fix from #24835 should this PR supercede it.

What is changed and how it works?

What’s Changed:A variable on the SysVar struct can now be set to skipInit. By default it will not skip for session-scope variables, which is why it is now a deny list.However, it will always skip for noop variables, which helps keep the memory footprint of new sessions slightly lower.

Related changes

None
There will need to be followup PRs to handle the specific skipInit variables; some probably don’t need to be on this list. The global-only variables that are hard-coded into the SkipInit function will also need removing.
后记

感激向社区报告 TiDB 行为异样的热心用户,十分遗憾没能在故障产生的第一工夫定位并解决问题。但咱们依然心愿在新版本公布修复这个问题后 TiDB 可能为你撑持 Hive metastore 乃至更多业务场景起到踊跃作用。

正文完
 0