-
Notifications
You must be signed in to change notification settings - Fork 55
定制化参考 配置中心
本文介绍了信也科技内部如何基于Apollo配置中心定制化DAS,为有类似需求的公司提供实施参考。
DAS客户端应用程序启动时,需要获取逻辑数据库和物理数据库的信息来创建数据库连接池。缺省的基于das.xml和datasource.xml的获取方式在一般的场景下虽然足够使用,但存在诸多限制,例如如何区分不同环境的同名配置文件,如何防止数据库连接串泄露,如何动态修改,切换数据源等等。为解决上述问题,DAS客户端提供ClientConfigureLoader来允许用户提供自定义的配置获取方式。
信也科技内部的DAS客户端利用现有的Apollo环境提供了信也科技自身的ClientConfigureLoader实现。
Apollo是目前较流行的配置中心,其配置层次结构application,Namespace和properties。其中application下面可以存在多个Namespace(简称NS),每个Namespace以properties的格式存放多个配置项
在用户配置逻辑数据库,物理数据库和创建应用的时候,DAS Console会先写自身的数据库,再向Apollo同步数据,将配置信息写入对应的apollo application中。
- Apollo公共name space的名字要求为全局唯一,为了避免冲突,所有用到namespace的地方,我们都增加das相关的前缀。namespace都是公有。
- apollo application和name space的名字是单词直接用-连接。例如,das-application-groups
- name space由固定前缀+实际名字组成。例如,das-my-order
- Name space中的配置项的属性名是驼峰方式。例如,applicationList
实体类型 | Apollo Application Name | 说明 | Name Space前缀 |
---|---|---|---|
Dal Team | global-das-teams | 存放全部的Dal Team | das-tm- |
MySql物理数据库配置 | global-mysql-datasource | 存储物理数据库的链接属性 | das-my- |
SqlServer物理数据库配置 | global-sqlserver-datasource | 存储物理数据库的链接属性 | das-ms- |
分库分表策略 | das-sharding-strategies | 存放公共的分库分表策略配置 | das-ss- |
应用组配置 | das-application- | 存放所有应用组配置 | das-ag- |
数据连接池配置 | global-datasource-pool-config | 全局唯一数据连接池配置信息 | |
服务器查找表 | das-sever-lookup-table | 存放所有服务器对应的IP和Port | das-sv- |
服务器组配置 | das-server-groups | 存放所有服务器组 | das-sg- |
全局唯一数据连接池配置信息
Apollo Application:global-datasource-pool-config
Namespace = datasource-pool-config
testWhileIdle = truetestOnBorrow = true
testOnReturn = false
validationQuery = "SELECT 1"
validationInterval = 30000
timeBetweenEvictionRunsMillis = 30000
maxActive = 100
minIdle = 0
maxWait = 10000
initialSize = 1
removeAbandonedTimeout = 60
removeAbandoned = true
logAbandoned = true
minEvictableIdleTimeMillis = 30000
mysqlOption = rewriteBatchedStatements=true;allowMultiQueries=true;useUnicode=true;characterEncoding=UTF-8;
sqlServeOption = sendTimeAsDateTime=false;sendStringParametersAsUnicode=false;
物理数据库配置会按照数据库类型区分为MySql与SqlServer,每种类型的数据库会对应一个Apollo应用。
每个具体的物理数据库配置会对应于特定数据库应用下的Name Space,名字是物理数据库的名字,也即连接串名字,connectionName。
Apollo Application:global-mysql-datasource
Name space前缀:das-my-
Apollo Application:global-sqlserver-datasource
Name space前缀:das-ms-
例如连接串名字为order的数据库,配置为:
Namespace = das-my-order
userName = your name
password = your pass
host = 12.12.12.12
port = 3306
dbName = order_shard_0
driverClassName = com.mysql.jdbc.Driver
由于逻辑数据库属于DAL Team。因此需要在Apollo上创建DAL Team的应用
Apollo Application:global-das-teams
Name space前缀:das-tm-
每个DAL Team创建为该应用下的Namespace
该DAL Team下的所有逻辑数据库配置作为该Namespace的配置项。
例如:
Namespace = dal-test-team
databaseSets = MySqlSimple,MySqlSimpleDbShard,MySqlSimpleTableShard,MySqlSimpleDbTableShard,SqlSvrSimple,SqlSvrSimpleDbShard,SqlSvrSimpleTableShard,SqlSvrSimpleDbTableShard
MySqlSimple.provider = mysqlProvider
MySqlSimple.entries = dal_shard_0
MySqlSimple.dal_shard_0.type = Master
MySqlSimple.dal_shard_0.sharding =
MySqlSimple.dal_shard_0.datasource = dal_shard_0
MySqlSimpleDbShard.provider = mysqlProvider
MySqlSimpleDbShard.shardingStrategy = class=com.ppdai.das.shard.ModStrategy;columns=CountryID;mod=2;
MySqlSimpleDbShard.entries = dal_shard_0,dal_shard_1
MySqlSimpleDbShard.dal_shard_0.type = Master
MySqlSimpleDbShard.dal_shard_0.sharding = 0
MySqlSimpleDbShard.dal_shard_0.datasource = dal_shard_0
MySqlSimpleDbShard.dal_shard_1.type = Master
MySqlSimpleDbShard.dal_shard_1.sharding = 1
MySqlSimpleDbShard.dal_shard_1.datasource = dal_shard_1
MySqlSimpleTableShard.provider = mysqlProvider
MySqlSimpleTableShard.shardingStrategy = class=com.ppdai.das.shard.ModStrategy;tableColumns=CityID;tableMod=4;separator=_;shardedTables=person
MySqlSimpleTableShard.entries = dal_shard_0
MySqlSimpleTableShard.dal_shard_0.type = Master
MySqlSimpleTableShard.dal_shard_0.sharding =
MySqlSimpleTableShard.dal_shard_0.datasource = dal_shard_0
MySqlSimpleDbTableShard.provider = mysqlProvider
MySqlSimpleDbTableShard.shardingStrategy = class=com.ppdai.das.shard.ModStrategy;columns=CountryID;mod=2;tableColumns=CityID;tableMod=4;separator=_;shardedTables=person
MySqlSimpleDbTableShard.entries = dal_shard_0,dal_shard_1
MySqlSimpleDbTableShard.dal_shard_0.type = Master
MySqlSimpleDbTableShard.dal_shard_0.sharding = 0
MySqlSimpleDbTableShard.dal_shard_0.datasource = dal_shard_0
MySqlSimpleDbTableShard.dal_shard_1.type = Master
MySqlSimpleDbTableShard.dal_shard_1.sharding = 1
MySqlSimpleDbTableShard.dal_shard_1.datasource = dal_shard_1
SqlSvrSimple.provider = sqlProvider
SqlSvrSimple.entries = sql_shard_0
SqlSvrSimple.sql_shard_0.type = Master
SqlSvrSimple.sql_shard_0.sharding =
SqlSvrSimple.sql_shard_0.datasource = sql_shard_0
SqlSvrSimpleDbShard.provider = sqlProvider
SqlSvrSimpleDbShard.shardingStrategy = class=com.ppdai.das.shard.ModStrategy;columns=CountryID;mod=2;
SqlSvrSimpleDbShard.entries = sql_shard_0,sql_shard_1
SqlSvrSimpleDbShard.sql_shard_0.type = Master
SqlSvrSimpleDbShard.sql_shard_0.sharding = 0
SqlSvrSimpleDbShard.sql_shard_0.datasource = sql_shard_0
SqlSvrSimpleDbShard.sql_shard_1.type = Master
SqlSvrSimpleDbShard.sql_shard_1.sharding = 1
SqlSvrSimpleDbShard.sql_shard_1.datasource = sql_shard_1
SqlSvrSimpleTableShard.provider = sqlProvider
SqlSvrSimpleTableShard.shardingStrategy = class=com.ppdai.das.shard.ModStrategy;tableColumns=CityID;tableMod=4;separator=_;shardedTables=person
SqlSvrSimpleTableShard.entries = sql_shard_0
SqlSvrSimpleTableShard.sql_shard_0.type = Master
SqlSvrSimpleTableShard.sql_shard_0.sharding =
SqlSvrSimpleTableShard.sql_shard_0.datasource = sql_shard_0
SqlSvrSimpleDbTableShard.provider = sqlProvider
SqlSvrSimpleDbTableShard.shardingStrategy = class=com.ppdai.das.shard.ModStrategy;columns=CountryID;mod=2;tableColumns=CityID;tableMod=4;separator=_;shardedTables=person
SqlSvrSimpleDbTableShard.entries = sql_shard_0,sql_shard_1
SqlSvrSimpleDbTableShard.sql_shard_0.type = Master
SqlSvrSimpleDbTableShard.sql_shard_0.sharding = 0
SqlSvrSimpleDbTableShard.sql_shard_0.datasource = sql_shard_0
SqlSvrSimpleDbTableShard.sql_shard_1.type = Master
SqlSvrSimpleDbTableShard.sql_shard_1.sharding = 1
SqlSvrSimpleDbTableShard.sql_shard_1.datasource = sql_shard_1
应用使用到的逻辑数据库需要写入该应用对应的Apollo应用下das-config NS。格式:
- 所有该应用用到的逻辑数据库名字用','隔开写入databaseSets配置项
- 应用所属的DAL Team写入dalTeam配置项
- 应用所属应用组的ID写入appGroupId
例如:
Namespace = das-config
databaseSets = MySqlSimple,MySqlSimpleDbShard,MySqlSimpleTableShard,MySqlSimpleDbTableShard,SqlSvrSimple,SqlSvrSimpleDbShard,SqlSvrSimpleTableShard,SqlSvrSimpleDbTableShard
dalTeam = dal-test-team
appGroupId = dal-test-app-group
Apollo Application:das-application-groups
Name space前缀:das-ag-
每个应用组创建为该application下的NS
每个应用组创建为das-application-groups application下的NS,将组名用于NS的名字。例如AppGroup-1, AppGroup-User。
每个应用组包含以下内容:
- applicationList。属于同一AppGroup的所有App ID。之间用','分隔。一个配置项
- serverEnabled。是否是远程连接Das Server的方式
- serverGroupId。指定的server-group-id。一个配置项
例如:
Namespace = das-test-app-group
applicationList = 1000001,1000002
serverEnabled = true
serverGroupId = financial-svr-group
Apollo Application:das-server-groups
Name space前缀:das-sg-
每个服务器组创建为该application下的NS
每个服务器组创建为das-server-groups application下的NS,组名就是NS的名字。例如das-group-1, das-group-fin
每个服务器组包含以下内容:
- applicationGroupList。所有指向该服务器组的应用组的Name(name唯一)
- serverList。[ip]:[port]。','分隔。方便客户端确定可用server实例
例如:
Namespace = das-sg-financial-svr-group
applicationGroupList = das-test-app-group, financial-app-group
serverList= 123.0.0.1:9090,123.0.0.1:9092,123.0.0.1:9093
在apollo创建一个名叫das-sever-lookup-table的application
Name space前缀:das-sv-
用server的IP创建NS,包含:
- [port]:当前实例所属的server group id。方便das sever查找自身所在server group
- [port]_maxPoolSize
- [port]_keepAliveTime 其他基于port的配置信息,格式如上
注意
- 一个server ip下面可能会存在多个port
- 在添加服务器的时候,需要同时写das-server-groups对应IP下的serverList和sever-lookup-table
例如:
Namespace = das-sv-123.0,0.1
9090 = das-sg-financial-svr-group
9090_maxPoolSize = 200
9090_keepAliveTime = 60
9091 = das-sg-financial-svr-group
9091_maxPoolSize = 200
9091_keepAliveTime = 60
9092 = das-sg-financial-svr-group
9092_maxPoolSize = 200
9092_keepAliveTime = 60
Apollo 应用:das-sharding-strategies
名字前缀:das-ss-
策略按前缀加名字保存为公共的name space。
例如策略名字为OrderRange,则实际name space为das-ss-OrderRange
- className:静态加载的策略类名
- dynamicSource:动态加载的Java代码。
- 两者不会并存 Namespace = das-ss-OrderRange Collapse source
isDynamic = true/false
className = com.ppdai.das.shard.AnotherModStrategy
或者
className=com.ppdai.das.shard.MyStrategy
dynamicSource = java code....
在逻辑数据库配置中,按照策略类型存储为:
- 如果存储的是公共策略则,则按照strategyName=策略名的形式存储
- 原来私有策略,则按照class=策略实现类的方式存储。和一期目前做法保保持一致
- 策略的其他相关属性还是按照key/value的形式存储。
策略样例:
私有策略:
MySqlSimpleDbShard.shardingStrategy = class=com.ppdai.das.shard.ModStrategy;columns=CountryID;mod=2;
公共策略:
MySqlSimpleDbShard.shardingStrategy = strategyName=das-ss-OrderRange;columns=CountryID;lowField=startDate;hightField=endDate;
客户端的配置加载程序在读取逻辑数据库shardingStrategy的时候:
- 如果包含class,则为私有策略,按类名实例化策略对象
- 如果包含strategyName,则为公共策略,需要:
- 按名字去das-sharding-strategies查找对应的name space
- 如果包含className属性,则判断为静态策略, 按类名实例化策略对象
- 如果包含dynamicSource,则判断为动态策略,按照调研中的办法加载
- 其他属性按照现在的方式作为初始化参数调用策略的初始化接口
对于通用的动态策略,建议在充分验证后,用Java类实现并放在相应的公共模块
- 如果是非信也科技特定策略,建议放在das-client里 package com.ppdai.das.strategy下面
- 如果是信也科技特定策略,建议放在ppdai-das-common里 package com.ppdai.das.shard下面