梦想还是要有的,万一忘了咋办?

0%

ShardingSphere

目录:

  • 安装 ShardingSphere
  • 配置ShardingSphere-JDBC
  • 配置ShardingSphere-Proxy
  • 测试弹性扩容

本次测试基于shardingsphere 5.0.0

安装ShardingSphere

1
2
3
4
5
<dependency>
<groupId>org.apache.shardingsphere</groupId>
<artifactId>shardingsphere-jdbc-core-spring-boot-starter</artifactId>
<version>5.0.0</version>
</dependency>

填坑:

1、与druid-spring-boot-starter有冲突,如果还想使用druid连接池可以 将druid-spring-boot-starter 修改为 druid

熟悉配置参数

点击查看官方稳定:Spring Boot Starter

1
2
# 显示sql日志 
spring.shardingsphere.props.sql-show=true

点击查看 spring.shardingsphere.props支持属性
也可以参考:org.apache.shardingsphere.infra.config.properties.ConfigurationPropertyKey

填坑:

1
2
3
4
# 5.x以前
spring.shardingsphere.props.sql.show=true
# 5.x 及以后
spring.shardingsphere.props.sql-show=true

数据源配置

点击查看官方稳定

1
2
3
4
5
6
7
8
9
spring.shardingsphere.datasource.names= # 真实数据源名称,多个数据源用逗号区分

# <actual-data-source-name> 表示真实数据源名称
spring.shardingsphere.datasource.<actual-data-source-name>.type= # 数据库连接池全类名
spring.shardingsphere.datasource.<actual-data-source-name>.driver-class-name= # 数据库驱动类名,以数据库连接池自身配置为准
spring.shardingsphere.datasource.<actual-data-source-name>.jdbc-url= # 数据库 URL 连接,以数据库连接池自身配置为准
spring.shardingsphere.datasource.<actual-data-source-name>.username= # 数据库用户名,以数据库连接池自身配置为准
spring.shardingsphere.datasource.<actual-data-source-name>.password= # 数据库密码,以数据库连接池自身配置为准
spring.shardingsphere.datasource.<actual-data-source-name>.<xxx>= # ... 数据库连接池的其它属性

分库配置

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
# 配置 tb_news 表规则
spring.shardingsphere.rules.sharding.tables.tb_news.actual-data-nodes=ds$->{0..1}.tb_news

## 配置分库策略
spring.shardingsphere.rules.sharding.tables.tb_news.database-strategy.standard.sharding-column=id
# 可以设置 suanfa-1、suanfa-2
spring.shardingsphere.rules.sharding.tables.tb_news.database-strategy.standard.sharding-algorithm-name=suanfa-1

# 配置算法
# 取模
spring.shardingsphere.rules.sharding.sharding-algorithms.suanfa-1.type=MOD
spring.shardingsphere.rules.sharding.sharding-algorithms.suanfa-1.props.sharding-count=2

# 行内+表达式模式
# 返回数据源名称、或者表名称

spring.shardingsphere.rules.sharding.sharding-algorithms.suanfa-2.type=INLINE
spring.shardingsphere.rules.sharding.sharding-algorithms.suanfa-2.props.algorithm-expression=ds$->{id.toInteger() % 2}

填坑

错误1:

1
2
3
//只为tb_news配置了策略,未对tb_news_type配置分库策略时,会提示以上错误。为tb_news_type配置策略

Cause: java.lang.IllegalStateException: All tables must be in the same datasource.] with root cause

错误2:

1
2
3
4
5
6
7

select n.*,t.name as type_name from org.apache.shardingsphere.sharding.rewrite.token.pojo.TableToken@377c0f4 n left join org.apache.shardingsphere.sharding.rewrite.token.pojo.TableToken@1b484898 t on t.id=n.type_id

-- 策略不同导致 两个表在不同的db中,需要确保tb_news 与tb_news_type 拥有相同的策略

spring.shardingsphere.rules.sharding.tables.tb_news_type.actual-data-nodes=ds$->{0..1}.tb_news_type
spring.shardingsphere.rules.sharding.binding-tables=tb_news,tb_news_type

延伸

1、不拆分的、但被拆分表关联查询(news_type ),那该怎么处理呢?

1
2
## 公共表
spring.shardingsphere.rules.sharding.broadcast-tables=tb_news_type

2、不拆分、且不被拆分表关联查询的,如何配置?

1
# 不用配置,shardingphere会自动识别应该用哪个库

加密字段

配置算法:

1
2
3
4
# 加密算法配置
spring.shardingsphere.rules.encrypt.encryptors.aes.type=AES
spring.shardingsphere.rules.encrypt.encryptors.aes.props.aes-key-value=111111222222
spring.shardingsphere.rules.encrypt.queryWithCipherColumn=false

场景1:对pwd 字段 进行 写入时自动加密,读取时自动解密;

1
2
3
4
5
6
# 对 pwd 列自动加密、解密
spring.shardingsphere.rules.encrypt.tables.tb_news.query-with-cipher-column=true
# 加密列名称
spring.shardingsphere.rules.encrypt.tables.tb_news.columns.pwd.cipher-column=pwd
# 加密算法名称
spring.shardingsphere.rules.encrypt.tables.tb_news.columns.pwd.encryptor-name=aes

场景2:同时存储明文、密文列author、author_enc

1
2
3
4
5
6
# 加密列名称
spring.shardingsphere.rules.encrypt.tables.tb_news.columns.author.cipher-column=author_enc
# 原文列名称
spring.shardingsphere.rules.encrypt.tables.tb_news.columns.author.plain-column=author
# 加密算法名称
spring.shardingsphere.rules.encrypt.tables.tb_news.columns.author.encryptor-name=aes

填坑:

1
2
3
# 写数据报错
# 配置查询列名称
spring.shardingsphere.rules.encrypt.tables.tb_news.columns.author.assisted-query-column=xxxx
1
2
3
4
# 查询报错
# 存在同时 存储明文、密文 的列时
# 开启对加密字段的查询(自动解密)
# spring.shardingsphere.rules.encrypt.tables.tb_news.query-with-cipher-column=true

总结下来:
同一个表 有同时存储明文、密文的字段时,query-with-cipher-column 一定时FALSE;

读写分离

1
2
3
4
5
6
7
8
9
10
11
# 负载均衡算法配置
# 负载均衡算法类型 RANDOM
spring.shardingsphere.rules.readwrite-splitting.load-balancers.random.type=RANDOM

# 为ds0配置读写规则
# 写库 ds0
spring.shardingsphere.rules.readwrite-splitting.data-sources.ds0.write-data-source-name=ds0
# 读库 ds11\ds12\ds13
spring.shardingsphere.rules.readwrite-splitting.data-sources.ds0.read-data-source-names=ds11,ds12,ds13
# 读库负载均衡规则
spring.shardingsphere.rules.readwrite-splitting.data-sources.ds0.load-balancer-name=random

填坑:

1、shardingphere不负责同步数据,需要用其他机制例如:mysql主从同步
2、所有数据源都需要再spring.shardingsphere.datasource.names 进行声明、否则不会加载

影子库

待完善

分布式事务

待完善,同一个线程内 基础的事务就可以满足;

1
2
3
4
5
6
7
8
9
10
11
12
/****可以保证事务性*/
@Transactional(rollbackFor = Exception.class)
@Override
public boolean save(NewsEntity entity) {
super.save(entity);
statsService.ince(key);
do others
if (false) {
throw new RuntimeException("xxx");
}
return true;
}

启用ShardingSphere-Proxy

测试弹性库容、需要基于Proxy进行;

下载Proxy

下载源码编译:

1
2
3
4
5
6
7
git clone https://gitee.com/Sharding-Sphere/sharding-sphere.git

cd sharding-sphere

mvn clean install -Dmaven.javadoc.skip=true -Dcheckstyle.skip=true -Drat.skip=true -Djacoco.skip=true -DskipITs -DskipTests -Prelease

mv shardingsphere-distribution/shardingsphere-proxy-distribution/target/apache-shardingsphere-5.0.1-SNAPSHOT-shardingsphere-proxy-bin.tar.gz /mnt/d/application/

直接下载:

1
# 下载地址:https://github.com/apache/shardingsphere/archive/refs/tags/5.0.0.tar.gz

配置Proxy

解压软件

1
2
3
cd  /mnt/d/application/
# 解压文件
tar -zxvf apache-shardingsphere-5.0.1-SNAPSHOT-shardingsphere-proxy-bin.tar.gz

修改conf/server.yaml

1
2
3
4
5
6
7
8
9
10
11
12
# 打开所有配置的注解 # 

# 修改 mode
mode:
type: Standalone
repository:
type: File
props:
path: /mnt/d/sharding_config.yaml
overwrite: true

# 其他保持不变

修改 conf/config-sharding.yaml

1
2
3
# 打开mysql相关配置注解
# 修改 对应数据源
# 修改 对应表的规则

启动Proxy

1
2
3
4
5
## 参考:https://shardingsphere.apache.org/document/5.0.0/cn/quick-start/shardingsphere-proxy-quick-start/
bin/start.sh

# 查看启动日志
tail -f logs/stdout.log

登录Proxy

1
2
3
# 注意 用localhost 会直接链接到mysql里面而非 proxy ,用127.0.0.1 替换
# mysql -u${proxy_username} -p${proxy_password} -h${proxy_host} -P${proxy_port}
mysql -uroot -proot -hlocalhost -P 3307

弹性扩容

确定scaling是否可用

1
2
3
4
5
6
7
8
9
10
11
12
# 在mysql客户端

show scaling list ;

# 提示 Empty set (0.05 sec) 、可用

# 提示 mode 必须配置 ,修改server.xml配置文件
# 必须时cluster模式
mode.type = Cluster
# Cluster模式无法启动
# wsl 下 IpUtil.getIp 无法获取 ip
# 在 cmd 中启动

弹性扩容案例

默认数据源以配置文件形式存在

1
conf/config-sharding.yaml

数据源调整

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
# 显示数据源 
SHOW SCHEMA RESOURCES ;

ADD RESOURCE ds_20 (
URL="jdbc:mysql://127.0.0.1:3306/test20?serverTimezone=UTC&useSSL=false",
USER=root,
PASSWORD=root,
PROPERTIES("maximumPoolSize"=10,"idleTimeout"="30000")
);
ADD RESOURCE ds_21 (
URL="jdbc:mysql://127.0.0.1:3306/test21?serverTimezone=UTC&useSSL=false",
USER=root,
PASSWORD=root,
PROPERTIES("maximumPoolSize"=10,"idleTimeout"="30000")
);
ADD RESOURCE ds_22 (
URL="jdbc:mysql://127.0.0.1:3306/test22?serverTimezone=UTC&useSSL=false",
USER=root,
PASSWORD=root,
PROPERTIES("maximumPoolSize"=10,"idleTimeout"="30000")
);

算法调整

1
2
3
4
5
6
7
# 非必须、自动分表时不需要

#显示算法
show SHARDING ALGORITHMS;

#增加算法
CREATE SHARDING ALGORITHM data_mod(TYPE(NAME=MOD,PROPERTIES("sharding-count"=20)))

分片调整

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
#显示算法
show SHARDING TABLE RULES;

# 修改tb_news 分片算法
ALTER SHARDING TABLE RULE tb_news (
DATANODES("ds_20.tb_news"),
DATABASE_STRATEGY(TYPE=standard,SHARDING_COLUMN="id",SHARDING_ALGORITHM="data_mod"),
TABLE_STRATEGY(TYPE=standard,SHARDING_COLUMN="id",SHARDING_ALGORITHM="tb_news_inline"),
GENERATED_KEY(COLUMN=id,TYPE(NAME=snowflake,PROPERTIES("worker-id"=123)))
);

# 自动分片算法
ALTER SHARDING TABLE RULE tb_news (
RESOURCES("ds_20","ds_21","ds_22"),
SHARDING_COLUMN="id",
TYPE(NAME=hash_mod , PROPERTIES("sharding-count"=10)),
GENERATED_KEY(COLUMN=id,TYPE(NAME=snowflake,PROPERTIES("worker-id"=123)))
);

同步任务

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
# 任务列表
show scaling list;

# 任务详情
show scaling status {jobId};

# 查看算法是否生效

preview select count(1) from tb_news;

# 何时算是完成扩容?
# 全量数据迁移完成、增量数据迁移完成

# 何时切换到新的规则?
# 任务完成数据校验后,会自动迁移到新的规则;也可以手动完成;

正常流程:
# 1.1、校验数据
check scaling {jobId};
#1.2、切换数据源
checkout scaling {jobId}
# >>Data consistency check not finished or failed.


#手动停止
stop scaling {jobId}

#需要的话可以再开启
start scaling {jobId}

#不需要就删掉
drop scaling {jobId}

坑位:

1、广播表 没有自动同步;
2、增量同步只支持mysql 5.1-5.7 的版本;
3、切换数据源 必须先进行检查
4、直接删除废旧的规则也能触发自动切换数据源

1
2
#删除旧的分片算法后生效的
drop sharding algorithm database_inline;