这天霞妹又来找烧哥了。
“烧哥,帮我看下这个分库分表,升级5.0后不能用了呢?”
“Let me c c?哇,Sharding-jdbc刚推出的最新版?”
关系数据库当今依然占有巨大市场份额,前期通常会存储至单一节点。为提高性能和可用性,一种方案是迁移到NoSQL ,但会有较大技术成本。另一种则考虑数据分片,按照某个维度将数据分散地存储到多个库或表,来有效的避免大数据量产生的查询瓶颈。
数据分片也有两种。垂直分片讲究专库专用,通常按业务模块划分。水平分片则是按字段,通过某种规则拆分到不同库或表。通过搭建多主多从的数据库架构,读写分离,配合水平拆分,实际场景中较为常见。
ShardingSphere则同时提供了这两种解决方案,2020.4.16成为 Apache 软件基金会的顶级项目。Sharding-jdbc作为子产品,以Jar包形式提供服务,可理解为增强版的 JDBC 驱动,能够几乎不改动代码的情况下实现架构迁移,2021.11.10推出了5.0.0版。
首先看之前的配置文件:
pom.xml
org.apache.shardingsphere
sharding-jdbc-spring-boot-starter
4.1.1
application.yml
spring:
shardingsphere:
datasource:
names: master1,slave1
master1:
driver-class-name: com.mysql.cj.jdbc.Driver
password:
type: com.alibaba.druid.pool.DruidDataSource
url:
username:
slave1:
driver-class-name: com.mysql.cj.jdbc.Driver
password:
type: com.alibaba.druid.pool.DruidDataSource
url:
username:
props:
sql:
show: true
sharding:
tables:
b_gcg_content:
actual-data-nodes: ds.b_gcg_content_$->{0..1}
table-strategy:
inline:
sharding-column: content_id
algorithm-expression: b_gcg_content_$->{content_id % 2}
key-generator:
column: content_id
type: SNOWFLAKE
master-slave-rules:
ds:
load-balance-algorithm-type: round_robin
master-data-source-name: master1
slave-data-source-names: slave1
主库master1,从库slave1,对content表根据content_id取模拆分为两个表。
查询,插入,运行正常。
再看之后的:
pom.yml
org.apache.shardingsphere
shardingsphere-jdbc-core-spring-boot-starter
5.0.0
application.yml
spring:
shardingsphere:
datasource:
names: master1,slave1
master1:
type: com.zaxxer.hikari.HikariDataSource
driverClassName: com.mysql.cj.jdbc.Driver
jdbcUrl:
username:
password:
slave1:
type: com.zaxxer.hikari.HikariDataSource
driverClassName: com.mysql.cj.jdbc.Driver
jdbcUrl:
username:
password:
props:
sql-show: true
rules:
sharding:
tables: # 数据分片规则配置
b_gcg_content: # 逻辑表名称
actualDataNodes: ds.b_gcg_content_$->{0..1} # 由数据源名 + 表名组成(参考Inline语法规则)
tableStrategy: # 分表策略,同分库策略
standard: # 用于单分片键的标准分片场景
shardingColumn: content_id # 分片列名称
shardingAlgorithmName: my # 分片算法名称
keyGenerateStrategy: # 分布式序列策略
column: content_id # 自增列名称,缺省表示不使用自增主键生成器
keyGeneratorName: my # 分布式序列算法名称
shardingAlgorithms:
my: # 分片算法名称
type: INLINE # 分片算法类型
props: # 分片算法属性配置
algorithm-expression: b_gcg_content_$->{content_id % 2}
keyGenerators:
my: # 分布式序列算法名称
type: SNOWFLAKE # 分布式序列算法类型
readwriteSplitting:
dataSources:
ds:
loadBalancerName: my
writeDataSourceName: master1
readDataSourceNames: slave1
loadBalancers:
my: # 负载均衡算法名称
type: ROUND_ROBIN # 负载均衡算法类型
查询正常,插入时报错:
Insert statement does not support sharding table routing to multiple data nodes.
首先看到配置文件的语法,升级后有很大改变,根据官方文档挨个排查,确认格式全部正确。
搜索这个报错,全网都没有。到官方仓库issue,有大把。引起的原因有很多,但都已修复。
那就下最新源码,5.0.1-SNAPSHOT,重新编译放入私服,岂不简单?
编译比较麻烦,不过最终还是成功了,更改maven版本,奇怪了,依然报错。
报错中提到了data nodes,配置里同时有读写分离和分表,那就去掉一个,只要分表
rules:
sharding:
tables: # 数据分片规则配置
b_gcg_content: # 逻辑表名称
actualDataNodes: master1.b_gcg_content_$->{0..1} # 由数据源名 + 表名组成(参考Inline语法规则)
tableStrategy: # 分表策略,同分库策略
standard: # 用于单分片键的标准分片场景
shardingColumn: content_id # 分片列名称
shardingAlgorithmName: my # 分片算法名称
keyGenerateStrategy: # 分布式序列策略
column: content_id # 自增列名称,缺省表示不使用自增主键生成器
keyGeneratorName: my # 分布式序列算法名称
shardingAlgorithms:
my: # 分片算法名称
type: INLINE # 分片算法类型
props: # 分片算法属性配置
algorithm-expression: b_gcg_content_$->{content_id % 2}
keyGenerators:
my: # 分布式序列算法名称
type: SNOWFLAKE # 分布式序列算法类型
还是报错。
那不分表总可以吧?再来
rules:
sharding:
tables: # 数据分片规则配置
b_gcg_content: # 逻辑表名称
actualDataNodes: master1.b_gcg_content # 由数据源名 + 表名组成(参考Inline语法规则)
tableStrategy: # 分表策略,同分库策略
standard: # 用于单分片键的标准分片场景
shardingColumn: content_id # 分片列名称
shardingAlgorithmName: my # 分片算法名称
keyGenerateStrategy: # 分布式序列策略
column: content_id # 自增列名称,缺省表示不使用自增主键生成器
keyGeneratorName: my # 分布式序列算法名称
shardingAlgorithms:
my: # 分片算法名称
type: INLINE # 分片算法类型
props: # 分片算法属性配置
algorithm-expression: b_gcg_content
keyGenerators:
my: # 分布式序列算法名称
type: SNOWFLAKE # 分布式序列算法类型
这下倒是可以,看来的确是分表有问题。
那官方demo不会也报错吗?apache出品的不至于吧?怀疑人生。
4.x的shardingsphere-example项目已经停更,新demo合并到了主库。
但官方demo是正常的?那就蹊跷了。
难道我的表不行?换成demo的库试试,还是报错,奇葩。
再来看看上面配置,唯一的区别就在于名称改成了my,难不成名称是不能改的??
改成跟demo一样名称,竟然行了。。。
spring:
shardingsphere:
datasource:
names: master1,slave1
master1:
type: com.zaxxer.hikari.HikariDataSource
driverClassName: com.mysql.cj.jdbc.Driver
jdbcUrl:
username:
password:
slave1:
type: com.zaxxer.hikari.HikariDataSource
driverClassName: com.mysql.cj.jdbc.Driver
jdbcUrl:
username:
password:
props:
sql-show: true
rules:
sharding:
tables: # 数据分片规则配置
b_gcg_content: # 逻辑表名称
actualDataNodes: ds.b_gcg_content_$->{0..1} # 由数据源名 + 表名组成(参考Inline语法规则)
tableStrategy: # 分表策略,同分库策略
standard: # 用于单分片键的标准分片场景
shardingColumn: content_id # 分片列名称
shardingAlgorithmName: my-table # 分片算法名称
keyGenerateStrategy: # 分布式序列策略
column: content_id # 自增列名称,缺省表示不使用自增主键生成器
keyGeneratorName: my-key # 分布式序列算法名称
shardingAlgorithms:
my-table: # 分片算法名称
type: INLINE # 分片算法类型
props: # 分片算法属性配置
algorithm-expression: b_gcg_content_$->{content_id % 2}
keyGenerators:
my-key: # 分布式序列算法名称
type: SNOWFLAKE # 分布式序列算法类型
readwriteSplitting:
dataSources:
ds:
loadBalancerName: my-load
writeDataSourceName: master1
readDataSourceNames: slave1
loadBalancers:
my-load: # 负载均衡算法名称
type: ROUND_ROBIN # 负载均衡算法类型
“霞妹可以啦”
“烧哥好棒,我这有张券,中午一起嘛”
架构师的工作就是解决各种疑难杂症,思路的锻炼来自长期实战经历。
Apache的品质总体还是可信赖的,这算个小问题。源码应该是把某些名称放在了一个map下,或者是缓存时出了岔子,有空去提个issue.
又增加一条规范:复杂配置文件中,自定义名称不应该重复。