分享一个思路,使用插桩技术解决慢查询测试问题

前段时间,我负责测试的系统在生产环境运行出现问题。该系统对于响应时间要求较高,问题发生的时候并发很高,出现大量请求超时,超时请求比例随时间推迟越来越高,最后几乎全部请求都失败。滚动重启了所有进程后,很快又出现超时情况。

后经过排查,发现是新版本实现某个功能时修改了一个数据库查询语句,修改后该查询语句的查询条件未使用到索引字段,而所查询的表生产环境中体量巨大,因此这个查询操作耗时从毫秒级变成了秒级,也就是形成了所谓的慢查询,再加上大量并发,悲剧就发生了。

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

求索

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

因为我们内部本来就有使用代码扫描的工具,每个版本都会通过扫描来识别一些问题,所以我们首先想到了通过静态扫描原代码,捞出所有的数据库查询语句然后进行分析。实际操作后发现,我们系统在数据库操作上大量使用框架,不同模块使用的框架还不同,捞出的数据库语句千奇百怪,且包含代码元素,并不是能直接执行的语句,对于大型系统而言,人工去分析这些语句工作量太大,这种方法并不可行。

然后我们想到,可以从数据库侧来解决这个问题,通过开启 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]ORtype in [range,index,ALL]ORRows >= 1000

这个规则表示:如果一个 SQL 语句它未经过索引、或者访问方式为 range、index、ALL 之一、或者预估扫描行数大于等于 1000 条,那么它可能是一个慢查询。

第三步,对可能是慢查询的语句进行人工分析。

通过第二步的筛选,我们将需要分析的 SQL 语句数量从几十万条降到了十几条,后续再人工逐一分析。

如此,我们完成了系统的慢查询测试工作。之前导致生产问题的 SQL 语句完美命中,其他疑似慢查询语句结合查询频率、生产数据表数量级等因素,人工判定为非慢。

破浪

后来,通过实现 agent 插桩位置、慢查询筛选规则的可配置,我们将这套解决方案优化为一个通用框架,并推广到部门的多个系统使用,并发现了若干慢查询隐患。

对于这套基于插桩的慢查询测试方法,总结优势如下

1.SQL 语句覆盖全面,且准确性较高。只有插桩点分析准备,可以保证捕获程序运行时执行的所有 SQL 语句(由于实际执行过的 SQL 语句才能被捕获,因此依赖于功能测试的完整性),而以执行计划为基础的分析更具有科学性,且不受数据量大小的影响,准确性更高。

2.有极好的通用性。插桩位置可配置,不同系统只需修改配置既能使用。桩点一般为底层实现与数据库交互的数据库驱动包某一些特定的类和方法,与具体应用程序实现方式不相关,也就是说,无论程序功能是什么、无论使用了什么数据库框架,只要配置正确的数据库交互类及其方法,都能适配。

3.非侵入、可插拔,被测应用无感知。agent 启动,则动态插桩,agent 停止,则桩点消失。无需对被测应用源码做任何修改,检测过程对功能无影响,可在功能测试中悄无声息的完成。


一些实践

有TesterHome社区的同学们看到这一思路后的一些想法和实践:

1.感觉真的好奇妙啊,我们对这个问题的解决思路竟然如此的相似,两年前我做的一个开源项目就是用这个思路,一直没推广,换公司后用 go 比较多了,已经好久没更新了。 https://github.com/bugVanisher/no-slow-query

2.mybatis 插件就够了.天然亲和. 一个 jar 包.全公司引用. Java agent 成本相对还是高一点点。

这是我搞的一个防止 where 标签失效的插件.其他同理https://github.com/Forest10/forest10-tool/blob/master/src/main/java/com/forest10/mybatis/interceptor/BatchModifyForbiddenInterceptor.java

3.根据楼主(作者)的思路实现的,已开源

 https://github.com/tangyiming/sql-detect

内含插桩插件,平台前后端,demo 应用,数据库 ddl 与数据资源。

总结:

感谢每一个认真阅读我文章的人!!!

作为一位过来人也是希望大家少走一些弯路,如果你不想再体验一次学习时找不到资料,没人解答问题,坚持几天便放弃的感受的话,在这里我给大家分享一些自动化测试的学习资源,希望能给你前进的路上带来帮助。

软件测试面试文档

我们学习必然是为了找到高薪的工作,下面这些面试题是来自阿里、腾讯、字节等一线互联网大厂最新的面试资料,并且有字节大佬给出了权威的解答,刷完这一套面试资料相信大家都能找到满意的工作。

 

          视频文档获取方式:
这份文档和视频资料,对于想从事【软件测试】的朋友来说应该是最全面最完整的备战仓库,这个仓库也陪伴我走过了最艰难的路程,希望也能帮助到你!以上均可以分享,点下方小卡片即可自行领取。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/639458.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

Leetcode刷题2

文章目录 前言寻找两个正序数组的中位数1️⃣ 双指针快速排序2️⃣ 第k小数解法 Z 字形变换1️⃣ 个人解法2️⃣巧妙解法13️⃣巧妙解法2 字符串转换整数 (atoi)1️⃣ 常规方法2️⃣ 作弊方法😫 整数转罗马数字1️⃣ 常规方法:按照给定规则写出判断条件即…

ABB机器人手动模式切换自动模式时,速度自动更改为100%的解决办法

ABB机器人手动模式切换自动模式时,速度自动更改为100%的解决办法 如下图所示,手动切换到自动模式时,示教器上提示:速度将改为100%,但是我们正常使用时的速度可能不是100%,所以还需要手动去更改速度,不太方便。。。 解决办法可参考以下内容: 如下图所示,打开菜单—控制…

防火墙技术基础篇:解析防火墙的网络隔离机制

防火墙技术基础篇:解析防火墙的网络隔离机制 网络安全在现代社会中扮演着重要的角色,保护网络系统、用户和数据免受未经授权的访问、破坏和窃取。个人、企业和国家都需要加强网络安全意识,采取有效措施保护自身的网络安全。随着网络攻击手段…

Golang实现递归复制文件夹

代码 package zdpgo_fileimport ("errors""os""path/filepath""strings" )// CopyDir 复制文件夹 // param srcPath 源文件夹 // param desPath 目标文件夹 // return error 错误信息 func CopyDir(srcPath, desPath string) error {…

张量 t-product 积(matlab代码)

参考文献:Tensor Robust Principal Component Analysis with a New Tensor Nuclear Norm 首先是文章2.3节中 t-product 的定义: 块循环矩阵: 参考知乎博主的例子及代码:(t-product与t-QR分解,另一篇傅里叶对…

200smart【编程入门】

说明 编程时,遇到困难就按【F1】 【I】输入 200smart 上限 i0.0~i31.7 255bit【255个输入点】 i0.0~i31.7 八进制 【布尔 bool 】 ib0~ib127 【单字节】 8bit iw0~iw127 …

六零导航页 file.php 任意文件上传漏洞复现(CVE-2024-34982)

0x01 产品简介 LyLme Spage(六零导航页)是中国六零(LyLme)开源的一个导航页面。致力于简洁高效无广告的上网导航和搜索入口,支持后台添加链接、自定义搜索引擎,沉淀最具价值链接,全站无商业推广,简约而不简单。 0x02 漏洞概述 六零导航页 file.php接口处任意文件上传…

Java面试八股之++操作符是线程安全的吗

操作符是线程安全的吗 操作符本身在Java中并不是线程安全的。这个操作实际上包含三个步骤:读取变量的值、将值加1、然后将新值写回内存。在多线程环境下,如果多个线程同时对同一个变量执行操作,就可能出现竞态条件(race conditio…

TransFormer学习之基础知识:STN、SENet、CBAM、Self-Attention

1.空间注意力机制STN 参考链接:STN(Spatial Transformer Networks) 参考链接:通俗易懂的Spatial Transformer Networks(STN) 核心动机: 在空间中捕获重要区域特征(如图像中的数字),将核心区域进行放大居中,使得结果更…

K8S认证|CKA题库+答案| 7. 调度 pod 到指定节点

7、调度 pod 到指定节点 您必须在以下Clusterd/Node上完成此考题: Cluster Master node Worker node hk8s master …

GS5812G 21V、2A同步降压DC/DC转换器芯片IC

一般描述 该GS5812G是一个同步降压DC/DC转换器与快速恒定的时间(FCOT)模式控制。该器件提供4. 5V至21V的输入电压范围和2A连续负载电流能力。它是恒定时间脉宽调制(PWM)控制器,支持 FCOT模式控制。工作频率取决于输入和输出电压条件。 该GS5812G故障…

桌面藏线大法

1有线改无线: 蓝牙鼠标 蓝牙键盘 蓝牙耳机 2将排插贴到桌子底下 购物软件上搜 3断舍离 不要的电子产品统统扔掉 4 洞洞板和挂钩 这个不用介绍了

uniapp中使用mockjs模拟接口测试总结(swiper轮播图示例)

完整总结下在uni-app中如何使用Mock.js模拟接口测试,这在后台接口未就绪的情况下非常有用。同时也给出个首页swiper轮播图的mock接口使用。网上的文章都不太完整,这里总结下完整的使用示例,同时也支持h5和小程序平台,分享给需要的…

个人感觉对Material设计有用的几个网址

(一) Modular and customizable Material Design UI components for Android GIthub: material-components-android (二) 学习Material设计 Material Design (三) 用于创建Material主题,支持导出多种格式 material-theme-builder

谷歌蜘蛛池是什么?

或称为谷歌爬虫池,是一项专门针对谷歌搜索引擎优化(SEO)的先进技术,这种技术的主要目的是通过建立庞大的网站群体和复杂的链接结构来吸引和维持谷歌的爬虫程序的注意力,其核心是通过这种结构优化,增强特定网…

ESP32 实现获取天气情况

按照小安派AiPi-Eyes天气站思路,在ESP32 S3上实现获取天气情况。 一、在ESP32 S3实现 1、main.c 建立2个TASK void app_main(void) {//lvgl初始化xTaskCreate(guiTask, "guiTask", 1024 * 6, NULL, 5, NULL);//wifi初始化、socket、json处理taskcustom_…

Xcode代码格式化SwiftFormat安装使用,以及不生效问题

官方仓库地址:GitHub - nicklockwood/SwiftFormat: A command-line tool and Xcode Extension for formatting Swift code 安装SwiftFormat 有两种安装方式,两种方式都可以,二选一即可: 第一种使用brew,如果已经使用…

AWPortrait1.4更新,人物的生成更加趋近真实感,将SD1.5人像的真实感提升到了一个新的高度

AWPortrait1.4更新,人物的生成更加趋近真实感,将SD1.5人像的真实感提升到了一个新的高度 经过5个月,AWPortrait终于迎来了1.4。 本次更新基于1.3训练,使得人物的生成更加趋近真实感,将SD1.5人像的真实感提升到了一个新…

《二》MP3在线搜索所歌曲的实现

上一期我们大致实现了布局等操作 那么这一期我们来实现如何去搜索歌曲: 首先呢,我们是设计多媒体,要包含多媒体类头文件,还要能在线搜索,那就要包含网络上的头文件,还要实现打开文件操作,处理…

618知识狂欢,挑本好书,点亮智慧生活!

618精选编程书单:提升你的代码力 一年一度的618又到啦!今年的618就不要乱买啦,衣服买多了会被淘汰,电子产品买多了会过时,零食买多了会增肥,最后怎么看都不划算。可是如果你购买知识,坚持阅读&a…