大家好,我是小富~
ShardingSphere 实现分库分表,如何治理散布在不同数据库实例中的成千上万张分片表?
上边的问题是之前有个小伙伴看了我的分库分表的文章,私下征询我的,看到他的发问我第一感觉就是这老铁没用过 ShardingSphere,因为这个问题在 ShardingSphere 中曾经有了很好的解决方案,接下来看看怎么实现。
本文案例代码 GitHub 地址:https://github.com/chengxy-nds/Springboot-Notebook/tree/master/shardingsphere101/shardingsphere-autocreate-table
系列往期
往期系列文章(我佛系更新,无上限拖更):
(一)好好的零碎,为什么要分库分表?
(二)分库分表的 21 条法令,hold 住!
(三)2 种形式疾速实现分库分表,轻松拿捏!
本文是《ShardingSphere5.x 分库分表原理与实战》系列的第四篇文章,在进行分库分表设计时,确认好了数据节点数量和分片策略当前,接下来要做的就是治理大量的分片表。理论施行过程中可能存在上百个分片数据库实例,每个实例中都可能有成千上万个分片表,如果仅依附人力来实现这些工作显然是不事实的。所以,想要疾速且自动化治理这些分片表,应用工具是十分必要滴。
前言
ShardingSphere
框架成员中的 Shardingsphere-jdbc
和Shardingsphere-proxy
都提供了自动化治理分片表的性能auto-tables
,能够对立保护大量的分片表,防止了手动编写脚本和保护分片表的繁琐工作,极大水平缩小分库分表的开发和保护老本,晋升效率和可靠性。
这里咱们先应用 Shardingsphere-jdbc
来实际操作一下,Shardingsphere-proxy
形式后续会有独自的文章具体解说,就不在这里开展了。
筹备工作
假如咱们要对 t_order
表进行分库分表,首先咱们要做的就是确定好分片计划,这里应用两个数据库实例 db0
、db1
,每个实例中t_order
表分成 1000 张分片表 t_order_1 ~ t_order_1000
,order_id
字段作为分片键,分片算法应用取模算法order_id % n
,分布式主键生成策略采纳snowflake
。
t_order
逻辑表的表构造如下:
CREATE TABLE `t_order` (`order_id` BIGINT ( 20) NOT NULL COMMENT "订单表分布式主健 ID",
`order_number` VARCHAR (255) NOT NULL COMMENT "订单号",
`customer_id` BIGINT (20) NOT NULL COMMENT "用户 ID",
`order_date` date NOT NULL COMMENT "下单工夫",
`total_amount` DECIMAL (10, 2) NOT NULL COMMENT "订单金额",
PRIMARY KEY (`order_id`) USING BTREE
);
有了这些根底信息,能够先来进行 t_order
表的分片配置了,不思考其余因素,这里先 Run 起来!
分片规定配置
设定好分片规定,接着编写逻辑表 t_order
的分片规定的配置,我别离应用 yml 配置
和Java 编码
两种形式做了实现。要留神的是两种形式不要并存,不然启动会报错。
yml 配置形式
应用 yml 配置绝对简略易用比拟直观,适宜对分库分表要求不太简单的场景,残缺配置如下:
spring:
shardingsphere:
datasource:
# 数据源名称,多数据源以逗号分隔 , 放在第一个的数据源为未配置分片规定表的默认数据源
names: db0 , db1
# 名称与上边 names 保持一致
db0:
....
db1:
....
# 具体规定配置
rules:
sharding:
# 分片算法定义
sharding-algorithms:
# 自定义分片算法名称
t_order_database_algorithms:
# 分片算法类型
type: INLINE
# 自定义参数
props:
algorithm-expression: db$->{order_id % 2}
t_order_table_algorithms:
type: INLINE
props:
algorithm-expression: t_order_$->{order_id % 1000}
t_order_mod:
type: MOD
props:
# 指定分片数量
sharding-count: 1000
# 分布式序列算法配置
key-generators:
t_order_snowflake:
type: SNOWFLAKE
# 分布式序列算法属性配置
props:
worker-id: 1
tables:
# 逻辑表名称
t_order:
# 数据节点:数据库. 分片表
actual-data-nodes: db$->{0..1}.t_order_$->{1..1000}
# 分库策略
database-strategy:
standard:
# 分片列名称
sharding-column: order_id
# 分片算法名称
sharding-algorithm-name: t_order_database_algorithms
# 分表策略
table-strategy:
standard:
# 分片列名称
sharding-column: order_id
# 分片算法名称
sharding-algorithm-name: t_order_table_algorithms
# 主键生成策略
keyGenerateStrategy:
column: order_id
keyGeneratorName: t_order_snowflake
# 属性配置
props:
# 展现批改当前的 sql 语句
sql-show: true
Java 编码方式
应用 Java 编码方式更加灵便和可扩大,能够依据业务定制分片规定,适宜对分库分表有非凡需要或须要动静调整的场景。
/**
* 公众号:程序员小富
*/
@Configuration
public class ShardingConfiguration {
/**
* 配置分片数据源
* 公众号:程序员小富
*/
@Bean
public DataSource getShardingDataSource() throws SQLException {Map<String, DataSource> dataSourceMap = new HashMap<>();
dataSourceMap.put("db0", dataSource0());
dataSourceMap.put("db1", dataSource1());
// 分片 rules 规定配置
ShardingRuleConfiguration shardingRuleConfig = new ShardingRuleConfiguration();
// 分片算法
shardingRuleConfig.setShardingAlgorithms(getShardingAlgorithms());
// 配置 t_order 表分片规定
ShardingTableRuleConfiguration orderTableRuleConfig = new ShardingTableRuleConfiguration("t_order", "db${0..1}.t_order_${1..1000}");
orderTableRuleConfig.setTableShardingStrategy(new StandardShardingStrategyConfiguration("order_id", "t_order_table_algorithms"));
orderTableRuleConfig.setDatabaseShardingStrategy(new StandardShardingStrategyConfiguration("order_id", "t_order_database_algorithms"));
shardingRuleConfig.getTables().add(orderTableRuleConfig);
// 是否在控制台输入解析革新后实在执行的 SQL
Properties properties = new Properties();
properties.setProperty("sql-show", "true");
// 创立 ShardingSphere 数据源
return ShardingSphereDataSourceFactory.createDataSource(dataSourceMap, Collections.singleton(shardingRuleConfig), properties);
}
/**
* 配置数据源 1
* 公众号:程序员小富
*/
public DataSource dataSource0() {HikariDataSource dataSource = new HikariDataSource();
dataSource.setDriverClassName("com.mysql.cj.jdbc.Driver");
dataSource.setJdbcUrl("jdbc:mysql://127.0.0.1:3306/db0?useUnicode=true&characterEncoding=utf-8&useSSL=false&serverTimezone=Asia/Shanghai&allowPublicKeyRetrieval=true");
dataSource.setUsername("root");
dataSource.setPassword("123456");
return dataSource;
}
/**
* 配置数据源 2
* 公众号:程序员小富
*/
public DataSource dataSource1() {HikariDataSource dataSource = new HikariDataSource();
dataSource.setDriverClassName("com.mysql.cj.jdbc.Driver");
dataSource.setJdbcUrl("jdbc:mysql://127.0.0.1:3306/db1?useUnicode=true&characterEncoding=utf-8&useSSL=false&serverTimezone=Asia/Shanghai&allowPublicKeyRetrieval=true");
dataSource.setUsername("root");
dataSource.setPassword("123456");
return dataSource;
}
/**
* 配置分片算法
* 公众号:程序员小富
*/
private Map<String, AlgorithmConfiguration> getShardingAlgorithms() {Map<String, AlgorithmConfiguration> shardingAlgorithms = new LinkedHashMap<>();
// 自定义分库算法
Properties databaseAlgorithms = new Properties();
databaseAlgorithms.setProperty("algorithm-expression", "db$->{order_id % 2}");
shardingAlgorithms.put("t_order_database_algorithms", new AlgorithmConfiguration("INLINE", databaseAlgorithms));
// 自定义分表算法
Properties tableAlgorithms = new Properties();
tableAlgorithms.setProperty("algorithm-expression", "db$->{order_id % 1000}");
shardingAlgorithms.put("t_order_table_algorithms", new AlgorithmConfiguration("INLINE", tableAlgorithms));
return shardingAlgorithms;
}
}
下面咱们在利用中编写好了分片规定,当初就差在数据库实例中创立分片表了,手动创立和治理 1000 张分片表的确是一个又脏又累的活,反正我是不会干的!
治理分片表
其实,ShardingSphere
内曾经为咱们提供了治理分片表的能力。
当一张逻辑表 t_order
被配置了分片规定,那么接下来对逻辑表的各种 DDL
操作(例如 创立表
、 批改表构造
等),命令和数据会依据分片规定,执行和存储到每个分片数据库和分片库中的相应分片表中,以此放弃整个分片环境的一致性。
不过,应用 Shardingsphere-jdbc
治理分片表的过程中,是须要咱们手动编写对逻辑表的 DDL
操作的代码。咱们来跑几个单元测试用例来察看理论的执行成果,间接应用 jdbcTemplate
执行创立逻辑表 t_order
的 SQL。
/**
* @author 公众号:程序员小富
* 主动创立分片表
* @date 2023/12/31 17:25
*/
@SpringBootTest
class AutoCreateTablesTests {
@Resource
private JdbcTemplate jdbcTemplate;
/**
* 执行创立逻辑表的 SQL,会依据 AutoTables 的配置主动在对应的数据源内创立分片表
* @author 公众号:程序员小富
*/
@Test
public void autoCreateOrderTableTest() {
jdbcTemplate.execute("CREATE TABLE `t_order` (\n" +
"`order_id` bigint(20) NOT NULL,\n" +
"`order_number` varchar(255) NOT NULL,\n" +
"`customer_id` bigint(20) NOT NULL,\n" +
"`order_date` date NOT NULL,\n" +
"`total_amount` decimal(10,2) NOT NULL,\n" +
"PRIMARY KEY (`order_id`) USING BTREE\n" +
");");
}
}
依据之前配置的分片规定,将会在两个数据库实例 db0
和 db1
中,别离生成 1000
张命名为 t_order_1
到t_order_1000
的分片表,看到两个数据库均胜利创立了 1000 张分片表。
在次执行更新 t_order
表 SQL,将字段 order_number
长度从 varchar(255)
扩大到 varchar(500)
,执行 SQL 看下成果。
/**
* @author 公众号:程序员小富
* 主动创立分片表
* @date 2023/12/31 17:25
*/
@SpringBootTest
class AutoCreateTablesTests {
@Resource
private JdbcTemplate jdbcTemplate;
@Test
public void autoModifyOrderTableTest() {jdbcTemplate.execute("ALTER TABLE t_order MODIFY COLUMN order_number varchar(500);");
}
}
通过查看两个分片库,咱们胜利地将所有分片表的 order_number
字段长度更改为了varchar(500)
,在控制台日志中,能够看到它是通过在每个分片库内顺次执行了 1000 次命令实现的。
Shardingsphere-jdbc
实现分库分表时,能够采纳这种默认的形式来治理分片表。但要留神的是,因为波及到不同的数据库实例,如果不应用第三方的分布式事务管理工具(例如 Seata
等),执行过程是无奈保障事务一致性的。
自定义治理分片表
上边为逻辑表配置分片规定,应用程序内执行对逻辑表的 DDL 操作,就能够很轻松的治理分片表。
自定义
不过,默认的分片治理还是有局限性的,咱们在设计分片规定时往往会依据不同的业务维度来划分,例如按天、月、按季度生成分片表并散布到不同数据源中等。这样就须要一些自定义的规定来实现。
ShardingSphere 5.X
版本后推出了一种新的治理分片配置形式:AutoTable
。设置了 AutoTable
的逻辑表,将交由 ShardingSphere
主动治理分片,用户只须要指定分片数量和应用的数据库实例,无需再关怀表的具体散布,配置格局如下:
spring:
shardingsphere:
# 数据源配置
datasource:
......
# 具体规定配置
rules:
sharding:
# 逻辑表分片规定
tables:
# 逻辑表名称
t_order:
.....
# 主动分片表规定配置
auto-tables:
t_order: # 逻辑表名称
actual-data-sources: db$->{0..1}
sharding-strategy: # 切分策略
standard: # 用于单分片键的规范分片场景
sharding-column: order_id # 分片列名称
sharding-algorithm-name: t_order_mod # 主动分片算法名称
ShardingSphere-Jdbc
中配置应用 auto-tables
次要两个参数,actual-data-sources
指定数据源散布,因为是治理分片表所以只需数据源信息即可;sharding-strategy
指具体采纳何种算法来进行分片。
对逻辑表的 DDL 操作,零碎会首先查看是否配置了AutoTable,如果已配置,则优先采纳配置的规定;若未配置,则将应用默认的逻辑表分片规定。
AutoTable
反对 ShardingSphere
内置的全副主动分片算法,所谓主动分片算法就是依据 actualDataSources
设置的数据源信息,应用对应内置算法自行解析解决。
- MOD:取模分片算法
- HASH_MOD:哈希取模分片算法
- VOLUME_RANGE:基于分片容量的范畴分片算法
- BOUNDARY_RANGE:基于分片边界的范畴分片算法
- AUTO_INTERVAL:主动时间段分片算法
AutoTable 应用
举个例子,咱们应用内置 MOD
取模算法作为 AutoTable
的分片算法,同样是 db0
、db1
两个实例中各创立 1000 张分片表。那么当对逻辑表的 DDL 操作时,ShardingSphere
会根据分片表编号 t_order_0~t_order_1999 % 数据库实例数
取模来确认 DDL 命令路由到哪个实例中执行。
spring:
shardingsphere:
# 数据源配置
datasource:
.....
# 具体规定配置
rules:
sharding:
# 主动分片表规定配置
auto-tables:
t_order:
actual-data-sources: db$->{0..1}
sharding-strategy:
standard:
sharding-column: order_date
sharding-algorithm-name: t_order_mod
# 分片算法定义
sharding-algorithms:
t_order_mod:
type: MOD
props:
# 指定分片数量
sharding-count: 2000
还是执行方才创立表的单元测试,会发现 db0
、db1
两个实例中曾经各自创立了 1000 张分片表,但你会发现 1000 张表曾经不再是依照程序创立的了。
上边应用的是内置主动分片算法,它对于咱们来说是黑盒,提供它不便咱们拿来即用。不过,如果想要做到更细粒度的治理分片表,最好的方法就是自定义分片算法,后续章节会介绍所有内置分片算法和自定义分片算法的应用。
总结
在应用 ShardingSphere
实现分库分表的时候,要摒弃 先建表、再配规定 的传统思维,要先确定规定在建表,治理表是一件很简略的事,咱们只有通知 ShardingSphere
分片数量和散布规定,剩下的就让框架来解决就好了。
本文案例代码 GitHub 地址:https://github.com/chengxy-nds/Springboot-Notebook/tree/master/shardingsphere101/shardingsphere-autocreate-table
我是小富~ 下期见