线上压测配套改造影子库路由方案设计
提供一个基础框架,支持mysql、mongo的影子库功能;配合线上压测影子库功能的推广
压测请求标识
压测请求标识,需要设置在WafContext中,key
为"PRESSURE_PRODUCT",值为boolean类型
组件方需要进行改造,根据当前的租户,设置压测标识到WafContext
waf的分库框架,支持从WafContext读取压测标识,进行相应的数据库路由
Mysql支持影子库
目前绝大部分java服务都是使用spring bean容器中DataSource对象,来进行mysql的操作的。所以我们可以对DataSource对象进行包装,将包装过的DataSource设置到spring bean容器。
//DataSource包装类
public class DataSourceWrapper implements DataSource {
//内部持有正式库、影子库2个DataSource
private DataSource normal;
private DataSource shadow;
public WafShadingDbWrapper(DataSource normal, DataSource shadow){
this.shadow = shadow;
}
protected DataSource getCurrentDb(){
//根据线程上下文中,是否压测请求的标识,来返回正式库或者影子库
if(WafShardingContext.isPressure()){
return shadow;
}else{
return normal;
}
}
//实现DataSource中定义的接口,所有方法都要支持自动切换正式库、影子库
@Override
public Connection getConnection()throws SQLException {
return getCurrentDb().getConnection();
}
......
}
如何对spring bean容器中DataSource对象进行包装
实现spring提供的BeanPostProcessor接口,可以拦截所有的bean创建过程,我们可以在DataSource bean初始化完、返回前,对DataSource对下进行包装,返回DataSourceWrapper对象。
如何构造影子库DataSource对象
目前大部分服务都是采用spring boot data的jdbc配置,我们可以基于该配置方式进行扩展:
spring:
#原有spring boot data方式的连接池配置
datasource:
driver-class-name: sql.fabric.jdbc.FabricMySQLDriver
url: xxxxx
username: xxxx
password: xxxxx
#我们扩展后的影子库的连接池配置
datasource-shadow:
driver-class-name: sql.fabric.jdbc.FabricMySQLDriver
url: xxxxx
username: xxxx
password: xxxxx
这样我们可以参考spring boot data的DataSource初始化代码,进行影子库的DataSource对象构造
未使用spring boot data的jdbc配置的工程
这些工程一般是使用自定义的properties配置,然后手动构造DataSource对象,存放到spring的bean容器中;这时候我们其实也会自动拦截DataSource bean的构造,进行包装;但是如何创建影子库的DataSource对象就没办法由框架自动来执行了,所以框架需要提供一个构造影子库的回调接口,由组件工程自己实现该接口返回影子库的DataSource对象
如何适配已使用shardingjdbc的工程
目前有一些组件工程已经在使用shardingjdbc进行分库分表配置。我们也需要针对这种场景,支持影子库路由。方案如下:
shardingjdbc本身已经对spring bean容器中的DataSource对象进行了包装,内部持有多个DataSource来实现分库的功能;我们同样可以在
shardingjdbc的DataSource对象上,再做一层包装,包装后的
DataSourceWrapper内部持有正式库、影子库2个shardingjdbc
DataSource对象:
sharding:
#原有sharding-jdbc的连接池配置
jdbc:
datasource:
names: db_0,db_1
db_0:
type: at.jdbc.pool.DataSource
driver-class-name: sql.fabric.jdbc.FabricMySQLDriver
url: xxxx
username: xxxx
password: xxxx
db_1:
type: at.jdbc.pool.DataSource
driver-class-name: sql.fabric.jdbc.FabricMySQLDriver
url: xxxx
username: xxxx
password: xxxx
config:
sharding:
tables:
student:
actual-data-nodes: db_$->{0..1}.student_$->{0..1}
database-strategy.standard.sharding-column: class_id
database-strategy.standard.precise-algorithm-class-name: xxx
table-strategy.standard.sharding-column: class_id
table-strategy.standard.precise-algorithm-class-name: xxx
#我们扩展后的影子库的连接池配置,其中datasource的name、数量需要保持和正式库一致
#config.shading无需再配置,会复用正式库的配置
jdbc-shadow:
datasource:
names: db_0,db_1
db_0:
type: at.jdbc.pool.DataSource
driver-class-name: sql.fabric.jdbc.FabricMySQLDriver
url: xxxx
username: xxxx
password: xxxx
db_1:
type: at.jdbc.pool.DataSource
driver-class-name: sql.fabric.jdbc.FabricMySQLDriver
url: xxxx
username: xxxx
password: xxxx
这样我们可以参考shardingjdbc的DataSource初始化代码,进行影子库的DataSource对象构造
Mongo支持影子库
目前绝大部分java服务都是使用spring bean容器中MongoTemplate对象,来进行mongo的操作的。MongoTemplate的构造过程一般是这样:先构造MongoClient对象,然后再使用MongoClient对象构造
MongoDbFactory对象,然后再使用MongoDbFactory对象构造
MongoTemplate对象。
MongoClient、MongoDbFactory、MongoTemplate对象中,其中包装任意一个都是可以实现数据源切换的。但是包装MongoDbFactory最为方便,因为MongoDbFactory本身就是一个接口类,而且接口方法的数量很少。
所以我们可以针对spring bean容器中的MongoDbFactory对象进行包装。具体实现和mysql的方案基本一致。
如何构造影子库MongoDbFactory对象
目前大部分服务都是采用spring boot data的mongo配置,我们可以基于该配置方式进行扩展:
spring:
data:
#原有spring boot data方式的mongo连接配置
mongodb:
uri: mongodb://xxxxx
#我们扩展后的mongo影子库的连接配置
mongodb-shadow:
uri: mongodb://xxxxxxxxx
未使用spring boot data的mongo配置的工程
这些工程一般是使用自定义的properties配置,然后手动构造MongoTemplate对象,存放到spring的bean容器中;针对这个场景,我们需要做几个限制:组件方需要将MongoDbFactory声明成spring的bean
组件方在创建MongoTemplate时,需要使用的是
MongoTemplate(MongoDbFactory mongoDbFactory)或者
MongoTemplate(MongoDbFactory mongoDbFactory, MongoConverter
springboot其实就是springmongoConverter)构造函数,并且mongoDbFactory参数是从spring bean 中获取的
最后框架需要提供一个构造影子库的回调接口,由组件工程自己实现该接口返回影子库的MongoDbFact
ory对象
补充
提供开关关闭自动包装功能
目前框架提供了自动包装DataSource、MongoDbFactory对象的功能,但是需要提供开关可以关闭
主要是考虑有些组件代码,并没有将DataSource、MongoDbFactory对象存放到spring bean容器中;这样这些组件可以在创建DataSource、MongoDbFactory 实例时,手动编码使用waf提供的包装类进行包装。
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。
发表评论