Sharding jdbc 强制路由策略(HintShardingStrategy)使用记录
背景
随着项目运行时间逐渐增加,数据库中的数据也越来越多,虽然加索引,优化查询,但是数据量太大,还是会影响查询效率,也给数据库增加了负载。
再加上冷数据基本不使用的场景,决定采用分表来处理数据,从而来提高系统性能。
sharding jdbc 介绍
官方文档在这里。
Sharding-jdbc 定位是轻量级的java框架,在java 的JDBC层提供额外功能。它使用客户端直连数据库,以jar包形式提供服务,无需额外部署和依赖,可理解为增强版的JDBC驱动,完全兼容JDBC和各种ORM框架。
- 适用于任何基于 java 的ORM 框架(JPA,Hibernate,mybatis 等)
- 基于任何第三方的数据库连接池(DBCP,c3p0, druid, hikariCP 等)
- 支持任意实现JDBC规范的数据库(目前支持MySQL,Oracle,SQLServer和PostgreSQL)---因为SQL 语法不同,有对应的解析
方案选择
文档很全,并且有三款产品的说明,分别是:Sharding jdbc 、Sharding-proxy、Sharding-sidecar(研发中)
本着想学技术,先实践写demo的原则,直接跳过SQL,解析引擎,路由、改写、归并引擎等说明,直接到配置界面。
配置的方式有很多种:
- java 配置
- SpringBoot 配置
- yaml 配置
- Spring 命名空间配置
配置好之后,直接传入一个 分片算法即可。
// 配置数据源
DataSource getShardingDataSource() throws SQLException {
ShardingRuleConfiguration shardingRuleConfig = new ShardingRuleConfiguration();
shardingRuleConfig.getTableRuleConfigs().add(getOrderTableRuleConfiguration());
shardingRuleConfig.getBindingTableGroups().add("t_order");
// 如果需要打印SQL new Properties 可以 设置一个属性 > io.shardingjdbc.core.constant.ShardingPropertiesConstant#SQL_SHOW
return ShardingDataSourceFactory.createDataSource(createDataSourceMap(), shardingRuleConfig, new ConcurrentHashMap<>(), new Properties());
}
// 针对不同的表可以有不同的策略
TableRuleConfiguration getOrderTableRuleConfiguration() {
TableRuleConfiguration result = new TableRuleConfiguration();
result.setLogicTable("t_order");
result.setActualDataNodes("ds${0..1}.t_order${0..1}");
result.setTableShardingStrategyConfig(shardingRuleConfiguration());
return result;
}
@Bean
public ShardingStrategyConfiguration shardingRuleConfiguration() {
return new MyHintShardingStrategyConfiguration("order_id","com.test.config.MyHintShardingAlgorithm");
}
Map<String, DataSource> createDataSourceMap() {
Map<String, DataSource> result = new HashMap<>();
result.put("ds0", DataSourceUtil.createDataSource("ds0"));
result.put("ds1", DataSourceUtil.createDataSource("ds1"));
return result;
}
踩坑记录
- 情况
本来以为这样就可以成功的分片,没想到 MyHintShardingAlgorithm#sharding方法一直都进不去,多次都不行,只能断点调试了。
确实发现了一个地方:
见:io.shardingjdbc.core.routing.type.simple.SimpleRoutingEngine#route 方法
// 分片路由:找到对应的表节点
@Override
public RoutingResult route() {
TableRule tableRule = shardingRule.getTableRule(logicTableName);
List<ShardingValue> databaseShardingValues = getDatabaseShardingValues(tableRule);
List<ShardingValue> tableShardingValues = getTableShardingValues(tableRule); // 获取下面表名的地方
Collection<String> routedDataSources = routeDataSources(tableRule, databaseShardingValues);
Collection<DataNode> routedDataNodes = new LinkedList<>();
for (String each : routedDataSources) {
routedDataNodes.addAll(routeTables(tableRule, each, tableShardingValues));
}
return generateRoutingResult(routedDataNodes);
}
// sharding方法只有这里才会调用,他有一个条件,就是传入的 tableShardingValues 不可以为空
private Collection<DataNode> routeTables(final TableRule tableRule, final String routedDataSource, final List<ShardingValue> tableShardingValues) {
Collection<String> availableTargetTables = tableRule.getActualTableNames(routedDataSource);
Collection<String> routedTables = tableShardingValues.isEmpty() ? availableTargetTables
: shardingRule.getTableShardingStrategy(tableRule).doSharding(availableTargetTables, tableShardingValues);// **这里**
Preconditions.checkState(!routedTables.isEmpty(), "no table route info");
Collection<DataNode> result = new LinkedList<>();
for (String each : routedTables) {
result.add(new DataNode(routedDataSource, each));
}
return result;
}
// 传入的参数是这里传入的:由于我这里使用强制路由所以走这里
private List<ShardingValue> getTableShardingValuesFromHint(final Collection<String> shardingColumns) {
List<ShardingValue> result = new ArrayList<>(shardingColumns.size());
for (String each : shardingColumns) {
Optional<ShardingValue> shardingValue = HintManagerHolder.getTableShardingValue(new ShardingKey(logicTableName, each));
if (shardingValue.isPresent()) {
result.add(shardingValue.get());
}
}
return result;
}
- 分析
shardingColumns 是从对应的 ShardingStrategy 中赋值的,我使用的强制路由源码如下:
public HintShardingStrategy(final HintShardingAlgorithm shardingAlgorithm) {
this.shardingColumns = new TreeSet<>(String.CASE_INSENSITIVE_ORDER);
this.shardingAlgorithm = shardingAlgorithm;
}
发现shardingColumns 一直是空的,也没有方法可以添加(自定义添加也不行,因为ShardingStrategy是通过对应的ShardingStrategyConfiguration#build方法生成的),所以肯定不会走到路由的地方。
变更
排查到这里,就找到了一个修改的方法--重写 ShardingStrategy ,随意给 columns 赋值不为空即可。
// 自定义新的构造函数,给 shardingColumns 赋值
public MyHintShardingStrategy(Collection<String> shardingColumns, final HintShardingAlgorithm shardingAlgorithm) {
this.shardingColumns = new TreeSet<>(shardingColumns);
this.shardingAlgorithm = shardingAlgorithm;
}
重新运行项目,发现一切按想要的来。
回顾
不知道是自己配置的原因,还是打开的方式不对,反正通过这种方式实现了表的分片。
向项目提的issue入口在这里,等待回复
如有不对还请大神们指教!
**==============20100307更新**
他们在最新的版本里修复了这个问题,从 HintManageHolder 里获取 sharding Columns。
代码如下:
package org.apache.shardingsphere.core.routing.type.standard;
private List<RouteValue> getTableShardingValuesFromHint() {
return getRouteValues(HintManagerHolder.getTableShardingValues(logicTableName));
}
但是 mvn 上不知道能不能获取到那个版本,先记录到这里吧。
Sharding jdbc 强制路由策略(HintShardingStrategy)使用记录的更多相关文章
- 记录因Sharding Jdbc批量操作引发的一次fullGC
周五晚上告警群突然收到了一条告警消息,点开一看,应用 fullGC 了. 于是赶紧联系运维下载堆内存快照,进行分析. 内存分析 使用 MemoryAnalyzer 打开堆文件 mat 下载地址:htt ...
- Sharding JDBC案例实战
基础分库 以下实例基于shardingsphere 4.1.0 + SpringBoot 2.2.5.RELEASE版本 依赖导入: <properties> <project.bu ...
- ip route rule 路由策略 高级路由 捆绑 网桥
http://lwfs.net/2005/11/28/10/ #!/bin/bash IP0= IP1= GW0= GW1= NET0= NET1= DEV0=eth0 DEV1=eth1 # com ...
- sharding jdbc(sphere) 3.1.0 spring boot配置
sharding jdbc 2.x系列详解参见https://www.cnblogs.com/zhjh256/p/9221634.html. 最近将sharding jdbc的配置从xml切换到了sp ...
- Sharding JDBC整合SpringBoot 2.x 和 MyBatis Plus 进行分库分表
Sharding JDBC整合SpringBoot 2.x 和 MyBatis Plus 进行分库分表 交易所流水表的单表数据量已经过亿,选用Sharding-JDBC进行分库分表.MyBatis-P ...
- 路由策略和策略路由 & route-map
今天,这个专题应用下route-map,在这个之前,有很多内容需要掌握,不是简单的制定一个路由图就可以了. -------- 本次专题理论的东西居多,但是不是复制黏贴,是加上自己的理解思想. 第一个要 ...
- Spring boot项目集成Sharding Jdbc
环境 jdk:1.8 framework: spring boot, sharding jdbc database: MySQL 搭建步骤 在pom 中加入sharding 依赖 <depend ...
- XXL-Job路由策略
企业项目中所有的任务调动通过XXL-Job 去管理调度 路由策略类似于Nginx哦 XXL-Job实际封装的是Quartz. 关于分片广播,执行器集群部署时候,任务路由策略选择“”分片广播”情况下,一 ...
- CCNP路由实验之九 路由策略
CCNP路由实验之九 路由策略 路由器在公布与接收路由信息时,可能须要实施一些策略.以便对路由信息进行过滤,比如仅仅接收或公布满足一定条件的路由信息. 一种路由协议可能须要引入其它的路由协议发现 ...
随机推荐
- Kubernetes中Service的使用
目录 简介 1. Service资源定义 1.1 Service Type ClusterIP 无头service NodePort sessionAffinity实现源地址session绑定 简介 ...
- 05 python开发之文件处理
05 python开发之文件处理 目录 05 python开发之文件处理 5 文件处理 5.1 字符编码 5.1.1 基本概念 5.1.2 发展历程 5.1.3 使用 5.2 文件处理基础 5.2.1 ...
- charles功能(二)修改response请求参数
1.接口处 鼠标右击,选择breakpoints(允许本接口使用breakpionts功能) 2.开始设置断点值 4.重新请求接口(charles的界面变为可编辑状态),修改请求参数,执行请求 5.最 ...
- 关于缓存的一些重要概念(Redis 前置菜)
1. 缓存的基本思想 很多朋友,只知道缓存可以提高系统性能以及减少请求相应时间,但是,不太清楚缓存的本质思想是什么. 缓存的基本思想其实很简单,就是我们非常熟悉的空间换时间.不要把缓存想的太高大上,虽 ...
- PyQt(Python+Qt)学习随笔:树型部件QTreeWidget中的topLevelItem、indexOfTopLevelItem和takeTopLevelItem方法
老猿Python博文目录 专栏:使用PyQt开发图形界面Python应用 老猿Python博客地址 获取指定位置顶层项 树型部件QTreeWidget中,通过topLevelItem方法根据位置索引取 ...
- 第一章、PyQt的简介、安装与配置
老猿Python博文目录 专栏:使用PyQt开发图形界面Python应用 老猿Python博客地址 第一章.PyQt的简介.安装与配置 一.引言 当朋友向我推荐PyQt时,老猿才知道有这样一个在Pyt ...
- selenium常用的标签
1.selenium之 下拉选择框Select.反选框Deselect.options 我们通常会遇到两种下拉框,一种使用的是html的标签select,另一种是使用input标签做的假下拉框.后者我 ...
- matplotlib 绘制多个图——两种方法
import numpy as np import matplotlib.pyplot as plt #创建自变量数bai组du x= np.linspace(0,2*np.pi,500) #创建函数 ...
- python 读取目录下的文件
参考方法: import os path = r'C:\Users\Administrator\Desktop\file' for filename in os.listdir(path): prin ...
- 题解-JSOI2011 分特产
题面 JSOI2011 分特产 有 \(n\) 个不同的盒子和 \(m\) 种不同的球,第 \(i\) 种球有 \(a_i\) 个,用光所有球,求使每个盒子不空的方案数. 数据范围:\(1\le n, ...