ShardingSphere5详细笔记
目录
一、介绍
1、读写分离
2、CAP理论
3、数据库分片
(1)垂直分片
(2)水平分片
4、ShardingSphere介绍
二、数据库搭建
1、同步原理
2、win搭建双主模式
(1)下载MySQL
(2)搭建主库
1)创建my.ini文件
2)初始化
3)安装mysql
4)启动或停止服务
5)修改root密码
(3)搭建从库
1)创建my.ini文件
2)初始化
3)安装MySQL
4)启动
5)修改root密码
(4)搭建互为主从
1)修改master和slave的my.ini文件
2)创建同步账号
3)查看二进制日志状态
4)配置主从
5)启动复制
3、docker搭建一主多从模式
(1)设计
(2)docker安装MySQL
1)docker安装MySQL主服务器(3306)
编辑 2)docker安装MySQL从服务请求(3307)
编辑 3)启动主从同步
4)实现主从同步
三、ShardingSphere-JDBC详解
1、ShardingSphere-JDBC读写分离
(1)创建工程
(2)添加依赖
(3)创建实体类
(4)创建Mapper
(5)配置读写分离
(6)测试
2、ShardingSphere-JDBC垂直分片
(1)搭建服务器
1)设计
2)创建容器
(2)程序创建
1)创建实体类order
2)创建mapper
3)配置垂直分片配置文件
4)测试
5)异常
3、ShardingSphere-JDBC水平分片
(1)搭建服务器
1)设计
2)创建容器
(2)基本水平分片
(3)行表达式
(4)分布式序列算法
(5)多表关联
(6)绑定表
(7)广播表
四、ShardingSphere-Proxy详解
1、安装
(1)二进制包方式安装
1)下载解压二进制包
2)引入数据库驱动
3)修改配置文件
4)启动
5)连接
(2)docker方式安装
1)创建容器
2)上传数据库驱动
3)修改配置文件
4)重启容器
5)连接
2、ShardingSphere-Proxy读写分离
(1)修改配置文件
(2)重启容器
(3)查看实时日志
(4)搭建工程
1)创建工程sharding-proxy-demo
2)添加依赖
3)创建实体类
4)创建mapper
5)添加配置文件
6)测试
3、ShardingSphere-Proxy垂直分片
(1)修改配置文件
(2)重启容器后查看日志
(3)访问测试
4、ShardingSphere-Proxy水平分片
(1)修改配置文件
(2)重启容器后查看日志
(3)访问测试
五、安装docker
1、查看内核
2、查看Centos版本信息
3、 安装软件包
编辑 4、设置docker下载镜像
编辑 5、更新yum软件包索引
6、安装docker ce
7、启动docker
8、查看版本
9、设置开机启动
10、卸载
六、附录
1、附录一
(1)问题
(2)解决
(3)重启
2、附录二:分片策略与算法
(1)分片策略
1)标准分片策略
2)复合分片策略
3)Hint分片策略
4)行表达式分片策略
5)不分片
(2)分片算法
1)自动化分片算法
《1》取模算法(MOD)
《2》哈希取模算法(HASH_MOD)
《3》容量范围取模算法(VOLUME_RANGE)
《4》边界范围取模算法(BOUNDARY_RANGE)
《5》时间分片算法(AUTO_INTERVAL)
2)自定义分片算法
《1》标准分片算法
1.1、行表达式算法(INLINE)
1.2、时间范围分片算法(INTERVAL)
《2》COSID 散列分片算法
COSID_MOD取模
COSID_INTERVAL时间范围
COSID_INTERVAL_SNOWFLAKE
《3》复合分片算法
COMPLEX_INLINE
《4》Hint 分片算法
HINT_INLINE
一、介绍
1、读写分离
将数据库读写操作分散到不同的节点上
优势:
主库负责处理事务性的增删改操作,从库负责处理查询操作
,能够有效的避免由数据更新导致的行锁,使得整个系统的查询性能得到极大的改善。读写分离是
根据 SQL 语义的分析
,将读操作和写操作分别路由至主库与从库
。通过
一主多从
的配置方式,可以将查询请求均匀的分散到多个数据副本,能够进一步的提升系统的处理能力。使用
多主多从
的方式,不但能够提升系统的吞吐量,还能够提升系统的可用性,可以达到在任何一个数据库宕机,甚至磁盘物理损坏的情况下仍然不影响系统的正常运行。
2、CAP理论
在一个分布式系统中,当涉及读写操作时,只能保证一致性(Consistence)、可用性(Availability)、分区容错性(Partition Tolerance)三者中的两个,另外一个必须被牺牲。
C 一致性(Consistency):对某个指定的客户端来说,读操作保证能够返回最新的写操作结果
A 可用性(Availability):非故障的节点在合理的时间内返回合理的响应
(不是错误和超时的响应)
P 分区容忍性(Partition Tolerance):当出现网络分区后
(可能是丢包,也可能是连接中断,还可能是拥塞)
,系统能够继续“履行职责”
3、数据库分片
将存放在单一数据库中的数据分散地存放至多个数据库或表中,以达到提升性能瓶颈以及可用性的效果。 数据分片的有效手段是对关系型数据库进行分库和分表。数据分片的拆分方式又分为垂直分片和水平分片
。
(1)垂直分片
- 垂直分库
按照业务拆分的方式称为垂直分片,又称为纵向拆分
,它的核心理念是专库专用。 在拆分之前,一个数据库由多个数据表构成,每个表对应着不同的业务。而拆分之后,则是按照业务将表进行归类,分布到不同的数据库中,从而将压力分散至不同的数据库。
垂直分库可以缓解数据量和访问量带来的问题,但无法根治。如果垂直拆分之后,表中的数据量依然超过单节点所能承载的阈值,则需要水平分片来进一步处理。
- 垂直分表
垂直分表适合将表中某些不常用的列或者是占用了大量空间的列拆分出去。
假设有一张用户表,在筛选他用户的时候,主要是用 age 和 sex 两个字段进行查询,而 nickname 和 description 两个字段主要用于展示,一般不会在业务查询中用到。description 本身又比较长,因此我们可以将这两个字段独立到另外一张表中,这样在查询 age 和 sex 时,就能带来一定的性能提升。
垂直分表引入的复杂性主要体现在表操作的数量要增加。例如,原来只要一次查询就可以获取 name、age、sex、nickname、description,现在需要两次查询,一次查询获取 name、age、sex,另外一次查询获取 nickname、description。
(2)水平分片
水平分片又称为横向拆分。
相对于垂直分片,它不再将数据根据业务逻辑分类,而是通过某个字段(或某几个字段),根据某种规则将数据分散至多个库或表中,每个分片仅包含数据的一部分。 例如:根据主键分片,偶数主键的记录放入 0 库(或表),奇数主键的记录放入 1 库(或表)。
水平分表:单表切分为多表后,新的表即使在同一个数据库服务器中,也可能带来可观的性能提升,如果性能能够满足业务要求,可以不拆分到多台数据库服务器,毕竟业务分库也会引入很多复杂性;
水平分库:如果单表拆分为多表后,单台服务器依然无法满足性能要求,那就需要将多个表分散在不同的数据库服务器中。
4、ShardingSphere介绍
Apache ShardingSphere 由 JDBC、Proxy 和 Sidecar(规划中)这 3 款既能够独立部署,又支持混合部署配合使用的产品组成。
(1)ShardingSphere-JDBC(程序代码封装)
定位为轻量级 Java 框架,在 Java 的 JDBC 层提供的额外服务
。 它使用客户端直连数据库,以 jar 包形式提供服务
,无需额外部署和依赖,可理解为增强版的 JDBC 驱动,完全兼容 JDBC 和各种 ORM 框架。
(2)ShardingSphere-Proxy(中间件封装)
定位为透明化的数据库代理端
,提供封装了数据库二进制协议的服务端版本,用于完成对异构语言的支持。 目前提供 MySQL 和 PostgreSQL版本,它可以使用任何兼容 MySQL/PostgreSQL 协议的访问客户端(如:MySQL Command Client, MySQL Workbench, Navicat 等)操作数据,对 DBA 更加友好。
二、数据库搭建
1、同步原理
-
master将数据改变记录到
二进制日志(binary log)
中。 -
当slave上执行
start slave
命令之后,slave会创建一个IO 线程
用来连接master,请求master中的binlog。 -
当slave连接master时,master会创建一个
log dump 线程
,用于发送 binlog 的内容。在读取 binlog 的内容的操作中,会对主节点上的 binlog 加锁,当读取完成并发送给从服务器后解锁。 -
IO 线程接收主节点 binlog dump 进程发来的更新之后,保存到
中继日志(relay log)
中。 -
s
slave的SQL线程
,读取relay log日志,并解析成具体操作,从而实现主从操作一致,最终数据一致。
2、win搭建双主模式
(1)下载MySQL
本次使用的是mysql-8.0.41-winx64,将文件解压
(2)搭建主库
1)创建my.ini文件
[mysqld]
# 基础配置
port=3310
basedir=D:/soft/mysql8/master
datadir=D:/soft/mysql8/master/data
socket=mysql3310.sock# 服务器id(每个实例必须不同)
server-id=10# 日志配置
log-error=D:/soft/mysql8/master/mysql.err
pid-file=D:/soft/mysql8/master/mysql.pid# 其他常用配置
character-set-server=utf8mb4
default-storage-engine=INNODB# 允许最大连接数
max_connections=200
# 允许连接失败的次数。
max_connect_errors=10#是否开启慢查询,ON是开启
slow_query_log = ON
#慢查询阈值(秒)
long_query_time = 0.5# 临时表大小
tmp_table_size = 128M
# 用户可以创建的内存表的最大大小
max_heap_table_size = 128M
# 缓冲池的大小
innodb_buffer_pool_size = 3G
# InnoDB 日志刷新策略
innodb_flush_log_at_trx_commit = 0
# 用于控制group_concat返回最大长度,默认1024
group_concat_max_len = 10240
# 控制InnoDB表空间自动扩展的参数
innodb_autoextend_increment = 256
# InnoDB 日志缓冲区大小
innodb_log_file_size = 64M
# 用于指定连接缓冲区大小的参数
join_buffer_size = 128M
# 用于置顶排序的缓冲区大小的参数
sort_buffer_size = 64M
# 这个参数用在sort查询之后 ,以保证获取以顺序的方式获取到查询的数据。是上面参数的补充
read_rnd_buffer_size = 64M# 语法校验规则
sql_mode=STRICT_TRANS_TABLES,NO_ZERO_IN_DATE,NO_ZERO_DATE,ERROR_FOR_DIVISION_BY_ZERO,NO_ENGINE_SUBSTITUTION[mysql]
default-character-set=utf8mb4[client]
port=3310
default-character-set=utf8mb4
2)初始化
以管理员的身份运行
mysqld --defaults-file=D:\soft\mysql8\master\my.ini --initialize --console
或者
mysqld --initialize-insecure
或者指定同户名
mysqld --initialize-insecure --user=mysql说明:--initialize-insecure:不初始化密码--initialize:初始化一个默认密码--console:控制台输出--user:指定用户名
3)安装mysql
mysqld --install mysql_m --defaults-file=D:\soft\mysql8\master\my.ini
4)启动或停止服务
-- 启动服务
net start mysql_m
-- 停止服务
net stop mysql_m
5)修改root密码
ALTER USER 'root'@'localhost' IDENTIFIED BY '新密码';
-- 刷新
FLUSH PRIVILEGES;
(3)搭建从库
1)创建my.ini文件
[mysqld]
# 基础配置
port=3311
basedir=D:/soft/mysql8/slave
datadir=D:/soft/mysql8/slave/data
socket=mysql3311.sock# 服务器id(每个实例必须不同)
server-id=11# 日志配置
log-error=D:/soft/mysql8/slave/mysql.err
pid-file=D:/soft/mysql8/slave/mysql.pid# 其他常用配置
character-set-server=utf8mb4
default-storage-engine=INNODB# 允许最大连接数
max_connections=200
# 允许连接失败的次数。
max_connect_errors=10#是否开启慢查询,ON是开启
slow_query_log = ON
#慢查询阈值(秒)
long_query_time = 0.5# 临时表大小
tmp_table_size = 128M
# 用户可以创建的内存表的最大大小
max_heap_table_size = 128M
# 缓冲池的大小
innodb_buffer_pool_size = 3G
# InnoDB 日志刷新策略
innodb_flush_log_at_trx_commit = 0
# 用于控制group_concat返回最大长度,默认1024
group_concat_max_len = 10240
# 控制InnoDB表空间自动扩展的参数
innodb_autoextend_increment = 256
# InnoDB 日志缓冲区大小
innodb_log_file_size = 64M
# 用于指定连接缓冲区大小的参数
join_buffer_size = 128M
# 用于置顶排序的缓冲区大小的参数
sort_buffer_size = 64M
# 这个参数用在sort查询之后 ,以保证获取以顺序的方式获取到查询的数据。是上面参数的补充
read_rnd_buffer_size = 64M# 语法校验规则
sql_mode=STRICT_TRANS_TABLES,NO_ZERO_IN_DATE,NO_ZERO_DATE,ERROR_FOR_DIVISION_BY_ZERO,NO_ENGINE_SUBSTITUTION[mysql]
default-character-set=utf8mb4[client]
port=3311
default-character-set=utf8mb4
2)初始化
以管理员的身份运行
mysqld --defaults-file=D:\soft\mysql8\slave\my.ini --initialize --console
3)安装MySQL
mysqld --install mysql_s --defaults-file=D:\soft\mysql8\slave\my.ini
4)启动
net start mysql_s
5)修改root密码
ALTER USER 'root'@'localhost' IDENTIFIED BY '新密码';
-- 刷新
FLUSH PRIVILEGES;
(4)搭建互为主从
1)修改master和slave的my.ini文件
master的my.ini文件
[mysqld]
... 增加如下设置
log-bin=mysql-bin
# 可以多个 binlog-do-db
binlog-do-db=db_test
# 排除系统库
binlog-ignore-db=mysql
auto_increment_increment=2
auto_increment_offset=1
slave的my.ini文件
[mysqld]
...增加如下配置
log-bin=mysql-bin
binlog-do-db=db_test
binlog-ignore-db=mysql
auto_increment_increment=2
auto_increment_offset=2
server-id必须唯一
auto_increment_increment和auto_increment_offset避免双主模式自增id冲突
log-bin打开二进制日志
改完后重启master和slave数据库
2)创建同步账号
在master创建slave同步账号,在master上执行如下sql:
-- 创建slave用户
CREATE USER 'hk_slave'@'%';
-- 设置密码
ALTER USER 'hk_slave'@'%' IDENTIFIED WITH mysql_native_password BY '123456';
-- 授予复制权限
GRANT REPLICATION SLAVE ON *.* TO 'hk_slave'@'%';
-- 刷新权限
FLUSH PRIVILEGES;
在slave创建master同步账号,在slave上执行如下sql:
-- 创建master用户
CREATE USER 'hk_master'@'%';
-- 设置密码
ALTER USER 'hk_master'@'%' IDENTIFIED WITH mysql_native_password BY '123456';
-- 授予复制权限
GRANT REPLICATION SLAVE ON *.* TO 'hk_master'@'%';
-- 刷新权限
FLUSH PRIVILEGES;
3)查看二进制日志状态
查看master
SHOW MASTER STATUS;
查看slave
4)配置主从
在slave上设置master为主,在slave上执行如下sql:
CHANGE MASTER TO MASTER_HOST='192.168.1.10',MASTER_PORT=3310,MASTER_USER='hk_slave',MASTER_PASSWORD='123456',MASTER_LOG_FILE='mysql-bin.000001',MASTER_LOG_POS=1080;
在master上设置slave为主,在master上执行如下sql:
CHANGE MASTER TO MASTER_HOST='192.168.1.10',MASTER_PORT=3311,MASTER_USER='hk_master',MASTER_PASSWORD='123456',MASTER_LOG_FILE='mysql-bin.000001',MASTER_LOG_POS=1083;
5)启动复制
在master和slave上都执行如下sql:
START SLAVE;
查看状态:
SHOW SLAVE STATUS\G
重点看:
Slave_IO_Running: Yes
Slave_SQL_Running: Yes
如果都是
Yes
,就说明 互为主从成功了!
master上查看状态:
slave上查看状态:
3、docker搭建一主多从模式
(1)设计
主服务器:容器名mysql-master
,端口3306
从服务器:容器名mysql-slave1
,端口3307
从服务器:容器名mysql-slave2
,端口3308
(2)docker安装MySQL
如果没有安装docker,需要先安装docker
1)docker安装MySQL主服务器(3306)
- 创建并启动容器
docker run -d \
-p 3306:3306 \
-v /opt/mysql/master/conf:/etc/mysql/conf.d \
-v /opt/mysql/master/data:/var/lib/mysql \
-e MYSQL_ROOT_PASSWORD=123456 \
--name mysql-master \
mysql:8.0.29
如果出现如下错误:解决方案查看附录一
- 创建MySQL主服务器配置文件
vim /opt/mysql/master/conf/my.cnf
内容如下
[mysqld]
# 服务器唯一id,默认值1
server-id=1
# 设置日志格式,默认值ROW
binlog_format=STATEMENT
# 二进制日志名,默认binlog
# log-bin=binlog
# 设置需要复制的数据库,默认复制全部数据库
#binlog-do-db=mytestdb
# 设置不需要复制的数据库
#binlog-ignore-db=mysql
#binlog-ignore-db=infomation_schema
binlog格式说明:
binlog_format=STATEMENT:日志记录的是主机数据库的
写指令
,性能高,但是now()之类的函数以及获取系统参数的操作会出现主从数据不同步的问题。binlog_format=ROW(默认):日志记录的是主机数据库的
写后的数据
,批量操作时性能较差,解决now()或者 user()或者 @@hostname 等操作在主从机器上不一致的问题。binlog_format=MIXED:是以上两种level的混合使用,有函数用ROW,没函数用STATEMENT,但是无法识别系统变量
- 重启MySQL容器
docker restart mysql-master
- 使用命令行登录MySQL主服务器
#进入容器:env LANG=C.UTF-8 避免容器中显示中文乱码
docker exec -it mysql-master env LANG=C.UTF-8 /bin/bash
#进入容器内的mysql命令行
mysql -uroot -p
#修改默认密码校验方式
ALTER USER 'root'@'%' IDENTIFIED WITH mysql_native_password BY '123456';
- 主机中创建slave用户
-- 创建slave用户
CREATE USER 'hk_slave'@'%';
-- 设置密码
ALTER USER 'hk_slave'@'%' IDENTIFIED WITH mysql_native_password BY '123456';
-- 授予复制权限
GRANT REPLICATION SLAVE ON *.* TO 'hk_slave'@'%';
-- 刷新权限
FLUSH PRIVILEGES;
- 主机中查询master状态
SHOW MASTER STATUS;
2)docker安装MySQL从服务请求(3307)
可以配置多台从机slave1、slave2...,这里以配置slave1为例
- 创建并启动容器
docker run -d \
-p 3307:3306 \
-v /opt/mysql/slave1/conf:/etc/mysql/conf.d \
-v /opt/mysql/slave1/data:/var/lib/mysql \
-e MYSQL_ROOT_PASSWORD=123456 \
--name mysql-slave1 \
mysql:8.0.29
- 创建MySQL从服务器配置文件
vim /opt/mysql/slave1/conf/my.cnf
内容如下
[mysqld]
# 服务器唯一id,每台服务器的id必须不同,如果配置其他从机,注意修改id
server-id=2
# 中继日志名,默认xxxxxxxxxxxx-relay-bin
#relay-log=relay-bin
- 重启容器
docker restart mysql-slave1
- 使用命令登录MySQL从服务器
#进入容器:
docker exec -it mysql-slave1 env LANG=C.UTF-8 /bin/bash
#进入容器内的mysql命令行
mysql -uroot -p
#修改默认密码校验方式
ALTER USER 'root'@'%' IDENTIFIED WITH mysql_native_password BY '123456';
- 在从机上配置主从关系
对照主服务器配置 ,在从机上执行如下sql:
CHANGE MASTER TO MASTER_HOST='192.168.1.38',
MASTER_USER='hk_slave',MASTER_PASSWORD='123456', MASTER_PORT=3306,
MASTER_LOG_FILE='binlog.000003',MASTER_LOG_POS=1343;
3)启动主从同步
- 启动从机的复制功能,在从机执行SQL:
START SLAVE;
-- 查看状态(不需要分号)
SHOW SLAVE STATUS\G
- 可能出现的问题1:
Got fatal error 1236 from master when reading data from binary log: 'Client requested master to start replication from position > file size'
解决方案:
-- 在从机停止slave
STOP SLAVE;-- 在主机查看mater状态
SHOW MASTER STATUS;
-- 在主机刷新日志
FLUSH LOGS;
-- 再次在主机查看mater状态(会发现File和Position发生了变化)
SHOW MASTER STATUS;
-- 修改从机连接主机的SQL,并重新连接即可
4)实现主从同步
在主机中执行以下SQL,在从机中查看数据库、表和数据是否已经被同步
-- 创建数据库
CREATE DATABASE db_user;
-- 使用数据库
USE db_user;
-- 创建表
CREATE TABLE t_user (id BIGINT AUTO_INCREMENT,uname VARCHAR(30),PRIMARY KEY (id)
);
-- 插入数据
INSERT INTO t_user(uname) VALUES('zhang3');
INSERT INTO t_user(uname) VALUES(@@hostname);
- 5)停止和重置
-- 在从机上执行。功能说明:停止I/O 线程和SQL线程的操作。
stop slave; -- 在从机上执行。功能说明:用于删除SLAVE数据库的relaylog日志文件,并重新启用新的relaylog文件。
reset slave;-- 在主机上执行。功能说明:删除所有的binglog日志文件,并将日志索引文件清空,重新开始所有新的日志文件。
-- 用于第一次进行搭建主从库时,进行主库binlog初始化工作;
reset master;
三、ShardingSphere-JDBC详解
1、ShardingSphere-JDBC读写分离
(1)创建工程
(2)添加依赖
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"><modelVersion>4.0.0</modelVersion><groupId>com.hk.sharding-jdbc</groupId><artifactId>sharding-jdbc-demo</artifactId><version>1.0-SNAPSHOT</version><properties><java.version>1.8</java.version><project.build.sourceEncoding>UTF-8</project.build.sourceEncoding><project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding><spring-boot.version>2.3.7.RELEASE</spring-boot.version></properties><dependencies><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId></dependency><dependency><groupId>org.apache.shardingsphere</groupId><artifactId>shardingsphere-jdbc-core-spring-boot-starter</artifactId><version>5.1.1</version></dependency><dependency><groupId>mysql</groupId><artifactId>mysql-connector-java</artifactId><scope>runtime</scope></dependency><dependency><groupId>com.baomidou</groupId><artifactId>mybatis-plus-boot-starter</artifactId><version>3.3.1</version></dependency><dependency><groupId>org.projectlombok</groupId><artifactId>lombok</artifactId><optional>true</optional></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-test</artifactId><scope>test</scope><exclusions><exclusion><groupId>org.junit.vintage</groupId><artifactId>junit-vintage-engine</artifactId></exclusion></exclusions></dependency></dependencies><dependencyManagement><dependencies><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-dependencies</artifactId><version>${spring-boot.version}</version><type>pom</type><scope>import</scope></dependency></dependencies></dependencyManagement><build><plugins><plugin><groupId>org.apache.maven.plugins</groupId><artifactId>maven-compiler-plugin</artifactId><version>3.8.1</version><configuration><source>1.8</source><target>1.8</target><encoding>UTF-8</encoding></configuration></plugin><plugin><groupId>org.springframework.boot</groupId><artifactId>spring-boot-maven-plugin</artifactId><version>2.3.7.RELEASE</version><configuration><mainClass>com.hk.shardingjdbcdemo.ShardingJdbcDemoApplication</mainClass></configuration><executions><execution><id>repackage</id><goals><goal>repackage</goal></goals></execution></executions></plugin></plugins></build>
</project>
(3)创建实体类
@TableName("t_user")
@Data
public class User {@TableId(type = IdType.AUTO)private Long id;private String uname;
}
(4)创建Mapper
@Mapper
public interface UserMapper extends BaseMapper<User> {
}
(5)配置读写分离
application.yml
spring:# 应用名称application:name: sharding-jdbc-demoshardingsphere:# 内存模式mode:type: Memory# 配置数据源datasource:names: master,slave1# 配置第 1 个数据源master:type: com.zaxxer.hikari.HikariDataSourcedriver-class-name: com.mysql.jdbc.Driverjdbc-url: jdbc:mysql://192.168.1.38:3306/db_userusername: rootpassword: 123456# 配置第 2 个数据源slave1:type: com.zaxxer.hikari.HikariDataSourcedriver-class-name: com.mysql.jdbc.Driverjdbc-url: jdbc:mysql://192.168.1.38:3307/db_userusername: rootpassword: 123456# 配置读写分离类型rules:readwrite-splitting:data-sources:myds:type: Staticprops:# 写数据源名称write-data-source-name: master# 读数据源名称,多个从数据源用逗号分隔read-data-source-names: slave1# 负载均衡算法名称load-balancer-name: alg_round# 负载均衡算法配置# 负载均衡算法类型load-balancers:alg_round:type: ROUND_ROBINalg_random:type: RANDOMalg_weight:type: WEIGHTprops:slave1: 1# 打印SQlprops:sql-show: true
或者application.properties
# 应用名称
spring.application.name=sharding-jdbc-demo
# 内存模式
spring.shardingsphere.mode.type=Memory# 配置数据源
spring.shardingsphere.datasource.names=master,slave1# 配置第 1 个数据源
spring.shardingsphere.datasource.master.type=com.zaxxer.hikari.HikariDataSource
spring.shardingsphere.datasource.master.driver-class-name=com.mysql.jdbc.Driver
spring.shardingsphere.datasource.master.jdbc-url=jdbc:mysql://192.168.1.38:3306/db_user
spring.shardingsphere.datasource.master.username=root
spring.shardingsphere.datasource.master.password=123456# 配置第 2 个数据源
spring.shardingsphere.datasource.slave1.type=com.zaxxer.hikari.HikariDataSource
spring.shardingsphere.datasource.slave1.driver-class-name=com.mysql.jdbc.Driver
spring.shardingsphere.datasource.slave1.jdbc-url=jdbc:mysql://192.168.1.38:3306/db_user
spring.shardingsphere.datasource.slave1.username=root
spring.shardingsphere.datasource.slave1.password=123456# 读写分离类型,如: Static,Dynamic
spring.shardingsphere.rules.readwrite-splitting.data-sources.myds.type=Static
# 写数据源名称
spring.shardingsphere.rules.readwrite-splitting.data-sources.myds.props.write-data-source-name=master
# 读数据源名称,多个从数据源用逗号分隔
spring.shardingsphere.rules.readwrite-splitting.data-sources.myds.props.read-data-source-names=slave1# 负载均衡算法名称
spring.shardingsphere.rules.readwrite-splitting.data-sources.myds.load-balancer-name=alg_round# 负载均衡算法配置
# 负载均衡算法类型
spring.shardingsphere.rules.readwrite-splitting.load-balancers.alg_round.type=ROUND_ROBIN
spring.shardingsphere.rules.readwrite-splitting.load-balancers.alg_random.type=RANDOM
spring.shardingsphere.rules.readwrite-splitting.load-balancers.alg_weight.type=WEIGHT
spring.shardingsphere.rules.readwrite-splitting.load-balancers.alg_weight.props.slave1=1# 打印SQl
spring.shardingsphere.props.sql-show=true
(6)测试
- 测试新增
@SpringBootTest
public class ReadwriteTest {@Autowiredprivate UserMapper userMapper;/*** 写入数据的测试*/@Testpublic void testInsert(){User user = new User();user.setUname("张三丰");userMapper.insert(user);}
}
- 测试事务
为了保证主从库间的事务一致性,避免跨服务的分布式事务,ShardingSphere-JDBC的主从模型中,事务中的数据读写均用主库
。
不添加@Transactional:insert对主库操作,select对从库操作
添加@Transactional:则insert和select均对主库操作
注意:在JUnit环境下的@Transactional注解,默认情况下就会对事务进行回滚(即使在没加注解@Rollback,也会对事务回滚)
@Test@Transactionalpublic void testInsert2(){User user = new User();user.setUname("张三丰222");userMapper.insert(user);int i = 1/0;}
2、ShardingSphere-JDBC垂直分片
(1)搭建服务器
用docker创建server-user和server-order两个容器
1)设计
服务器:容器名server-user
,端口3301
服务器:容器名server-order
,端口3302
2)创建容器
《1》创建server-user容器
docker run -d \
-p 3301:3306 \
-v /opt/mysql/server/user/conf:/etc/mysql/conf.d \
-v /opt/mysql/server/user/data:/var/lib/mysql \
-e MYSQL_ROOT_PASSWORD=123456 \
--name server-user \
mysql:8.0.29
修改密码
#进入容器:
docker exec -it server-user env LANG=C.UTF-8 /bin/bash
#进入容器内的mysql命令行
mysql -uroot -p
#修改默认密码插件
ALTER USER 'root'@'%' IDENTIFIED WITH mysql_native_password BY '123456';
创建数据库
CREATE DATABASE db_user;
USE db_user;
CREATE TABLE t_user (id BIGINT AUTO_INCREMENT,uname VARCHAR(30),PRIMARY KEY (id)
);
《2》创建server-order容器
docker run -d \
-p 3302:3306 \
-v /opt/mysql/server/order/conf:/etc/mysql/conf.d \
-v /opt/mysql/server/order/data:/var/lib/mysql \
-e MYSQL_ROOT_PASSWORD=123456 \
--name server-order \
mysql:8.0.29
修改密码
#进入容器:
docker exec -it server-order env LANG=C.UTF-8 /bin/bash
#进入容器内的mysql命令行
mysql -uroot -p
#修改默认密码插件
ALTER USER 'root'@'%' IDENTIFIED WITH mysql_native_password BY '123456';
创建数据库
CREATE DATABASE db_order;
USE db_order;
CREATE TABLE t_order (id BIGINT AUTO_INCREMENT,order_no VARCHAR(30),user_id BIGINT,amount DECIMAL(10,2),PRIMARY KEY(id)
);
(2)程序创建
再上一工程的基础上进行实现
1)创建实体类order
@TableName("t_order")
@Data
public class Order {@TableId(type = IdType.AUTO)private Long id;private String orderNo;private Long userId;private BigDecimal amount;
}
2)创建mapper
@Mapper
public interface OrderMapper extends BaseMapper<Order> {
}
3)配置垂直分片配置文件
# 应用名称
spring.application.name=sharding-jdbc-demo# 配置数据源
spring.shardingsphere.datasource.names=server-user,server-order# 配置第 1 个数据源
spring.shardingsphere.datasource.server-user.type=com.zaxxer.hikari.HikariDataSource
spring.shardingsphere.datasource.server-user.driver-class-name=com.mysql.jdbc.Driver
spring.shardingsphere.datasource.server-user.jdbc-url=jdbc:mysql://192.168.1.38:3301/db_user
spring.shardingsphere.datasource.server-user.username=root
spring.shardingsphere.datasource.server-user.password=123456# 配置第 2 个数据源
spring.shardingsphere.datasource.server-order.type=com.zaxxer.hikari.HikariDataSource
spring.shardingsphere.datasource.server-order.driver-class-name=com.mysql.jdbc.Driver
spring.shardingsphere.datasource.server-order.jdbc-url=jdbc:mysql://192.168.1.38:3302/db_order
spring.shardingsphere.datasource.server-order.username=root
spring.shardingsphere.datasource.server-order.password=123456# 标准分片表配置(数据节点)
# spring.shardingsphere.rules.sharding.tables.<table-name>.actual-data-nodes=值
# 值由数据源名 + 表名组成,以小数点分隔。
# <table-name>:逻辑表名spring.shardingsphere.rules.sharding.tables.t_user.actual-data-nodes=server-user.t_user
spring.shardingsphere.rules.sharding.tables.t_order.actual-data-nodes=server-order.t_order# 打印SQl
spring.shardingsphere.props.sql-show=true
4)测试
@Autowiredprivate UserMapper userMapper;@Autowiredprivate OrderMapper orderMapper;// 垂直分片:插入数据测试@Testpublic void testInsertOrderAndUser(){User user = new User();user.setUname("李四");userMapper.insert(user);Order order = new Order();order.setOrderNo("LS001");order.setUserId(user.getId());order.setAmount(new BigDecimal(100));orderMapper.insert(order);}@Testpublic void testSelectFromOrderAndUser(){User user = userMapper.selectById(1L);Order order = orderMapper.selectById(1L);}
5)异常
ShardingSphere-JDBC远程连接的方式默认的密码加密规则是:mysql_native_password
因此需要在服务器端修改服务器的密码加密规则,如下:
ALTER USER 'root'@'%' IDENTIFIED WITH mysql_native_password BY '123456';
3、ShardingSphere-JDBC水平分片
(1)搭建服务器
用docker创建server-order0和server-order1两个容器
1)设计
服务器:容器名server-order0
,端口3310
服务器:容器名server-order1
,端口3311
2)创建容器
《1》创建server-order0容器
docker run -d \
-p 3310:3306 \
-v /opt/mysql/server/order0/conf:/etc/mysql/conf.d \
-v /opt/mysql/server/order0/data:/var/lib/mysql \
-e MYSQL_ROOT_PASSWORD=123456 \
--name server-order0 \
mysql:8.0.29
修改密码
#进入容器:
docker exec -it server-order0 env LANG=C.UTF-8 /bin/bash
#进入容器内的mysql命令行
mysql -uroot -p
#修改默认密码插件
ALTER USER 'root'@'%' IDENTIFIED WITH mysql_native_password BY '123456';
创建数据库,水平分片的id需要业务层实现,不能依赖数据库的主键自增
CREATE DATABASE db_order;
USE db_order;
CREATE TABLE t_order0 (id BIGINT,order_no VARCHAR(30),user_id BIGINT,amount DECIMAL(10,2),PRIMARY KEY(id)
);
CREATE TABLE t_order1 (id BIGINT,order_no VARCHAR(30),user_id BIGINT,amount DECIMAL(10,2),PRIMARY KEY(id)
);
《2》创建server-order1容器
docker run -d \
-p 3311:3306 \
-v /opt/mysql/server/order1/conf:/etc/mysql/conf.d \
-v /opt/mysql/server/order1/data:/var/lib/mysql \
-e MYSQL_ROOT_PASSWORD=123456 \
--name server-order1 \
mysql:8.0.29
修改密码
#进入容器:
docker exec -it server-order1 env LANG=C.UTF-8 /bin/bash
#进入容器内的mysql命令行
mysql -uroot -p
#修改默认密码插件
ALTER USER 'root'@'%' IDENTIFIED WITH mysql_native_password BY '123456';
创建数据库
CREATE DATABASE db_order;
USE db_order;
CREATE TABLE t_order0 (id BIGINT,order_no VARCHAR(30),user_id BIGINT,amount DECIMAL(10,2),PRIMARY KEY(id)
);
CREATE TABLE t_order1 (id BIGINT,order_no VARCHAR(30),user_id BIGINT,amount DECIMAL(10,2),PRIMARY KEY(id)
);
(2)基本水平分片
分片策略https://shardingsphere.apache.org/document/5.1.1/cn/features/sharding/concept/sharding/
1)修改配置文件
先只对t_order0表进行测试,使用行表达式主键id取模分片算法
# 应用名称
spring.application.name=sharding-jdbc-demo# 内存模式
spring.shardingsphere.mode.type=Memory# 配置数据源
spring.shardingsphere.datasource.names=server-user,server-order0,server-order1# 配置第 1 个数据源
spring.shardingsphere.datasource.server-user.type=com.zaxxer.hikari.HikariDataSource
spring.shardingsphere.datasource.server-user.driver-class-name=com.mysql.jdbc.Driver
spring.shardingsphere.datasource.server-user.jdbc-url=jdbc:mysql://192.168.1.38:3301/db_user
spring.shardingsphere.datasource.server-user.username=root
spring.shardingsphere.datasource.server-user.password=123456# 配置第 2 个数据源
spring.shardingsphere.datasource.server-order0.type=com.zaxxer.hikari.HikariDataSource
spring.shardingsphere.datasource.server-order0.driver-class-name=com.mysql.jdbc.Driver
spring.shardingsphere.datasource.server-order0.jdbc-url=jdbc:mysql://192.168.1.38:3310/db_order
spring.shardingsphere.datasource.server-order0.username=root
spring.shardingsphere.datasource.server-order0.password=123456# 配置第 3 个数据源
spring.shardingsphere.datasource.server-order1.type=com.zaxxer.hikari.HikariDataSource
spring.shardingsphere.datasource.server-order1.driver-class-name=com.mysql.jdbc.Driver
spring.shardingsphere.datasource.server-order1.jdbc-url=jdbc:mysql://192.168.1.38:3311/db_order
spring.shardingsphere.datasource.server-order1.username=root
spring.shardingsphere.datasource.server-order1.password=123456# 标准分片表配置(数据节点)
# spring.shardingsphere.rules.sharding.tables.<table-name>.actual-data-nodes=值
# 值由数据源名 + 表名组成,以小数点分隔。多个表以逗号分隔,支持 inline 表达式。
# <table-name>:逻辑表名spring.shardingsphere.rules.sharding.tables.t_user.actual-data-nodes=server-user.t_user
spring.shardingsphere.rules.sharding.tables.t_order.actual-data-nodes=server-order0.t_order0,server-order1.t_order0#-----分库策略
# 分片列名称
spring.shardingsphere.rules.sharding.tables.t_order.database-strategy.standard.sharding-column=id
# 分片算法名称
spring.shardingsphere.rules.sharding.tables.t_order.database-strategy..standard.sharding-algorithm-name=alg_inline_id#----分片算法配置
# 1、行表达式分片算法
# 分片算法类型
spring.shardingsphere.rules.sharding.sharding-algorithms.alg_inline_id.type=INLINE
# 分片算法属性配置
spring.shardingsphere.rules.sharding.sharding-algorithms.alg_inline_id.props.algorithm-expression=server-order$->{id % 2}# 打印SQl
spring.shardingsphere.props.sql-show=true
2)修改order实体类
@TableName("t_order")
@Data
public class Order {// 分表策略,主键不能自增@TableId(type = IdType.ASSIGN_ID)private Long id;private String orderNo;private Long userId;private BigDecimal amount;
}
3)测试
@Testpublic void testInsertOrder(){for (int i = 1; i <= 5; i++) {Order order = new Order();order.setOrderNo("lisi00"+i);order.setUserId(Long.parseLong(i+""));order.setAmount(new BigDecimal(100));orderMapper.insert(order);}}
详细的分片策略查看附录二
(3)行表达式
行表达式https://shardingsphere.apache.org/document/5.1.1/cn/features/sharding/concept/inline-expression/修改前:
# 标准分片表配置(数据节点)
# spring.shardingsphere.rules.sharding.tables.<table-name>.actual-data-nodes=值
# 值由数据源名 + 表名组成,以小数点分隔。多个表以逗号分隔,支持 inline 表达式。
# <table-name>:逻辑表名
spring.shardingsphere.rules.sharding.tables.t_user.actual-data-nodes=server-user.t_user
spring.shardingsphere.rules.sharding.tables.t_order.actual-data-nodes=server-order0.t_order0,server-order0.t_order1,server-order1.t_order0,server-order1.t_order1
修改后
# 标准分片表配置(数据节点)
# spring.shardingsphere.rules.sharding.tables.<table-name>.actual-data-nodes=值
# 值由数据源名 + 表名组成,以小数点分隔。多个表以逗号分隔,支持 inline 表达式。
# <table-name>:逻辑表名
spring.shardingsphere.rules.sharding.tables.t_user.actual-data-nodes=server-user.t_user
spring.shardingsphere.rules.sharding.tables.t_order.actual-data-nodes=server-order$->{0..1}.t_order$->{0..1}
(4)分布式序列算法
雪花算法https://shardingsphere.apache.org/document/5.1.1/cn/features/sharding/concept/key-generator/两种方案:二选一即可
基于mybatisplus的id策略
@TableId(type = IdType.ASSIGN_ID)private Long id;
基于ShardingSphere-JDBC的全局序列配置
# 应用名称
spring.application.name=sharding-jdbc-demo# 内存模式
spring.shardingsphere.mode.type=Memory# 打印SQl
spring.shardingsphere.props.sql-show=true# 配置数据源
spring.shardingsphere.datasource.names=server-user,server-order0,server-order1# 配置第 1 个数据源
spring.shardingsphere.datasource.server-user.type=com.zaxxer.hikari.HikariDataSource
spring.shardingsphere.datasource.server-user.driver-class-name=com.mysql.jdbc.Driver
spring.shardingsphere.datasource.server-user.jdbc-url=jdbc:mysql://192.168.1.38:3301/db_user
spring.shardingsphere.datasource.server-user.username=root
spring.shardingsphere.datasource.server-user.password=123456# 配置第 2 个数据源
spring.shardingsphere.datasource.server-order0.type=com.zaxxer.hikari.HikariDataSource
spring.shardingsphere.datasource.server-order0.driver-class-name=com.mysql.jdbc.Driver
spring.shardingsphere.datasource.server-order0.jdbc-url=jdbc:mysql://192.168.1.38:3310/db_order
spring.shardingsphere.datasource.server-order0.username=root
spring.shardingsphere.datasource.server-order0.password=123456# 配置第 3 个数据源
spring.shardingsphere.datasource.server-order1.type=com.zaxxer.hikari.HikariDataSource
spring.shardingsphere.datasource.server-order1.driver-class-name=com.mysql.jdbc.Driver
spring.shardingsphere.datasource.server-order1.jdbc-url=jdbc:mysql://192.168.1.38:3311/db_order
spring.shardingsphere.datasource.server-order1.username=root
spring.shardingsphere.datasource.server-order1.password=123456# 标准分片表配置(数据节点)
# spring.shardingsphere.rules.sharding.tables.<table-name>.actual-data-nodes=值
# 值由数据源名 + 表名组成,以小数点分隔。多个表以逗号分隔,支持 inline 表达式。
# <table-name>:逻辑表名
spring.shardingsphere.rules.sharding.tables.t_user.actual-data-nodes=server-user.t_user
spring.shardingsphere.rules.sharding.tables.t_order.actual-data-nodes=server-order$->{0..1}.t_order0#-----分库策略
# 分片列名称
spring.shardingsphere.rules.sharding.tables.t_order.database-strategy.standard.sharding-column=id
# 分片算法名称
spring.shardingsphere.rules.sharding.tables.t_order.database-strategy.standard.sharding-algorithm-name=alg_inline_id#-----分布式序列策略配置
# 分布式序列列名称
spring.shardingsphere.rules.sharding.tables.t_order.key-generate-strategy.column=id
# 分布式序列算法名称
spring.shardingsphere.rules.sharding.tables.t_order.key-generate-strategy.key-generator-name=alg_snowflake
# 分布式序列算法类型
spring.shardingsphere.rules.sharding.key-generators.alg_snowflake.type=SNOWFLAKE#----分片算法配置
# 行表达式分片算法
# 分片算法类型
spring.shardingsphere.rules.sharding.sharding-algorithms.alg_inline_id.type=INLINE
# 分片算法属性配置
spring.shardingsphere.rules.sharding.sharding-algorithms.alg_inline_id.props.algorithm-expression=server-order$->{id % 2}
@TableName("t_order")
@Data
public class Order {@TableId(type = IdType.AUTO)private Long id;private String orderNo;private Long userId;private BigDecimal amount;
}
(5)多表关联
同一用户的订单表和订单详情表的数据都在一个数据源中,避免跨库关联,因此这两张表我们使用相同的分片策略。
1)创建关联表
在`server-order0、server-order1`服务器中分别创建两张订单详情表`t_order_item0、t_order_item1`
CREATE TABLE t_order_item0(id BIGINT,order_no VARCHAR(30),user_id BIGINT,price DECIMAL(10,2),`count` INT,PRIMARY KEY(id)
);CREATE TABLE t_order_item1(id BIGINT,order_no VARCHAR(30),user_id BIGINT,price DECIMAL(10,2),`count` INT,PRIMARY KEY(id)
);
2)创建实体类
@TableName("t_order_item")
@Data
public class OrderItem {//当配置了shardingsphere-jdbc的分布式序列时,自动使用shardingsphere-jdbc的分布式序列@TableId(type = IdType.AUTO)private Long id;private String orderNo;private Long userId;private BigDecimal price;private Integer count;
}
3)创建mapper
@Mapper
public interface OrderItemMapper extends BaseMapper<OrderItem> {
}
4)配置关联表配置
# 应用名称
spring.application.name=sharding-jdbc-demo# 内存模式
spring.shardingsphere.mode.type=Memory# 打印SQl
spring.shardingsphere.props.sql-show=true# 配置数据源
spring.shardingsphere.datasource.names=server-user,server-order0,server-order1# 配置第 1 个数据源
spring.shardingsphere.datasource.server-user.type=com.zaxxer.hikari.HikariDataSource
spring.shardingsphere.datasource.server-user.driver-class-name=com.mysql.jdbc.Driver
spring.shardingsphere.datasource.server-user.jdbc-url=jdbc:mysql://192.168.1.38:3301/db_user
spring.shardingsphere.datasource.server-user.username=root
spring.shardingsphere.datasource.server-user.password=123456# 配置第 2 个数据源
spring.shardingsphere.datasource.server-order0.type=com.zaxxer.hikari.HikariDataSource
spring.shardingsphere.datasource.server-order0.driver-class-name=com.mysql.jdbc.Driver
spring.shardingsphere.datasource.server-order0.jdbc-url=jdbc:mysql://192.168.1.38:3310/db_order
spring.shardingsphere.datasource.server-order0.username=root
spring.shardingsphere.datasource.server-order0.password=123456# 配置第 3 个数据源
spring.shardingsphere.datasource.server-order1.type=com.zaxxer.hikari.HikariDataSource
spring.shardingsphere.datasource.server-order1.driver-class-name=com.mysql.jdbc.Driver
spring.shardingsphere.datasource.server-order1.jdbc-url=jdbc:mysql://192.168.1.38:3311/db_order
spring.shardingsphere.datasource.server-order1.username=root
spring.shardingsphere.datasource.server-order1.password=123456# 标准分片表配置(数据节点)
# spring.shardingsphere.rules.sharding.tables.<table-name>.actual-data-nodes=值
# 值由数据源名 + 表名组成,以小数点分隔。多个表以逗号分隔,支持 inline 表达式。
# <table-name>:逻辑表名
spring.shardingsphere.rules.sharding.tables.t_user.actual-data-nodes=server-user.t_user
spring.shardingsphere.rules.sharding.tables.t_order.actual-data-nodes=server-order$->{0..1}.t_order$->{0..1}#-----分库策略
# 分片列名称
spring.shardingsphere.rules.sharding.tables.t_order.database-strategy.standard.sharding-column=user_id
# 分片算法名称
spring.shardingsphere.rules.sharding.tables.t_order.database-strategy.standard.sharding-algorithm-name=alg_mod#----分表策略
# 分片列名称
spring.shardingsphere.rules.sharding.tables.t_order.table-strategy.standard.sharding-column=order_no
# 分片算法名称
spring.shardingsphere.rules.sharding.tables.t_order.table-strategy.standard.sharding-algorithm-name=alg_hash_mod#-----分布式序列策略配置
# 分布式序列列名称
spring.shardingsphere.rules.sharding.tables.t_order.key-generate-strategy.column=id
# 分布式序列算法名称
spring.shardingsphere.rules.sharding.tables.t_order.key-generate-strategy.key-generator-name=alg_snowflake
# 分布式序列算法类型
spring.shardingsphere.rules.sharding.key-generators.alg_snowflake.type=SNOWFLAKE#--------配置t_order_item表分片策略
#----标准分片表配置(数据节点配置)
spring.shardingsphere.rules.sharding.tables.t_order_item.actual-data-nodes=server-order$->{0..1}.t_order_item$->{0..1}
#----分库策略
# 分片列名称
spring.shardingsphere.rules.sharding.tables.t_order_item.database-strategy.standard.sharding-column=user_id
# 分片算法名称
spring.shardingsphere.rules.sharding.tables.t_order_item.database-strategy.standard.sharding-algorithm-name=alg_mod#----分表策略
# 分片列名称
spring.shardingsphere.rules.sharding.tables.t_order_item.table-strategy.standard.sharding-column=order_no
# 分片算法名称
spring.shardingsphere.rules.sharding.tables.t_order_item.table-strategy.standard.sharding-algorithm-name=alg_hash_mod#-----分布式序列策略配置
# 分布式序列列名称
spring.shardingsphere.rules.sharding.tables.t_order_item.key-generate-strategy.column=id
# 分布式序列算法名称
spring.shardingsphere.rules.sharding.tables.t_order_item.key-generate-strategy.key-generator-name=alg_snowflake#----分库算法
# 分片算法类型
spring.shardingsphere.rules.sharding.sharding-algorithms.alg_mod.type=MOD
spring.shardingsphere.rules.sharding.sharding-algorithms.alg_mod.props.sharding-count=2#----分片算法配置
# 行表达式分片算法
# 分片算法类型
spring.shardingsphere.rules.sharding.sharding-algorithms.alg_hash_mod.type=HASH_MOD
# 分片算法属性配置
spring.shardingsphere.rules.sharding.sharding-algorithms.alg_hash_mod.props.sharding-count=2
5)测试
@Testpublic void testInsertOrderAndOrderItem(){for (long i = 1; i < 6; i++) {String orderNo = "lisi-" + i;Long userId = i;Order order = new Order();order.setOrderNo(orderNo);order.setUserId(userId);orderMapper.insert(order);for (long j = 1; j < 3; j++) {OrderItem orderItem = new OrderItem();orderItem.setOrderNo(orderNo);orderItem.setUserId(userId);orderItem.setPrice(new BigDecimal(10));orderItem.setCount(2);orderItemMapper.insert(orderItem);}}}
(6)绑定表
绑定表https://shardingsphere.apache.org/document/4.0.1/cn/features/sharding/concept/table/
查询每个订单的订单号和总订单金额
1)创建对象
@Data
public class OrderVo {private String orderNo;private BigDecimal amount;
}
2)添加mapper查询方法
@Mapper
public interface OrderMapper extends BaseMapper<Order> {@Select({"select o.order_no, sum(i.price * i.count) as amount from t_order o join t_order_item i on o.order_no = i.order_no group by o.order_no"})List<OrderVo> getOrderAmount();
}
3)测试
@Testpublic void testGetOrderAmount(){List<OrderVo> orderAmountList = orderMapper.getOrderAmount();orderAmountList.forEach(System.out::println);}
此时会出现查询8条SQL
4)配置绑定表
# 在配置文件增加如下配置
#-----绑定表
spring.shardingsphere.rules.sharding.binding-tables[0]=t_order,t_order_item
再次测试,此时只出现查询4条SQL
5)说明
- 如果不配置绑定表:测试的结果为8个SQL。多表关联查询会出现笛卡尔积关联。
-
如果配置绑定表:测试的结果为4个SQL。 多表关联查询不会出现笛卡尔积关联,关联查询效率将大大提升。
绑定表:
指分片规则一致的一组分片表。 使用绑定表进行多表关联查询时,必须使用分片键进行关联,否则会出现笛卡尔积关联或跨库关联,从而影响查询效率。
(7)广播表
1)介绍
广播表:指所有的分片数据源中都存在的表,表结构及其数据在每个数据库中均完全一致。 适用于数据量不大且需要与海量数据的表进行关联查询的场景,例如:字典表。
广播具有以下特性:
- 插入、更新操作会实时在所有节点上执行,保持各个分片的数据一致性
- 查询操作,只从一个节点获取
- 可以跟任何一个表进行 JOIN 操作
2)创建广播表
在server-order0、server-order1和server-user服务器中分别创建t_dict表
CREATE TABLE t_dict(id BIGINT,dict_type VARCHAR(200),PRIMARY KEY(id)
);
3)创建实体
@TableName("t_dict")
@Data
public class Dict {//可以使用MyBatisPlus的雪花算法@TableId(type = IdType.ASSIGN_ID)private Long id;private String dictType;
}
4)创建mapper
@Mapper
public interface DictMapper extends BaseMapper<Dict> {
}
5)修改配置
===========增加如下配置===========#数据节点可不配置,默认情况下,向所有数据源广播
spring.shardingsphere.rules.sharding.tables.t_dict.actual-data-nodes=server-user.t_dict,server-order$->{0..1}.t_dict
# 广播表
spring.shardingsphere.rules.sharding.broadcast-tables[0]=t_dict
6)测试
@Testpublic void testBroadcast(){Dict dict = new Dict();dict.setDictType("type1");dictMapper.insert(dict);}
@Testpublic void testSelectBroadcast(){List<Dict> dicts = dictMapper.selectList(null);dicts.forEach(System.out::println);}
四、ShardingSphere-Proxy详解
1、安装
(1)二进制包方式安装
1)下载解压二进制包
各版本下载地址https://archive.apache.org/dist/shardingsphere/
2)引入数据库驱动
如果后端连接 PostgreSQL 或 openGauss 数据库,不需要引入额外依赖。
如果后端连接 MySQL 数据库,请下载 mysql-connector-java-5.1.49.jar 或者 mysql-connector-java-8.0.11.jar,并将其放入 ext-lib
目录。
3)修改配置文件
修改conf/server.yaml文件
rules:- !AUTHORITYusers:- root@%:root- sharding@:shardingprovider:type: ALL_PRIVILEGES_PERMITTED
props:sql-show: true
4)启动
Linux 操作系统请运行 bin/start.sh
Windows 操作系统请运行 bin/start.bat
5)连接
(2)docker方式安装
1)创建容器
docker run -d \
-v /opt/mysql/server/proxy-a/conf:/opt/shardingsphere-proxy/conf \
-v /opt/mysql/server/proxy-a/ext-lib:/opt/shardingsphere-proxy/ext-lib \
-e ES_JAVA_OPTS="-Xmx256m -Xms256m -Xmn128m" \
-p 3321:3307 \
--name server-proxy-a \
apache/shardingsphere-proxy:5.1.1
2)上传数据库驱动
将MySQL驱动上传至/opt/mysql/server/proxy-a/ext-lib目录
3)修改配置文件
在opt/mysql/server/proxy-a/conf修改或者新建server.yaml文件
rules:- !AUTHORITYusers:- root@%:root- sharding@:shardingprovider:type: ALL_PRIVILEGES_PERMITTED
props:sql-show: true
4)重启容器
docker restart server-proxy-a
5)连接
2、ShardingSphere-Proxy读写分离
(1)修改配置文件
修改config-readwrite-splitting.yaml文件
schemaName: readwrite_splitting_dbdataSources:write_ds:url: jdbc:mysql://192.168.1.38:3306/db_user?serverTimezone=UTC&useSSL=falseusername: rootpassword: 123456connectionTimeoutMilliseconds: 30000idleTimeoutMilliseconds: 60000maxLifetimeMilliseconds: 1800000maxPoolSize: 50minPoolSize: 1read_ds_0:url: jdbc:mysql://192.168.1.38:3307/db_user?serverTimezone=UTC&useSSL=falseusername: rootpassword: 123456connectionTimeoutMilliseconds: 30000idleTimeoutMilliseconds: 60000maxLifetimeMilliseconds: 1800000maxPoolSize: 50minPoolSize: 1
rules:
- !READWRITE_SPLITTINGdataSources:readwrite_ds:type: Staticprops:write-data-source-name: write_dsread-data-source-names: read_ds_0
(2)重启容器
docker restart server-proxy-a
(3)查看实时日志
docker exec -it server-proxy-a env LANG=C.UTF-8 /bin/bash
tail -f /opt/shardingsphere-proxy/logs/stdout.log
(4)搭建工程
1)创建工程sharding-proxy-demo
2)添加依赖
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"><modelVersion>4.0.0</modelVersion><groupId>com.hk.shardingproxydemo</groupId><artifactId>sharding-proxy-demo</artifactId><version>1.0-SNAPSHOT</version><properties><java.version>1.8</java.version><project.build.sourceEncoding>UTF-8</project.build.sourceEncoding><project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding><spring-boot.version>2.3.7.RELEASE</spring-boot.version></properties><dependencies><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId></dependency><dependency><groupId>mysql</groupId><artifactId>mysql-connector-java</artifactId><scope>runtime</scope></dependency><dependency><groupId>com.baomidou</groupId><artifactId>mybatis-plus-boot-starter</artifactId><version>3.3.1</version></dependency><dependency><groupId>org.projectlombok</groupId><artifactId>lombok</artifactId><optional>true</optional></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-test</artifactId><scope>test</scope><exclusions><exclusion><groupId>org.junit.vintage</groupId><artifactId>junit-vintage-engine</artifactId></exclusion></exclusions></dependency></dependencies><dependencyManagement><dependencies><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-dependencies</artifactId><version>${spring-boot.version}</version><type>pom</type><scope>import</scope></dependency></dependencies></dependencyManagement><build><plugins><plugin><groupId>org.apache.maven.plugins</groupId><artifactId>maven-compiler-plugin</artifactId><version>3.8.1</version><configuration><source>1.8</source><target>1.8</target><encoding>UTF-8</encoding></configuration></plugin><plugin><groupId>org.springframework.boot</groupId><artifactId>spring-boot-maven-plugin</artifactId><version>2.3.7.RELEASE</version><configuration><mainClass>com.hk.shardingproxydemo.ShardingProxyDemoApplication</mainClass></configuration><executions><execution><id>repackage</id><goals><goal>repackage</goal></goals></execution></executions></plugin></plugins></build>
</project>
3)创建实体类
@TableName("t_user")
@Data
public class entityUser {@TableId(type = IdType.AUTO)private Long id;private String uname;
}
4)创建mapper
@Mapper
public interface UserMapper extends BaseMapper<User> {
}
5)添加配置文件
# 应用名称
spring.application.name=sharding-proxy-demo# 开发环境设置
spring.profiles.active=dev#mysql数据库连接(proxy)
spring.datasource.driver-class-name=com.mysql.jdbc.Driver
spring.datasource.url=jdbc:mysql://192.168.1.38:3321/readwrite_splitting_db?serverTimezone=GMT%2B8&useSSL=false
spring.datasource.username=root
spring.datasource.password=root#mybatis日志
mybatis-plus.configuration.log-impl=org.apache.ibatis.logging.stdout.StdOutImpl
6)测试
@SpringBootTest
class ShardingProxyDemoTest {@Autowiredprivate UserMapper userMapper;@Testpublic void testSelectAll(){List<User> users = userMapper.selectList(null);users.forEach(System.out::println);}
}
3、ShardingSphere-Proxy垂直分片
(1)修改配置文件
修改配置config-sharding.yaml
schemaName: sharding_dbdataSources:ds_0:url: jdbc:mysql://192.168.1.38:3301/db_user?serverTimezone=UTC&useSSL=falseusername: rootpassword: 123456connectionTimeoutMilliseconds: 30000idleTimeoutMilliseconds: 60000maxLifetimeMilliseconds: 1800000maxPoolSize: 50minPoolSize: 1ds_1:url: jdbc:mysql://192.168.1.38:3302/db_order?serverTimezone=UTC&useSSL=falseusername: rootpassword: 123456connectionTimeoutMilliseconds: 30000idleTimeoutMilliseconds: 60000maxLifetimeMilliseconds: 1800000maxPoolSize: 50minPoolSize: 1rules:
- !SHARDINGtables:t_user:actualDataNodes: ds_0.t_usert_order:actualDataNodes: ds_1.t_order
(2)重启容器后查看日志
docker restart server-proxy-a
docker exec -it server-proxy-a env LANG=C.UTF-8 /bin/bash
tail -f /opt/shardingsphere-proxy/logs/stdout.log
(3)访问测试
mysql> show databases;
mysql> use sharding_db;
mysql> show tables;
mysql> select * from t_order;
mysql> select * from t_user;
4、ShardingSphere-Proxy水平分片
(1)修改配置文件
修改配置config-sharding.yaml
schemaName: sharding_dbdataSources:ds_user:url: jdbc:mysql://192.168.1.38:3301/db_user?serverTimezone=UTC&useSSL=falseusername: rootpassword: 123456connectionTimeoutMilliseconds: 30000idleTimeoutMilliseconds: 60000maxLifetimeMilliseconds: 1800000maxPoolSize: 50minPoolSize: 1ds_order0:url: jdbc:mysql://192.168.1.38:3310/db_order?serverTimezone=UTC&useSSL=falseusername: rootpassword: 123456connectionTimeoutMilliseconds: 30000idleTimeoutMilliseconds: 60000maxLifetimeMilliseconds: 1800000maxPoolSize: 50minPoolSize: 1ds_order1:url: jdbc:mysql://192.168.1.38:3311/db_order?serverTimezone=UTC&useSSL=falseusername: rootpassword: 123456connectionTimeoutMilliseconds: 30000idleTimeoutMilliseconds: 60000maxLifetimeMilliseconds: 1800000maxPoolSize: 50minPoolSize: 1rules:
- !SHARDINGtables:t_user:actualDataNodes: ds_user.t_usert_order:actualDataNodes: ds_order${0..1}.t_order${0..1}databaseStrategy:standard:shardingColumn: user_idshardingAlgorithmName: alg_modtableStrategy:standard:shardingColumn: order_noshardingAlgorithmName: alg_hash_modkeyGenerateStrategy:column: idkeyGeneratorName: snowflaket_order_item:actualDataNodes: ds_order${0..1}.t_order_item${0..1}databaseStrategy:standard:shardingColumn: user_idshardingAlgorithmName: alg_modtableStrategy:standard:shardingColumn: order_noshardingAlgorithmName: alg_hash_modkeyGenerateStrategy:column: idkeyGeneratorName: snowflakebindingTables:- t_order,t_order_itembroadcastTables:- t_dict shardingAlgorithms:alg_mod:type: MODprops:sharding-count: 2alg_hash_mod:type: HASH_MODprops:sharding-count: 2alg_inline_userid:type: INLINEprops:algorithm-expression: t_order_item_${order_id % 2}keyGenerators:snowflake:type: SNOWFLAKE
(2)重启容器后查看日志
docker restart server-proxy-a
docker exec -it server-proxy-a env LANG=C.UTF-8 /bin/bash
tail -f /opt/shardingsphere-proxy/logs/stdout.log
(3)访问测试
mysql> show databases;
mysql> use sharding_db;
mysql> show tables;
mysql> select * from t_order; --测试水平分片
mysql> select * from t_dict; --测试广播表
五、安装docker
Docker官网http://www.docker.com
Docker安装手册https://docs.docker.com/install/linux/docker-ce/centos
1、查看内核
Docker 运行在 CentOS 7 上,要求系统为64位、系统内核版本为 3.10 以上。
Docker 运行在 CentOS-6.5 或更高的版本的 CentOS 上,要求系统为64位、系统内核版本为 2.6.32-431 或者更高版本。
uname -r
2、查看Centos版本信息
cat /etc/redhat-release
3、 安装软件包
yum install -y yum-utils device-mapper-persistent-data lvm2
4、设置docker下载镜像
yum-config-manager --add-repo http://mirrors.aliyun.com/docker-ce/linux/centos/docker-ce.repo
5、更新yum软件包索引
在更新或配置yum源之后,通常都会使用yum makecache 生成缓存,这个命令是将软件包信息提前在本地缓存一份,用来提高搜索安装软件的速度
yum makecache fast
6、安装docker ce
yum install -y docker-ce
7、启动docker
systemctl start docker
8、查看版本
docker version
9、设置开机启动
#查看服务是否自动启动(是:enabled | 否:disabled)
systemctl list-unit-files|grep docker.service #设置开机启动:如不是enabled可以运行如下命令设置自启动
systemctl enable docker
#重新加载服务配置
systemctl daemon-reload #如果希望不进行自启动,运行如下命令设置
systemctl disable docker
#重新加载服务配置
systemctl daemon-reload
10、卸载
systemctl stop docker
yum remove -y docker-ce
rm -rf /var/lib/docker
六、附录
1、附录一
(1)问题
Error response from daemon: Get "https://registry-1.docker.io/v2/": net/http: request canceled while waiting for connection (Client.Timeout exceeded while awaiting headers)
类似错误
(2)解决
修改/etc/docker/daemon.json文件
vim /etc/docker/daemon.json
内容如下
{"registry-mirrors": ["https://docker.registry.cyou",
"https://docker-cf.registry.cyou",
"https://dockercf.jsdelivr.fyi",
"https://docker.jsdelivr.fyi",
"https://dockertest.jsdelivr.fyi",
"https://mirror.aliyuncs.com",
"https://dockerproxy.com",
"https://mirror.baidubce.com",
"https://docker.m.daocloud.io",
"https://docker.nju.edu.cn",
"https://docker.mirrors.sjtug.sjtu.edu.cn",
"https://docker.mirrors.ustc.edu.cn",
"https://mirror.iscas.ac.cn",
"https://docker.rainbond.cc"]
}
(3)重启
systemctl daemon-reload
systemctl restart docker
2、附录二:分片策略与算法
(1)分片策略
分片策略是
分片键
和分片算法
的组合策略,分片键确定了数据的拆分依据,分片算法则决定了如何对分片键值进行运算,将数据路由到哪个物理分片中。
ShardingSphere
对外提供了5种分片策略:
standard:标准分片策略
complex:复合分片策略
hint:hint分片策略
inline:行表达式分片策略
none:无策略
1)标准分片策略
适用于具有单一分片键的标准分片场景。该策略支持精确分片,即在SQL中包含=
、in
操作符,以及范围分片,包括BETWEEN AND
、>
、<
、>=
、<=
等范围操作符。该策略下有两个属性:分片字段shardingColumn
和算法名称shardingAlgorithmName
。
spring:shardingsphere:rules:sharding:tables:t_order: # 逻辑表名称# 数据节点:数据库.分片表actual-data-nodes: db_test$->{0..1}.t_order_$->{0..4}# 分库策略databaseStrategy: # 分库策略standard: # 用于单分片键的标准分片场景shardingColumn: order_id # 分片列名称shardingAlgorithmName: # 分片算法名称# 分表策略,同分库策略一致tableStrategy:
2)复合分片策略
复合分片策略适用于多个分片键的复杂分片场景,属性shardingColumns
中多个分片健以逗号分隔。支持 SQL 语句中有>
、>=
、<=
、<
、=
、IN
和 BETWEEN AND
等操作符。比如:希望通过user_id
和order_id
等多个字段共算出数据路由到具体哪个分片中,可以应用该策略。
spring:shardingsphere:rules:sharding:tables:t_order: # 逻辑表名称# 数据节点:数据库.分片表actual-data-nodes: db_test$->{0..1}.t_order_$->{0..4}# 分库策略databaseStrategy: # 分库策略complex: # 用于多分片键的复合分片场景shardingColumns: order_id,user_id # 分片列名称,多个列以逗号分隔shardingAlgorithmName: # 分片算法名称tableStrategy: # 分表策略,同分库策略
3)Hint分片策略
该策略无需配置分片健,由外部指定分库和分表的信息,可以让SQL在指定的分库、分表中执行。
使用场景:
分片字段不存在SQL和数据库表结构中,而存在于外部业务逻辑。
强制在指定数据库进行某些数据操作。
我们希望用
user_id
做分片健进行路由订单数据,但是t_order
表中也没user_id
这个字段,这时可以通过Hint API
手动指定分片库、表等信息,让数据插入指定的位置。
spring:shardingsphere:rules:sharding:tables:t_order: # 逻辑表名称# 数据节点:数据库.分片表actual-data-nodes: db_test$->{0..1}.t_order_$->{0..4}# 分库策略databaseStrategy: # 分库策略hint: # Hint 分片策略shardingAlgorithmName: # 分片算法名称tableStrategy: # 分表策略,同分库策略
4)行表达式分片策略
适用于具有单一分片键的简单分片场景,支持SQL语句中=
和in
操作符;该分片策略支持在配置属性algorithm-expression
中书写Groovy
表达式,用来定义对分片健的运算逻辑,无需单独定义分片算法。
spring:shardingsphere:rules:sharding:tables:t_order: # 逻辑表名称# 数据节点:数据库.分片表actual-data-nodes: db_test$->{0..1}.t_order_$->{0..4}# 分库策略databaseStrategy: # 分库策略inline: # 行表达式类型分片策略algorithm-expression: db_test$->{order_id % 2}tableStrategy: # 分表策略,同分库策略
5)不分片
对逻辑表的所有操作将会执行全库表路由
spring:shardingsphere:rules:sharding:tables:t_order: # 逻辑表名称# 数据节点:数据库.分片表actual-data-nodes: db_test$->{0..1}.t_order_$->{0..4}# 分库策略databaseStrategy: # 分库策略none: # 不分片tableStrategy: # 分表策略,同分库策略
(2)分片算法
ShardingSphere将分片算法分为两大类:自动化分片算法和自定义分片算法
自动化分片算法:包括取模、哈希、范围、时间等常用分片算法的实现。
自定义分片算法:
标准分片算法
、复合分片算法
和Hint 分片算法
1)自动化分片算法
《1》取模算法(MOD)
一种比较简单的算法,定义算法时类型MOD
,表达式大致(分片健 % sharding-count)
,它只有一个 props 属性sharding-count
代表分片表的数量。
spring:shardingsphere:rules:sharding:# 分片算法定义sharding-algorithms:t_order_table_mod:type: MOD # 取模分片算法props:# 指定分片数量sharding-count: 6tables:t_order: # 逻辑表名称actual-data-nodes: db_test$->{0..1}.t_order_$->{0..4}# 分库策略database-strategy:....# 分表策略table-strategy:standard:sharding-column: order_idsharding-algorithm-name: t_order_table_mod
《2》哈希取模算法(HASH_MOD)
是取模分片算法的一个升级版本,定义算法时类型为HASH_MOD
,props
属性的sharding-count
代表分片的数量。表达式(分片健的hash值 % sharding-count)
。
spring:shardingsphere:rules:sharding:# 分片算法定义sharding-algorithms:t_order_table_hash_mod:type: HASH_MOD # 哈希取模分片算法props:# 指定分片数量sharding-count: 6tables:t_order: # 逻辑表名称actual-data-nodes: db_test$->{0..1}.t_order_$->{0..2}# 分库策略database-strategy:....# 分表策略table-strategy:standard:sharding-column: order_idsharding-algorithm-name: t_order_table_hash_mod
《3》容量范围取模算法(VOLUME_RANGE)
基于分片容量的范围分片算法,依据数据容量来均匀分布到分片表中。它适用于数据增长趋势相对均匀,按分片容量将数据均匀地分布到不同的分片表中,可以有效避免数据倾斜问题;由于数据已经被按照范围进行分片,支持频繁进行范围查询场景。该算法支持动态的分片调整,可以根据实际业务数据的变化动态调整分片容量和范围,使得系统具备更好的扩展性和灵活性。
VOLUME_RANGE
算法主要有三个属性:range-lower: 分片键取值范围下界,超过边界的数据会报错
range-upper: 分片键范围上界,超过边界的数据会报错
sharding-volume: 分片容量 ,每个分片中存储的数据量
spring:shardingsphere:rules:sharding:sharding-algorithms:t_order_table_volume_range:type: VOLUME_RANGEprops:range-lower: 2 # 范围下界,超过边界的数据会报错range-upper: 20 # 范围上界,超过边界的数据会报错sharding-volume: 10 # 分片容量tables:t_order: # 逻辑表名称actual-data-nodes: db_test$->{0..1}.t_order_$->{0..2}# 分库策略database-strategy:....# 分表策略table-strategy:standard:sharding-column: order_idsharding-algorithm-name: t_order_table_volume_range
说明:分片健t_order_id
的值在界值 [range-lower,range-upper) 范围内,每个分片表最大存储 10 条数据;低于下界的值 [ 1,2 )
数据分布到 t_order_0,在界值范围内的数据 [ 2,20 )
遵循每满足 10 条依次放入 t_order_1、t_order_2;超出上界的数据[ 20,∞ )
即便前边的分片表里未满 10条剩下的也全部放在 t_order_3。
那么它的数据分布应该如下:
[ 0,2 )
数据分布到 t_order_0
[ 2,12 )
数据分布到 t_order_1
[ 12,20 )
数据分布到 t_order_2
[ 20,∞ )
数据分布到 t_order_3
《4》边界范围取模算法(BOUNDARY_RANGE)
基于分片边界的范围分片算法,和分片容量算法不同,该算法根据数据的取值范围进行分片,特别适合按数值范围频繁查询的场景。该算法只有一个属性sharding-ranges
为分片健值的范围区间。
spring:shardingsphere:rules:sharding:sharding-algorithms:# 基于分片边界的范围分片算法t_order_table_boundary_range:type: BOUNDARY_RANGEprops:sharding-ranges: 10,20,30,40 # 分片的范围边界,多个范围边界以逗号分隔tables:t_order: # 逻辑表名称actual-data-nodes: db_test$->{0..1}.t_order_$->{0..2}# 分库策略database-strategy:....# 分表策略table-strategy:standard:sharding-column: order_idsharding-algorithm-name: t_order_table_boundary_range
配置
sharding-ranges=10,20,30,40
,它的范围默认是从 0开始,范围区间前闭后开。配置算法以后执行建表语句,生成数据节点分布如:
[ 0,10 )
数据分布到t_order_0,
[ 10,20 )
数据分布到t_order_1,
[ 20,30 )
数据分布到t_order_2,
[ 30,40 )
数据分布到t_order_3,
[ 40,∞ )
数据分布到t_order_4。
《5》时间分片算法(AUTO_INTERVAL)
自动时间段分片算法,适用于以时间字段作为分片健的分片场景,和VOLUME_RANGE
基于容量的分片算法用法有点类似,不同的是AUTO_INTERVAL
依据时间段进行分片。
主要有三个属性:
datetime-lower:
分片健值开始时间(下界)时间格式:yyyy-MM-dd HH:mm:ss
datetime-upper:
分片健值结束时间(上界)时间格式:yyyy-MM-dd HH:mm:ss
sharding-seconds:
单一分片所能承载的最大时间,单位:秒,允许分片键的时间戳格式的秒带有时间精度,但秒后的时间精度会被自动抹去
spring:shardingsphere:rules:sharding:# 分片算法定义sharding-algorithms:# 自动时间段分片算法t_order_table_auto_interval:type: AUTO_INTERVALprops:datetime-lower: '2023-01-01 00:00:00' # 分片的起始时间范围,时间戳格式:yyyy-MM-dd HH:mm:ssdatetime-upper: '2025-01-01 00:00:00' # 分片的结束时间范围,时间戳格式:yyyy-MM-dd HH:mm:sssharding-seconds: 31536000 # 单一分片所能承载的最大时间,单位:秒,允许分片键的时间戳格式的秒带有时间精度,但秒后的时间精度会被自动抹去tables:# 逻辑表名称t_order:# 数据节点:数据库.分片表actual-data-nodes: db$->{0..1}.t_order_${0..2}# 分库策略database-strategy:...# 分表策略table-strategy:standard:sharding-column: order_datesharding-algorithm-name: t_order_table_auto_interval
分片健值在界值范围内 [datetime-lower,datetime-upper) 遵循每满足 sharding-seconds 时间段的数据放入对应分片表,超出界值的数据上下顺延到其他分片中。
它的数据分布应该如下:
[ 2023-01-01 00:00:00,2024-01-01 00:00:00 )
数据分布到 t_order_0,
[ 2024-01-01 00:00:00,2025-01-01 00:00:00 )
数据分布到 t_order_1,
[ 2025-01-01 00:00:00,2026-01-01 00:00:00 )
数据分布到 t_order_2。
[ 2026-01-01 00:00:00,∞ )
数据分布到 t_order_3。
2)自定义分片算法
《1》标准分片算法
1.1、行表达式算法(INLINE)
行表达式分片算法,适用于比较简单的分片场景,利用Groovy
表达式在算法属性内,直接书写分片逻辑,省略了配置和代码开发,只支持SQL语句中的 = 和 IN 的分片操作,只支持单分片键。
该算法有两属性:
algorithm-expression
:分片算法行表达式。
allow-range-query-with-inline-sharding
:是否允许范围查询,一旦开启范围查询会无视分片策略,进行全库表路由查询,这个要慎重开启!
spring:shardingsphere:# 具体规则配置rules:sharding:# 分片算法定义sharding-algorithms:# 标准分片算法# 行表达式分片算法t_order_table_inline:type: INLINEprops:algorithm-expression: t_order_$->{order_id % 3} # 分片算法的行表达式allow-range-query-with-inline-sharding: false # 是否允许范围查询。注意:范围查询会无视分片策略,进行全路由,默认 falsetables:# 逻辑表名称t_order:# 数据节点:数据库.分片表actual-data-nodes: db_test$->{0..1}.t_order_$->{0..2}# 分库策略database-strategy:standard:sharding-column: order_idsharding-algorithm-name: t_order_database_algorithms# 分表策略table-strategy:standard:sharding-column: order_idsharding-algorithm-name: t_order_table_inline
1.2、时间范围分片算法(INTERVAL)
时间范围分片算法,针对于时间字段(字符串类型)作为分片健的范围分片算法,适用于按照天、月、年这种固定区间的数据分片。使用其它时间分片算法时,用的都是t_order_n
后缀编号格式的分片表。但业务上往往需要的可能是按月、年t_order_yyyyMM
的这种分片表格式。时间范围分片算法(INTERVAL
),可以轻松实现这种场景。
属性说明:
datetime-pattern:分片健值的时间格式,必须是Java DateTimeFormatter类支持的转换类型,例如:yyyy-MM-dd HH-mm-ss 、yyyy-MM-dd、HH-mm-ss
datetime-lower:分片健值的下界,超过会报错,格式必须与
datetime-pattern
一致datetime-upper:分片健值的上界,超过会报错,格式必须与
datetime-pattern
一致sharding-suffix-pattern:分片表后缀名格式,yyyyMM、yyyyMMdd等格式,分片表格式的定义要结合
datetime-interval-unit
的单位,比如:t_order_yyyyMM
格式表示分片表存的月的数据,t_order_yyyy
格式表示分片表存的年的数据;datetime-interval-unit:分片间隔单位,超过该时间间隔将进入下一分片。它遵循 Java ChronoUnit 枚举,比如:
MONTHS
、DAYS
等;datetime-interval-amount:分片间隔数,和
datetime-interval-unit
是紧密配合使用;
spring:shardingsphere:rules:sharding:# 分片算法定义sharding-algorithms:t_order_database_mod:type: MODprops:sharding-count: 2 # 指定分片数量t_order_table_interval:type: INTERVALprops:datetime-pattern: "yyyy-MM-dd HH:mm:ss" # 分片字段格式datetime-lower: "2024-01-01 00:00:00" # 范围下限datetime-upper: "2024-06-30 23:59:59" # 范围上限sharding-suffix-pattern: "yyyyMM" # 分片名后缀,可以是MM,yyyyMMdd等。datetime-interval-amount: 1 # 分片间隔,这里指一个月datetime-interval-unit: "MONTHS" # 分片间隔单位tables:# 逻辑表名称t_order:# 数据节点:数据库.分片表actual-data-nodes: db_test$->{0..1}.t_order_$->{202401..202406}# 分库策略database-strategy:standard:sharding-column: order_idsharding-algorithm-name: t_order_database_mod# 分表策略table-strategy:standard:sharding-column: interval_valuesharding-algorithm-name: t_order_table_interval
用t_order_202401
~t_order_202406
6张分片表存储前半年的数据,每张分片表存储一个月的数据。interval_value
字段作为分片健,时间字符串类型,允许的分片值时间范围 2024-01-01 00:00:00~2024-06-30 23:59:59, 不在范围内插入报错。
《2》COSID 散列分片算法
ShardingSphere 提供了三种散列算法的CosId
(它是一款性能极高分布式ID生成器)分片算法,核心思想是通过散列算法对CosId生成的分布式ID和分片键值进行处理,以确定数据应该存放在哪个具体的数据节点上。
使用散列算法的优势,可以将数据按照一定规则映射到不同的数据节点上,能够确保数据的均匀分布,避免某些节点负载过重或者数据倾斜的情况。
COSID_MOD取模
基于 CosId 的取模分片算法和普通的MOD算法使用上略有不同,mod
为分片数量,logic-name-prefix
分片数据源或真实表的前缀格式
spring:shardingsphere:rules:sharding:# 分片算法定义sharding-algorithms:t_order_database_mod:type: MODprops:sharding-count: 2 # 指定分片数量# 8、基于 CosId 的取模分片算法t_order_table_cosid_mod:type: COSID_MODprops:mod: 3 # 分片数量logic-name-prefix: t_order_ # 分片数据源或真实表的前缀格式tables:# 逻辑表名称t_order:# 数据节点:数据库.分片表actual-data-nodes: db_test$->{0..1}.t_order_$->{0..2}# 分库策略database-strategy:standard:sharding-column: order_idsharding-algorithm-name: t_order_database_mod# 分表策略table-strategy:standard:sharding-column: order_idsharding-algorithm-name: t_order_table_cosid_mod
COSID_INTERVAL时间范围
基于 CosId 的固定时间范围的分片算法,和INTERVAL
算法的用法很相似,不同点在于增加了zone-id
时区属性。
属性说明:
zone-id:
时区,必须遵循 java.time.ZoneId的所含值。例如:Asia/Shanghai
logic-name-prefix:
分片数据源或真实表的前缀格式datetime-lower:分片健值的下界,超过会报错,格式必须与
datetime-pattern
一致datetime-upper:分片健值的上界,超过会报错,格式必须与
datetime-pattern
一致sharding-suffix-pattern:分片表后缀名格式,yyyyMM、yyyyMMdd等格式,分片表格式的定义要结合
datetime-interval-unit
的单位,比如:t_order_yyyyMM
格式表示分片表存的月的数据,t_order_yyyy
格式表示分片表存的年的数据;datetime-interval-unit:分片间隔单位,超过该时间间隔将进入下一分片。它遵循 Java ChronoUnit 枚举,比如:
MONTHS
、DAYS
等;datetime-interval-amount:分片间隔数,和
datetime-interval-unit
是紧密配合使用;
spring:shardingsphere:rules:sharding:# 分片算法定义sharding-algorithms:t_order_database_mod:type: MODprops:sharding-count: 2 # 指定分片数量# 基于 CosId 的固定时间范围的分片算法t_order_table_cosid_interval:type: COSID_INTERVALprops:zone-id: "Asia/Shanghai" # 时区,必须遵循 java.time.ZoneId 的所含值。 例如:Asia/Shanghailogic-name-prefix: t_order_ # 分片数据源或真实表的前缀格式sharding-suffix-pattern: "yyyyMM" # 分片数据源或真实表的后缀格式,必须遵循 Java DateTimeFormatter 的格式,必须和 datetime-interval-unit 保持一致。例如:yyyyMMdatetime-lower: "2024-01-01 00:00:00" # 时间分片下界值,格式与 yyyy-MM-dd HH:mm:ss 的时间戳格式一致datetime-upper: "2024-12-31 00:00:00" # 时间分片上界值,格式与 yyyy-MM-dd HH:mm:ss 的时间戳格式一致datetime-interval-unit: "MONTHS" # 分片键时间间隔单位,必须遵循 Java ChronoUnit 的枚举值。例如:MONTHSdatetime-interval-amount: 1 # 分片键时间间隔,超过该时间间隔将进入下一分片tables:# 逻辑表名称t_order:# 数据节点:数据库.分片表actual-data-nodes: db_test$->{0..1}.t_order_$->{202401..202412}# 分库策略database-strategy:standard:sharding-column: order_idsharding-algorithm-name: t_order_database_mod# 分表策略table-strategy:standard:sharding-column: interval_valuesharding-algorithm-name: t_order_table_cosid_interval
COSID_INTERVAL_SNOWFLAKE
基于 CosId 的雪花ID固定时间范围的分片算法,和上边的COSID_INTERVAL
算法不同之处在于,底层用于散列的COSID的生成方式是基于雪花算法(Snowflake
),内部结合了时间戳、节点标识符和序列号等,这样有助于数据分布更均匀些。
属性说明:
zone-id:
时区,必须遵循 java.time.ZoneId的所含值。例如:Asia/Shanghai
logic-name-prefix:
分片数据源或真实表的前缀格式datetime-lower:分片健值的下界,超过会报错,格式必须与
datetime-pattern
一致datetime-upper:分片健值的上界,超过会报错,格式必须与
datetime-pattern
一致sharding-suffix-pattern:分片表后缀名格式,yyyyMM、yyyyMMdd等格式,分片表格式的定义要结合
datetime-interval-unit
的单位,比如:t_order_yyyyMM
格式表示分片表存的月的数据,t_order_yyyy
格式表示分片表存的年的数据;datetime-interval-unit:分片间隔单位,超过该时间间隔将进入下一分片。它遵循 Java ChronoUnit 枚举,比如:
MONTHS
、DAYS
等;datetime-interval-amount:分片间隔数,和
datetime-interval-unit
是紧密配合使用;
spring:shardingsphere:rules:sharding:# 分片算法定义sharding-algorithms:t_order_database_mod:type: MODprops:sharding-count: 2 # 指定分片数量# 基于 CosId 的固定时间范围的分片算法t_order_table_cosid_interval_snowflake:type: COSID_INTERVAL_SNOWFLAKEprops:zone-id: "Asia/Shanghai" # 时区,必须遵循 java.time.ZoneId 的所含值。 例如:Asia/Shanghailogic-name-prefix: t_order_ # 分片数据源或真实表的前缀格式sharding-suffix-pattern: "yyyyMM" # 分片数据源或真实表的后缀格式,必须遵循 Java DateTimeFormatter 的格式,必须和 datetime-interval-unit 保持一致。例如:yyyyMMdatetime-lower: "2024-01-01 00:00:00" # 时间分片下界值,格式与 yyyy-MM-dd HH:mm:ss 的时间戳格式一致datetime-upper: "2024-12-31 00:00:00" # 时间分片上界值,格式与 yyyy-MM-dd HH:mm:ss 的时间戳格式一致datetime-interval-unit: "MONTHS" # 分片键时间间隔单位,必须遵循 Java ChronoUnit 的枚举值。例如:MONTHSdatetime-interval-amount: 1 # 分片键时间间隔,超过该时间间隔将进入下一分片tables:# 逻辑表名称t_order:# 数据节点:数据库.分片表actual-data-nodes: db$->{0..1}.t_order_$->{202401..202412}# 分库策略database-strategy:standard:sharding-column: order_idsharding-algorithm-name: t_order_database_mod# 分表策略table-strategy:standard:sharding-column: interval_valuesharding-algorithm-name: t_order_table_cosid_interval_snowflake
《3》复合分片算法
COMPLEX_INLINE
复合行表达式分片算法,适用于多分片健的简单分片场景,和行表达式分片算法使用的方式基本一样。多了一个属性sharding-columns
分片列名称,多个列用逗号分隔。特别注意:使用多分片键复合算法,一定要基于复合分片策略进行设置。
属性说明:
sharding-columns:分片列名称,多个可用逗号分割。
allow-range-query-with-inline-sharding:是否允许范围查询,注意:范围查询会无视分片策略,进行全路由,默认值为:false
algorithm-expression:分片算法行表达式
spring:shardingsphere:# 具体规则配置rules:sharding:# 分片算法定义sharding-algorithms:t_order_database_complex_inline_algorithms:type: COMPLEX_INLINEprops:sharding-columns: order_id, user_id # 分片列名称,多个列用逗号分隔。algorithm-expression: db$->{(order_id + user_id) % 2} # 分片算法的行表达式allow-range-query-with-inline-sharding: false # 是否允许范围查询。注意:范围查询会无视分片策略,进行全路由,默认 false# 11、复合行表达式分片算法t_order_table_complex_inline:type: COMPLEX_INLINEprops:sharding-columns: order_id, user_id # 分片列名称,多个列用逗号分隔。algorithm-expression: t_order_$->{ (order_id + user_id) % 3 } # 分片算法的行表达式allow-range-query-with-inline-sharding: false # 是否允许范围查询。注意:范围查询会无视分片策略,进行全路由,默认 falsetables:# 逻辑表名称t_order:# 数据节点:数据库.分片表actual-data-nodes: db$->{0..1}.t_order_${0..2}# 分库策略database-strategy:complex:shardingColumns: order_id, user_idsharding-algorithm-name: t_order_database_complex_inline_algorithms# 分表策略table-strategy:complex:shardingColumns: order_id, user_idsharding-algorithm-name: t_order_table_complex_inline
《4》Hint 分片算法
HINT_INLINE
Hint 行表达式分片算法(强制路由分片算法),允许我们指定数据分布的分片库和分表的位置。这个算法只有一个属性algorithm-expression
,直接利用Groovy
表达式在其中书写分片逻辑。
如果想要向db0.t_order_1
分片表中插入一条数据,但我的 Insert SQL 中并没有分片健呀,执意执行插入操作可能就会导致全库表路由,插入的数据就会重复,显然是不能接受的。Hint 算法可以很好的解决此场景。
HINT_INLINE 算法一定要在 HINT 分片策略内使用,否则会报错。
spring:shardingsphere:rules:sharding:# 分片算法定义sharding-algorithms:# Hint 行表达式分片算法t_order_database_hint_inline:type: HINT_INLINEprops:algorithm-expression: db$->{Integer.valueOf(value) % 2} # 分片算法的行表达式,默认值${value}t_order_table_hint_inline:type: HINT_INLINEprops:algorithm-expression: t_order_$->{Integer.valueOf(value) % 3} # 分片算法的行表达式,默认值${value}tables:# 逻辑表名称t_order:# 数据节点:数据库.分片表actual-data-nodes: db$->{0..1}.t_order_$->{0..2}# 分库策略database-strategy:hint:sharding-algorithm-name: t_order_database_hint_inline# 分表策略table-strategy:hint:sharding-algorithm-name: t_order_table_hint_inline
值的传递
@Test
public void Test1() {HintManager hintManager = HintManager.getInstance();hintManager.clearShardingValues();// 设置逻辑表 t_order 的分库值hintManager.addDatabaseShardingValue("t_order", 0);// 设置逻辑表 t_order 的分表值hintManager.addTableShardingValue("t_order", 1);// 1%3 = 1 所以放入 db0.t_order_1 分片表jdbcTemplate.execute("INSERT INTO `t_order`(`id`,`order_date`,`order_id`, `order_number`, `customer_id`, `total_amount`, `interval_value`, `user_id`) VALUES (1, '2024-03-20 00:00:00', 1, '1', 1, 1.00, '2024-01-01 00:00:00', 1);");hintManager.close();
}
ShardingSphere 通过使用ThreadLocal
管理强制路由配置,可以通过编程的方式向HintManager
中添加分片值,该分片值仅在当前线程内生效。
-
HintManager.getInstance() 获取 HintManager 实例;
-
HintManager.addDatabaseShardingValue,HintManager.addTableShardingValue 方法设置分片键值;
-
执行 SQL 语句完成路由和执行;
-
最后调用 HintManager.close 清理 ThreadLocal 中的内容。
推荐博主文档https://mp.weixin.qq.com/mp/appmsgalbum?__biz=MzAxNTM4NzAyNg==&action=getalbum&album_id=2987992825445416970&subscene=159&subscene=21&scenenote=https%3A%2F%2Fmp.weixin.qq.com%2Fs%3F__biz%3DMzAxNTM4NzAyNg%3D%3D%26mid%3D2247506123%26idx%3D1%26sn%3D50ea1c80fbd145a0407a647cbbb10a10%26scene%3D21%26poc_token%3DHBaLEGijU_cSZDFmAmDBKDUoqRxRCnZjPE9o7J06&nolastread=1#wechat_redirect这位博主总结的shardingsphere非常不错,可以满足开发中的绝大多数场景使用。