睡觉的时分,步骤能不克不及主动查 bug?
作者 | 杜沁园 等
责编 | 郭芮
出品 | CSDN(ID:CSDNnews)
曾在 Hacker News 上看到过一个 Oracle 工程师处理 bug 的 平常:
先花两周支配时间来了解 20 个参数怎样经过神奇的组合引发 bug。
改了几行代码,实验对 bug 举行修复,提交测试集群开头跑近百万个测试 case,通常要 20~30 小时。
运气好的话会有 100 多个 case 没过,偶尔分上千个也有约莫,只好挑选几个来看,发觉另有 10 个参数之前没有注意到。
又过了两周,终于找到了惹起 bug 的真正参数组合,并跑通了一切测试。并增长 100 多个测试 case 确保掩盖他的修正。
颠末一个多月的代码 review,他的修正终于兼并了,开头处理下一个 bug……
厥后这个工程师感受说:“I don't work for Oracle anymore. Will never work for Oracle again!”
Oracle 12.2 有将近 2500 万行 C 代码,繁复体系的测试是一件困难、艰苦和困难的事变,而测试一个分布式数据库的情况就更繁复了。我们永久不晓得用户约莫写出什么样的 SQL,表布局和索引有几多种组合,别的还要思索集群在什么时分节点产生宕机,以及遭到网络发抖、磁盘功能退步等要素的影响——约莫性几乎是无穷的。
那么有没有一种办法能让步骤主动帮我们查 bug?
怎样做到「睡觉的时分让步骤主动查 bug」?
项目标思绪但是很简便,假如在每次跑 case 的时分能用统计学的办法对充足多次实行的代码途径举行分析,就可以找出疑似 bug 的代码,终极后果以代码染色的办法由前端可视化展现,就取得了如下图展现的后果:
「颜色越深,亮度越高」表现包含错误逻辑的约莫性越大。该办法不仅实用于数据库体系的测试,相反实用于其他任何繁复的体系。
眼前的原理
项目最初是遭到 VLDB 的一篇论文的启示 APOLLO: Automatic Detection and Diagnosis of Performance Regressions in Database Systems,该论文主要围绕怎样诊断引发数据库功能回退的代码,其中心头脑也相反实用于排查 bug。论文中提到的主动诊断体系由 SQLFuzz,SQLMin 和 SQLDebug 三个模块构成。
SQLFuzz:卖力随机天生 SQL,并使用二分查找定位到功能回退的前后两个版本,转达给 SQLMin 模块。
SQLMin:经过剪枝算法将 SQLFuzz 天生的 SQL 举行化简,得出可以复现该成绩的最小 SQL ,转达给 SQLDebug 模块。目标是变小不关的代码途径,低落杂音。
SQLDebug:对源码举行插桩,使其在实行 SQL 时可以输入代码的实行途径。然后对两个版本的代码途径举行分析,创建一个统计模子来定位成绩的地点。
终极体系主动天生测试报告,内容包含:
哪一次的代码 commit 引入了功能回退。
存在成绩的代码源文件。
具体的函数地点。
而实践上,思索到并发、循环、递归等带来的影响,代码实行途径分析会十分繁复。为了确保可以在 Hackathon 那么短的时间内展现出后果,我们又参考了另一篇论文 Visualization of Test Information to Assist Fault Localization,其中心头脑是经过统计代码块被准确和错误测试用例颠末次数,再基于分析算法来涂上不同的颜色,简便而实用。
但是借助这个思绪也可以使用到其他范畴,后方我们将掀开来先容。接下去我们先来看看 SQLDebug 是怎样完成的。
聊聊细 (gān) 节 (huò)
怎样主动产生测试 case?
由于是基于统计的诊断,我们必要先构建充足多的测试用例,这个历程固然最好也由步骤主动完成。内幕上,grammar-based 的测试在查验编译器准确性方面有相当长的汗青,DBMS 社区也接纳相似的办法来验证数据库的功效性。好比:微软的 SQL Server 团队开发的 RAGS 体系对数据库举行持续的主动化测试,另有社区比力出名的 SQLSmith 项目等等。本年 TiDB Hackathon 的另一个获奖项目 sql-spider 也是完成相似的目标。
这里我们暂且接纳 PingCAP 开源的随机测试框架 go-randgen 完成 SQL fuzzing,它必要用户写一些端正文件来协助天生随机的 SQL 测试用例。端正文件由一些产生式构成。randgen 每次从 query 开头随机游走一遍产生式,天生一条 SQL,产生一条像下图红线如此的途径。
我们将每个产生式天生准确与错误用例的比例作为该产生式的颜色值,绘制成一个页面,作为 SQLFuzz 的展现页面。经过该页面,可以比力容易地看出哪条产生式更容易产生错误的 SQL。
代码跟踪
为了跟踪每一条 SQL 在运转时的代码实行途径,一个紧张利用是对被测步骤举行插桩 (Dynamic Instrumentation)。VLDB 论文中提到一个二进制插桩东西 DynamoRIO,但是我们不确定用它来搞 Go 编译的二进制可否正常事情。换一个思绪,假如能在编译之前直接对源码举行插桩呢?
参考 go cover tool 的完成,我们写了一个专门的代码插桩东西 tidb-wrapper。它可以对随意版本的 TiDB 源码举行处理,天生 wrapped 代码。并且在步骤中注入一个 HTTP Server,假定某条 SQL 的择要是 df6bfbff(这里的择要指的是 SQL 语句的 32 位 MurmurHash 盘算后果的十六进制,主要目标是简化传输的数据),那么只需拜候 http://