1.背景
随着互联网的快速发展,传统的单体系统架构已不能满足海量用户的需求。系统的架构大致经历了:单体应用架构--->垂直应用架构--->分布式架构--->SOA架构--->微服务架构的演变。随着架构的演变以及日益增大的流量规模,底层的数据库/表的数量也越来越多,越来越细化。
实际的场景中,一次业务场景往往会涉及到多个数据库/表的变动。以我所在的支付业务的结算场景中最简单流程(未考虑账户创建、权限、商户借款还款等场景)为例:
一共涉及到2个数据库11个表16种单据(仅考虑支付内部的单据流转)。在测试过程中,需要查出各种单据,并对字段进行核验。由于单据分布在不同的库/表,就算提前准备好sql,也需要对单据的关联关系相当熟悉才能快速的查出单据进行核对。整个测试过程中数据库单据核对时间占整体测试时间的大头,数据库查询又占整个单据核对时间的大头,要对测试提效,首先要解决这个问题。2.设计
思路:
通过一个业务单据或者traceId能将整个业务场景所涉及到的单据在同一个页面进行展示
数据表可能是在不同的数据库集群的,因此无法通过数据库原生能力解决该问题,因此需要引入一个"中间商"对业务过程中的数据库操作进行处理,然后进行集中展示。
获取业务过程中数据库变动:
有两个方案
1、通过数据库的binlog进行获取。优点:能够获取到最终的数据,不需要复杂处理。缺点:无法关联业务,只能获取到某个时间段的数据。需要DBA、架构支持
2、通过代码增强,在业务层内获取。优点:能够赋予数据业务场景。不仅仅能够处理MySQL类型数据库。缺点:不是数据库最终数据,处理起来比较麻烦。
同一个时间段内,会有多个需求同时进行测试,某个时间段内会有很多干扰的数据,因此binlog并不太明满足我们的需求,因此选了方案2。
3.技术实现
3.1 代码增强
转转在测试环境中所有集群都接入了jvm-sandbox,因为直接使用jvm-sandbox的能力进行增强即可。
因为需要知道SQL的执行结果,因此需要监听RETURN和THROWS事件(不关心异常,监听Return即可)
3.2 增强点
jdbc执行流程:装载驱动 -> 建立connection -> 创建statement(prepareStatement) -> 执行SQL语句(executeInternal)我们需要获取到已经准备好的SQL语句,因此需要在executeInternal处进行增强jdbc有两个版本,因为不确定服务使用的是哪个版本,为了减少配置,都需要进行增强。
在module内通过反射调用PreparedStatement#asSql()即可获取SQL语句
3.3 业务关联
转转接入了transmittable-thread-local,在流量起点会生成一个traceId在服务间传递,因此只需要将traceId与sql绑定即可。
3.4 SQL处理
我们只需要关注变动的数据,因此我们只需要关心INSERT、UPDATE、DELETE语句。
通过对这三种SQL的解析,最终得到以下数据:
3.5 事务处理
如果在执行SQL的时候开启了事务,我们从RETURN事件中获取到的并不是最终提交的数据,因此我们需要感知到事务的提交和回滚。
MYSQL 事务处理主要有两种方法:
1、用 BEGIN, ROLLBACK, COMMIT来实现
- BEGIN 开始一个事务
- ROLLBACK 事务回滚
- COMMIT 事务确认
2、直接用 SET 来改变 MySQL 的自动提交模式:
- SET AUTOCOMMIT=0 禁止自动提交
- SET AUTOCOMMIT=1 开启自动提交
通过对多个数据库框架源码的阅读,大部分采用的都是第二种:开启事务时将AUTOCOMMIT=0,事务结束之后主动调用commit并恢复AUTOCOMMIT=1。
因此我们可以对下面三个地方进行增强:
setAutoCommit(false),增加一个ThreadLocal用来存储SQL。
commit或setAutoCommit(true),标记事务已提交,并发送数据
rollback,标记事务已回滚,并发送数据。
3.6 前端展示
最终呈现示例:
4.未来优化
1、兼容更多的数据库:redis、es等
2、提供类似Charles、fiddler类似,实时抓取数据库变更页面
3、根据流量入口进行数据归类
作者:陈俊华
转转研发中心及业界小伙伴们的技术学习交流平台,定期分享一线的实战经验及业界前沿的技术话题。
关注公众号「转转技术」(综合性)、「大转转FE」(专注于FE)、「转转QA」(专注于测试),更多干货实践,欢迎交流分享~