关于java:使用插桩技术解决慢查询测试问题

4次阅读

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

原文由 zlulu 发表于 TesterHome 社区,原文链接

缘起

前段时间,我负责测试的零碎在生产环境运行呈现问题。该零碎对于响应工夫要求较高,问题产生的时候并发很高,呈现大量申请超时,超时申请比例随工夫推延越来越高,最初简直全副申请都失败。滚动重启了所有过程后,很快又呈现超时状况。

后通过排查,发现是新版本实现某个性能时批改了一个数据库查问语句,批改后该查问语句的查问条件未应用到索引字段,而所查问的表生产环境中体量微小,因而这个查问操作耗时从毫秒级变成了秒级,也就是造成了所谓的慢查问,再加上大量并发,喜剧就产生了。

事件产生后,咱们测试团队进行了反思,这么重大的问题为何测试环境没有发现?总结了两点起因,一是,测试环境进行功能测试时并发量不高,即便单个申请变慢也不会产生超时景象;二是,测试环境数据库表的数据量较生产环境小很多,所以单个查问操作比生产快很多,这样压力测试中申请也极少超时。

求索

综上所述,想要在测试过程中人为辨认一个慢查问很难,为了杜绝这类问题再次发生,在后续版本测试中咱们做了一些尝试。

因为咱们外部原本就有应用代码扫描的工具,每个版本都会通过扫描来辨认一些问题,所以咱们首先想到了通过动态扫描原代码,捞出所有的数据库查问语句而后进行剖析。实际操作后发现,咱们零碎在数据库操作上大量应用框架,不同模块应用的框架还不同,捞出的数据库语句千奇百怪,且蕴含代码元素,并不是能间接执行的语句,对于大型零碎而言,人工去剖析这些语句工作量太大,这种办法并不可行。

而后咱们想到,能够从数据库侧来解决这个问题,通过开启 Mysql 的慢查问日志开关,将功能测试过程中大于 long_query_time 配置工夫的数据库查问操作都记录下来,再一一剖析是否存在慢查问问题。过程中咱们的确抓到了很多执行较慢的查问语句,但通过剖析后发现,这些语句绝大部分都是测试人员人工查询数据库的操作,更遗憾的是,因为测试数据数量级较少,之前产生生产问题的查问语句在测试环境的执行工夫并没有超过 long_query_time,由此并不能被辨认进去。由此可见,这种办法误报和漏报概率很大,也不可行。

变革

现有工具无奈满足咱们辨认慢查问语句的需要,于是咱们决定本人做了一套工具。通过大量的剖析和试验,咱们失去了一个高效、准确性、且通用性极好的解决方案:

通过剖析,辨认慢查问语句须要解决两个问题:一是,如何取得零碎执行是查问语句;二是,如何剖析某个查问是否是慢查问。

解决第一个问题,咱们想到了应用插桩技术。

对于一个查问操作,不论下层利用代码如何编写、或应用何种数据库框架,这个操作最终会与指标数据库交互,而交互的时候它肯定必须是一个规范的 SQL 语句。基于这一点,咱们对这个利用进行了全面的剖析,咱们的零碎部署在 Jboss 上,通过层层分析,咱们找到了这个理论执行查问操作数据库交互的办法,位于 Jboss 的 JCA 包中,共用到以下两处:

① org.jboss.jca.adapters.jdbc.WrappedPreparedStatement.executeQuery()
② org.jboss.jca.adapters.jdbc.WrappedStatement.executeQuery()

通过大量的试验,咱们确定咱们这个零碎所有数据库查问操作必定会调用①②中的一个来实现(实现逻辑不同其余零碎可能调用的是 JCA 的其余办法)。再通过在①②设置断点 bebug 咱们发现,在①②办法外部 SQL 语句是齐全可见的。

接下来咱们利用的 Java Instrument Api 及其衍生的开源组件,搭建了一个 agent 程序。启动 agent,agent 在利用零碎程序运行时动静的往这两个中央别离插个桩,桩的内容非常简单:将以后办法体内存中正在执行的 SQL 语句打印到某个固定地位(假如咱们把 SQL 语句输入到日志文件 A 中)。绝对于在①②办法体外部多写一句 print,仅仅只做一个打印的操作,不会对业务逻辑产生任何烦扰。

于是咱们就实现了这样一个事件:当利用零碎要进行数据库查问操作时,它会调用①②中的一个来执行这个查问 SQL,①②被调用时,会将正在执行的 SQL 语句输入到日志文件 A 中。这样,每一个查问操作,都会将理论的查问语句记录在日志文件 A 中,也就实现了查问语句的收集啦。

通过插桩咱们取得了大量的 SQL 语句,接下来解决第二个问题,如何判断一个查问语句是否为慢查问。

因为测试和生产数据数量级的差别,用执行工夫来判断显然不迷信。同时,咱们一共取得了几万条 SQL 语句,间接进行人工剖析显然不可行。

咱们想到了 Mysql 提供的 explain 命令来扩大 SQL 语句,通过 Mysql 的执行打算来迷信判断执行的快慢。每条可执行 SQL 语句都能够间接用 explain 命令取得

执行打算中的每一个列标签都能够作为匹配环节的关注项,咱们称其为指标项,咱们用到了与查问效率相干的指标项中最重要的两个:
1、key:示意这个 SQL 语句执行时会应用的索引的键;
2、type:拜访形式,示意执行 SQL 语句是在数据库表中找到所需行的形式,可能的值如下:

system > const > eq_ref > ref > fulltext > ref_or_null > index_merge > unique_subquery > index_subquery > range > index > ALL

从 system 到 ALL,性能从好到差,一般来说应保障至多达到 range 级别。
第一步,咱们将日志文件 A 中所有的 SQL 语句逐条转换成执行打算;
第二步,依据零碎理论需要,建设一套规定,对执行打算进行筛选,找出可能是慢查问的语句;
咱们零碎匹配慢查问的规定是:

key in [NULL]
OR
type in [range,index,ALL]
OR
Rows >= 1000

这个规定示意:如果一个 SQL 语句它未通过索引、或者拜访形式为 range、index、ALL 之一、或者预估扫描行数大于等于 1000 条,那么它可能是一个慢查问。
第三步,对可能是慢查问的语句进行人工剖析。
通过第二步的筛选,咱们将须要剖析的 SQL 语句数量从几十万条降到了十几条,后续再人工逐个剖析。
如此,咱们实现了零碎的慢查问测试工作。之前导致生产问题的 SQL 语句完满命中,其余疑似慢查问语句联合查问频率、生产数据表数量级等因素,人工断定为非慢。

破浪

起初,通过实现 agent 插桩地位、慢查问筛选规定的可配置,咱们将这套解决方案优化为一个通用框架,并推广到部门的多个零碎应用,并发现了若干慢查问隐患。

对于这套基于插桩的慢查问测试方法,总结劣势如下:
1、SQL 语句笼罩全面,且准确性较高。只有插桩点剖析筹备,能够保障捕捉程序运行时执行的所有 SQL 语句(因为理论执行过的 SQL 语句能力被捕捉,因而依赖于功能测试的完整性),而以执行打算为根底的剖析更具备科学性,且不受数据量大小的影响,准确性更高。
2、有极好的通用性。插桩地位可配置,不同零碎只需批改配置既能应用。桩点个别为底层实现与数据库交互的数据库驱动包某一些特定的类和办法,与具体应用程序实现形式不相干,也就是说,无论程序性能是什么、无论应用了什么数据库框架,只有配置正确的数据库交互类及其办法,都能适配。
3、非侵入、可插拔,被测利用无感知。agent 启动,则动静插桩,agent 进行,则桩点隐没。无需对被测利用源码做任何批改,检测过程对性能无影响,可在功能测试中悄无声息的实现。


播种前沿测试开发技术 · 学习先进品质治理方法 · 结识测试大咖和行业精英 ↓↓↓↓

正文完
 0