数据库Mock方案设计
一、需求分析
1.背景
华为导流测试平台通过对线上流量回放到被测环境中,利用线上真实流量进行充分测试,保证业务系统稳定上线。但是业务在导流测试过程中现网数据库往往难以同步到测试环境,导致现网数据无法正常回放,测试价值降低。由此提出回放过程中对数据库进行mock,以保证回放过程正常进行。
2.方案分析
数据库Mock方案大致分为以下3种:
3.方案对比
方案 |
实现原理 |
难点 |
优点 |
缺点 |
当前研究进展 |
① |
数据库中间件接收的是字节码序列化数据,要实现Mock,就必须从Service发送给数据库的查询语句字节码中解析出select语句,并且再从数据库返回给Service的字节码中解析出结果数据再进行Mock数据的字节码替换。 |
已实现从Service发给数据库的字节码序列中解出了select语句,但是从数据库返回的结果字节码序列非常复杂,解析存在一定的困难,需要对mysql数据库底层序列化协议非常清楚才能实现解析算法,该方案在持续研究中。 |
数据库中间件是一个独立的TCP服务进程,只需要在一台机器上启动该进程,然后将要Mock服务的数据库连接指向该TCP进程的IP端口即可,不需要被测服务代码、服务器做任何改动。 |
功能可以实现,但方案最难最花时间,需要研究mysql协议。 |
该方案已通过Vertex实现了一个TCP服务,并解析出了select语句,mysql结果数据解析替换Mock数据需要在对mysql序列化协议熟悉之后才能进一步开发,持续研究中。 |
② |
该方案和LuBan,OneAPM等监控工具原理一样,采用基于javaagent的javassist无侵入字节码动态修改技术和class反射技术将mysql驱动的原始类字节码进行修改,实现在sql语句执行后并在ResultSet真实数据结果返回替换成Mock数据返回。 |
需要熟悉javassist字节码动态修改技术,java反射技术,以及熟悉mysql驱动的源码逻辑,要知道在源码中什么地方替换返回的ResultSet对象中的结果集数据。 |
该方案生成一个dbmockagent.jar,在启动要Mock的服务时只需增加-javaagent参数指向该jar包即可,不需要被Mock的服务修改代码。 该方案适配MySQL数据库,无需考虑使用何种数据库访问框架(MyBatis等)。 |
相对第一种方案对业务服务器部署有一定的要求,需将dbmockagent.jar部署在所有想要Mock服务的机器上,再修改启动命令指向该jar包。 |
1、已开发出第一版并上线用户生产环境使用: (1)mock数据预置redis。 (2)mockAgent改造,回放时从redis拉取数据。 2、后续计划: (1)开发mock server,用户配置mockAgent后,自动向mockServer注册;mockServer可以实现对mockAgent管理。 (2)并行回放,mockAgent V2.0开发,开发是否可以通过luban通信获取唯一id映射关系。 |
③ |
和第②种方案类似,不同的是,不是修改mysql驱动字节码,而是修改mybatis返回结果的字节码。 |
和第②种方案类似,需要了解mybatis的源码。 |
该方案和第②种方案一样生成一个dbmockagent.jar,在启动要Mock的服务时增加-javaagent参数指向该jar包即可,不需要被Mock的服务修改代码。 该方案只适配于MyBatis框架,和具体的数据库无关。
|
同第②种部署方案。 该方案只适配MyBatis框架,如果访问框架换成其它比如Hibernate就需要重新开发。 |
已实现 |
二、方案2:MySQL驱动字节码修改增强方案详细说明
1.方案设计
字节码增强:通过分析MySQL数据库驱动源码可知,获取数据库返回的ResultSet结果集的方法在com.mysql.jdbc.PreparedStatement类中的executeQuery方法,和执行完execute方法之后再调用getResultSet方法两种方式,所以我们需要对executeQuery和execute两个方法进行字节码修改增强。即在这两个方法执行完成之后,注入以下代码:获取Mock文件中的行列数据,转成MySQL需要的字节码对象,再设置到ResultSet实例化对象中替换原数据库的真实数据即可。
Mock数据设计和解析:一次请求链路中,比如有下面三次查询语句,并且存在相同sql执行多次并且返回结果不同的情况,那么我们在回放请求过程时,就得按顺序去依次取得每条sql执行的结果数据,而且能做到可对链路中其中一些sql结果进行mock,不mock的sql返回数据库的真实数据。
2.使用说明
1.在需要数据库Mock功能的第三方服务的启动命令中增加-javaagent参数指向该jar包,方式如下:
java -javaagent:D:/dbmockagent.jar -jar **.jar
2.参数设置:
(1)可设置dbmock.file参数指定Mock数据文件,不设置时默认为C:/dbmock.data。目前只实现了从文件中读取mock数据,可扩展从接口等其它地方获取Mock数据。
java -javaagent:D:/dbmockagent.jar -Ddbmock.file="D:/dbmock.data" –jar **.jar
(2)可设置dbmock.port参数指定重载Mock数据接口调用的端口,可不设置,默认为8888:
java -javaagent:D:/dbmockagent.jar -Ddbmock.file="D:/dbmock.data" -Ddbmock.port=8088 -jar **.jar
3.方案测试
3.1 使用MySQL驱动直连数据库
3.1.1 不使用插件
3.1.2 使用插件
再次运行上面的代码,执行结果如下,输出了DBMock相关的log信息,返回的数据正好为上面mock的数据,并且两次sql语句虽然相同,但是返回的结果数据是按照mock文件里的顺序返回的。
3.2 SpringBoot工程中通过MyBatis连接数据库
3.2.1 不使用插件
3.2.2 使用插件
3.3 Mock数据更新
- 点赞
- 收藏
- 关注作者
评论(0)