针对选择哪一个版本的shardingsphere刚开始有点纠结,不同版本的配置及支持范围有很大的不同,但最终统合考虑之后选择了5.0的版本,相对于目前来说这个版本支持的范围还是不错的,基本能满足当前业务的所有需求。
当前分库的整体需求是,将这150W的数据根据一定的规则存入不同的数据源中,每个数据源相对隔离:
但是按照shardingsphere的分库逻辑来说,不能采用传统的路由规则,例如根据组织id、人员id类进行分库,而需要根据业务采用自定义的路由hint模式。
具体hint的路由逻辑为:
public class PartyUserDbHintShardingAlgorithm implements HintShardingAlgorithm<String> { @SneakyThrows @Override public Collection<String> doSharding(Collection<String> collection, HintShardingValue<String> hintShardingValue) { log.info("*********进入分库策略*********"); List<String> dataBaseList = new ArrayList<>(); for (String value : hintShardingValue.getValues()) { if (collection.contains(value)) { dataBaseList.add(value); } } if (CollectionUtils.isEmpty(dataBaseList)) { log.error("查询分库结果失败,collection={},hintShardingValues={}", JSON.toJSONString(collection), JSON.toJSONString(hintShardingValue.getValues())); throw new Exception("执行操作失败,请联系管理员!"); } log.info("分库结果:{}", dataBaseList); return dataBaseList; } @Override public void init() { } @Override public String getType() { return "hint-db-party-user"; } @Override public Properties getProps() { return null; } @Override public void setProps(Properties props) { } // 这里getType为配置文件中的路由名称,具体可以参照下面的yml配置
使用shardingsphere组件嵌入到项目中,默认情况下shardingsphere会托管所有的数据源,即使是不需要分库分表的其他业务表的增删改查,也会被它所托管,理论情况下没什么问题,但是在集成的过程中发现,由于不参与分库分表的增删改查sql语句,很多采用了复杂的写法(例如多层的嵌套子查询,多聚合函数同时使用等),但shardingsphere在托管的情况下进行sql解析的时候会出现问题,所以去查询资料详细了解了一下,这个组件存在一定的sql不兼容情况,具体可查看链接:
http://www.gitweixin.com/?p=717
这时候项目中又引进了另外一个组件dynamic,组中采用了dynamic+shardingsphere的方式来实现本次分库的需求,以下是具体的yml文件配置:
#基础数据源 datasource: dynamic: datasource: master: type: com.alibaba.druid.pool.DruidDataSource driverClassName: com.mysql.cj.jdbc.Driver url: jdbc:mysql://XXX:3306/XX?useUnicode=true&characterEncoding=UTF-8&useSSL=false&serverTimezone=GMT%2B8 username: XX password: XXX druid: publicKey: XXX # 初始化连接大小 默认:0 initialSize: 10 # 最小空闲连接数 默认:0 minIdle: 10 # 最大连接数 默认:8 maxActive: 200 ..... primary: master #shardingsphere配置 shardingsphere: datasource: common: type: com.alibaba.druid.pool.DruidDataSource driverClassName: com.mysql.cj.jdbc.Driver names: base,shangcheng,shangcheng-other base: type: com.alibaba.druid.pool.DruidDataSource driverClassName: com.mysql.cj.jdbc.Driver url: jdbc:mysql://XXX:3306/XX?useUnicode=true&characterEncoding=UTF-8&useSSL=false&serverTimezone=GMT%2B8 username: XX password: XXX filters: config connectionProperties: config.decrypt=true;config.decrypt.key=XXX # 初始化连接大小 默认:0 initialSize: 10 # 最小空闲连接数 默认:0 minIdle: 10 # 最大连接数 默认:8 maxActive: 100 ..... shangcheng: type: com.alibaba.druid.pool.DruidDataSource driverClassName: com.mysql.cj.jdbc.Driver url: jdbc:mysql://XXX:3306/XX?useUnicode=true&characterEncoding=UTF-8&useSSL=false&serverTimezone=GMT%2B8&tinyInt1isBit=false username: XX password: XXX filters: config connectionProperties: config.decrypt=true;config.decrypt.key=XXX # 初始化连接大小 默认:0 initialSize: 10 # 最小空闲连接数 默认:0 minIdle: 10 # 最大连接数 默认:8 maxActive: 50 ..... shangcheng-other: type: com.alibaba.druid.pool.DruidDataSource driverClassName: com.mysql.cj.jdbc.Driver url: jdbc:mysql://XXX:3306/XX?useUnicode=true&characterEncoding=UTF-8&useSSL=false&serverTimezone=GMT%2B8&tinyInt1isBit=false username: XX password: XXX filters: config connectionProperties: config.decrypt=true;config.decrypt.key=XXX # 初始化连接大小 默认:0 initialSize: 10 # 最小空闲连接数 默认:0 minIdle: 10 # 最大连接数 默认:8 ..... rules: sharding: tables: ob_party_user: actualDataNodes: shangcheng.ob_party_user,shangcheng-other.ob_party_user databaseStrategy: hint: shardingAlgorithmName: hint-db-party-user tableStrategy: hint: shardingAlgorithmName: hint-table-party-user sharding-algorithms: hint-db-party-user: type: hint-db-party-user hint-table-party-user: type: hint-table-party-user defaultTableStrategy: none: defaultDatabaseStrategy: none: props: sql-show: false
dynamic组件的目的是将整个项目的数据源托管方式分为2大部分,第一部分是默认的数据源托管模式,另一部分是shardingsphere托管模式(专门用于分库分表),这样的好处是不参与分库分表的操作走默认托管的数据源,参与分库分表的走shardingsphere托管的数据源,这样极大的减少了分库组件给项目带来的不兼容性。
业务的难点在于分库分表之后,如何能够快速定位指定数据源进行增删改查,因为用户表的访问是整个系统中最核心也是量最大的,所以根据业务的需求,根据组织id、人员id来查询用户信息是最常见的需求,故而将用户所属组织的关系进行redis缓存的存储。
使用用户与组织的缓存数据,项目采用在启动时将所有的用户组织关系存入到redis缓存中