ShardingSphere分库分表

ShardingSphere分库分表

ShardingSphere介绍

Apache ShardingSphere 是一套开源的分布式数据库中间件解决方案组成的生态圈,它由JDBC、Proxy和Sidecar(规划中)这3款相互独立,却又能够混合部署配合使用的产品组成。 它们均提供标准化的数据分片、分布式事务和数据库治理功能,可适用于如 Java 同构、异构语言、云原生等各种多样化的应用场景。

分库分表

当我们使用读写分离、索引、缓存后,数据库的压力还是很大的时候,这就需要使用到数据库拆分了。

一般来说, MySQL推荐的单表数据量在500w ~ 800w, 超过800w则建议分表.
或是在系统接口响应时间明显变慢, 并且通过代码优化, 改写sql等形式无法获得明显提升, 且明确了性能瓶颈在数据库时, 建议分表
分库则是在分表后单库性能到达瓶颈后进行, 如果个人或项目有钱任性的除外.分库主要解决的是并发量大的问题。

垂直拆分

水平拆分

分片后的常见问题

四种分片算法&五种分片策略

4种分片算法

5种分片策略

ShardingSphere-JDBC

定位为轻量级 Java 框架,在 Java 的 JDBC 层提供的额外服务。 它使用客户端直连数据库,以 jar 包形式提供服务,无需额外部署和依赖,可理解为增强版的 JDBC 驱动,完全兼容 JDBC 和各种 ORM 框架。

需要注意的是,分库分表并不是由 ShardingSphere-JDBC 来做,它是用来负责操作已经分完之后的 CRUD 操作。

水平分表实操(单分片键,分片类型:HASH_MODE)

环境使用:SpringBoot 2.7.12 + MybatisPlus + ShardingSphere-jdbc 5.2.0 + Druid连接池
本示例为单库,库内有6个分表,并且按照order_id的hash值进行取模计算得到实际表

添加Maven依赖

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
33
34
35
36
37
38
39
40
41
42
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
<version>2.2.2</version>
</dependency>

<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
</dependency>

<dependency>
<groupId>com.zaxxer</groupId>
<artifactId>HikariCP</artifactId>
</dependency>

<dependency>
<groupId>com.mysql</groupId>
<artifactId>mysql-connector-j</artifactId>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>org.apache.shardingsphere</groupId>
<artifactId>shardingsphere-jdbc-core-spring-boot-starter</artifactId>
<version>5.1.0</version>
</dependency>

<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>

<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.20</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-logging</artifactId>
</dependency>

按照水平分表创建数据库

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
CREATE TABLE `t_order_5`
(
`order_id` bigint NOT NULL AUTO_INCREMENT,
`price` double(12,2),
`user_id` int NOT NULL,
`address_id` bigint NOT NULL,
`city` varchar(32) NULL DEFAULT NULL,
`status` tinyint NULL DEFAULT NULL,
`interval_time` datetime NULL DEFAULT NULL,
`creator` varchar(32) NULL DEFAULT NULL,
`create_time` datetime NULL DEFAULT NULL,
`updater` varchar(32) NULL DEFAULT NULL,
`update_time` datetime NULL DEFAULT NULL,
PRIMARY KEY (`order_id`) USING BTREE
) ENGINE = InnoDB AUTO_INCREMENT = 1 CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = Dynamic

配置Sharding-jdbc分片策略
application.yml内容:

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
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
spring:
main:
banner-mode: off

shardingsphere:
# 配置数据源,给数据源起别名ds
datasource:
ds:
type: com.zaxxer.hikari.HikariDataSource
driver-class-name: com.mysql.cj.jdbc.Driver
jdbc-url: jdbc:mysql://localhost:3306/test?serverTimezone=UTC&useSSL=false&useUnicode=true&characterEncoding=UTF-8
username: root
password: 1234
names: ds
rules:
sharding:
binding-tables:
- t_order,t_order_item
broadcast-tables: t_address
# 分片算法
sharding-algorithms:
t-order-algorithm:
type: HASH_MOD
props:
sharding-count: '6'
t-order-item-inline:
type: INLINE
props:
algorithm-expression: t_order_item_$->{order_id % 2}
tables:
# 分表
t_order:
actual-data-nodes: ds.t_order_$->{0..5} # 真实表名
table-strategy:
standard:
sharding-algorithm-name: t-order-algorithm
sharding-column: order_id # 分片键
t_order_item:
actual-data-nodes: ds.t_order_item_$->{0..1}
table-strategy:
standard:
sharding-algorithm-name: t-order-item-inline
sharding-column: order_id
props:
sql-show: true



#mybatis-plus:
# global-config:
# banner: false
# db-config:
# id-type: assign_id #使用雪花算法开启数据入库时ID自增
# logic-delete-field: deleted
# logic-delete-value: 1
# logic-not-delete-value: 0
# #开启mp的日志(控制台输出)
# configuration:
# log-impl: org.apache.ibatis.logging.stdout.StdOutImpl

mybatis:
mapper-locations: classpath*:/mappers/*-mapper.xml
type-aliases-package: com.panliu.domain
configuration:
default-fetch-size: 20
default-statement-timeout: 30
map-underscore-to-camel-case: true
use-generated-keys: true

测试代码运行

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
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
@Slf4j
@SpringBootTest
public class OrderMapperTests {
private final static String[] CITIES = {"shanghai", "beijing"};
/**
* -120000, 0, 18, 20000, 40000, 50000, 60000, 64000, 80000, 99000
*/
private final static long[] PRICES = {-120000, 0, 18, 20000, 40000, 50000, 60000, 64000, 80000, 99000};
@Autowired
private OrderMapper orderMapper;

@Test
//@Disabled
void save() {
ThreadLocalRandom random = ThreadLocalRandom.current();

Date[] dates = create();
IntStream.range(0, 20).forEach(i -> {
Order order = new Order();
order.setOrderId(System.nanoTime() + i);
order.setPrice(PRICES[i % PRICES.length]);
order.setAddressId(i);
order.setCity(CITIES[i % 2]);
order.setUserId(Math.abs(random.nextInt()));
order.setCreator("user.0" + i);
order.setIntervalTime(dates[i % 5]);
order.setUpdater(order.getCreator());
log.info("====>{}", order);
orderMapper.save(order);
});
}

@Test
// @Disabled
void findAll() {
List<Order> list = orderMapper.findAllAtPrice(60000);
log.info("===>{}", list);
}

private Date[] create() {
Date[] dates = new Date[6];

try {
Date date = DateUtils.parseDate("2023-08-14 00:00:00", Locale.CHINA, "yyyy-MM-dd HH:mm:ss");
IntStream.range(0, 6).forEach(i -> dates[i] = DateUtils.addDays(date, i));
} catch (ParseException e) {
log.error("date parse fail: ", e);
}
return dates;
}
}

运行结果
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

复合分片(根据城市和order_id分片)

application.yml配置

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
rules:
sharding:
sharding-algorithms:
t-order-algorithm:
type: COMPLEX_INLINE
props:
algorithm-expression: t_order_$->{city}_$->{order_id % 2}
sharding-columns: city,order_id
tables:
t_order:
actual-data-nodes: ds.t_order_$->{['shanghai','beijing']}_$->{0..1}
table-strategy:
complex:
sharding-algorithm-name: t-order-algorithm
sharding-columns: city,order_id

分片结果
在这里插入图片描述
在这里插入图片描述

last update time 2023-08-24