ShardingSphere-Proxy 入门教程之三

大纲

前言

学习资源

ShardingSphere-Proxy 分布式序列算法

水平分片(包括水平分库和水平分表)需要关注分布式序列(即分布式全局唯一 ID),因为不能简单的使用基于数据库的自增主键,否则不同库不同表之间会发生主键冲突。通常主键冲突有两种解决方案:一种是使用 MyBatis-Plus 的 ID 生成策略;一种是使用 ShardingSphere-Proxy 的分布式序列配置。

MyBatis-Plus 的 ID 生成策略

  • 使用 MyBatis-Plus 的 ID 生成策略 ASSIGN_ID(默认是基于 Snowflake 算法实现)
1
2
3
4
5
6
7
8
9
10
11
12
@TableName("t_order")
@Data
public class Order {

/**
* 不依赖数据库自增主键,插入数据时由 MyBatis-Plus 自动生成主键
* 默认使用雪花算法(Snowflake)生成 64 位的长整型 ID
*/
@TableId(type = IdType.ASSIGN_ID)
private Long id;

}
  • 在 MyBatis-Plus 中,Snowflake 算法生成的 ID 是一个 64 位长整型(| 1 bit 符号位 | 41 bit 时间戳 | 5 bit 数据中心 ID | 5 bit 工作机器 ID | 12 bit 序列号 |),其默认的 Snowflake 参数为:
参数默认值说明
dataCenterId1数据中心 ID(0 ~ 31)
workerId1工作机器 ID(0 ~ 31)
  • 在 MyBatis-Plus 中,Snowflake 参数的默认值在分布式部署时可能会出现 ID 冲突,因此通常需要自定义 Snowflake 参数(包括 dataCenterIdworkerId),避免 ID 冲突的发生
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
69
70
71
import com.baomidou.mybatisplus.core.incrementer.IdentifierGenerator;
import com.baomidou.mybatisplus.core.toolkit.Sequence;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import java.net.InetAddress;
import java.net.NetworkInterface;

@Configuration
public class SnowflakeConfig {

/**
* 定义一个 Bean 来覆盖 MyBatis-Plus 默认的 IdentifierGenerator
*/
@Bean
public IdentifierGenerator identifierGenerator() {
return new IdentifierGenerator() {

// 动态获取 Snowflake 参数
private final Sequence sequence = new Sequence(getWorkerId(), getDatacenterId());

@Override
public Number nextId(Object entity) {
return sequence.nextId();
}

};
}

/**
* 获取工作机器 ID(0~31)
*/
private long getWorkerId() {
try {
// 根据 IP 或容器主机名计算工作机器 ID(0 ~ 31)
String hostAddress = InetAddress.getLocalHost().getHostAddress();
return (hostAddress.hashCode() & 31);
} catch (Exception e) {
// 异常情况返回默认值 0
return 0;
}
}

/**
* 获取数据中心 ID(0~31)
*/
private long getDatacenterId() {
try {
InetAddress inetAddress = InetAddress.getLocalHost();
NetworkInterface ni = NetworkInterface.getByInetAddress(inetAddress);

if (ni == null) {
// 返回默认值 0
return 0;
}

byte[] mac = ni.getHardwareAddress();
if (mac == null || mac.length == 0) {
// 返回默认值 0
return 0;
}

// 根据 MAC 地址计算数据中心ID(0 ~ 31)
return (mac[mac.length - 1] & 31);
} catch (Exception e) {
// 异常情况返回默认值 0
return 0;
}
}

}

ShardingSphere 的分布式序列

ShardingSphere-Proxy 内置了两种分布式序列算法(即分布式 ID 生成算法),包括 SNOWFLAKEUUID,可用于生成分布式全局唯一 ID。

SNOWFLAKE 算法

  • 这里以单库分表举例,演示如何配置 ShardingSphere-Proxy 使用 SNOWFLAKE 分布式序列算法(有 DistSQL 和 YAML 两种配置方式,任选一种方式即可)
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
-------------------------------------------- DistSQL 配置方式 --------------------------------------------

-- 创建逻辑数据库(Schema)
CREATE DATABASE sharding_db;

-- 切换到逻辑数据库(Schema)
USE sharding_db;

-- 创建数据源
ADD RESOURCE server_order0 (
URL="jdbc:mysql://192.168.2.191:3310/db_order?serverTimezone=UTC&useSSL=false",
USER=root,
PASSWORD=123456,
PROPERTIES(
"connectionTimeoutMilliseconds"="30000",
"idleTimeoutMilliseconds"="60000",
"maxLifetimeMilliseconds"="1800000",
"maxPoolSize"="50",
"minPoolSize"="1"
)
);

-- 创建分片算法
CREATE SHARDING ALGORITHM alg_inline_order (
TYPE(NAME=INLINE, PROPERTIES(
"algorithm-expression"="t_order${order_id % 2}"
))
);

-- 创建分布式序列算法
CREATE SHARDING KEY GENERATOR alg_snowflake (
TYPE(NAME=SNOWFLAKE, PROPERTIES(
"max-vibration-offset"="1",
"max-tolerate-time-difference-milliseconds"="10"
))
);

-- 创建分片规则
CREATE SHARDING TABLE RULE t_order (
-- 数据节点
DATANODES("server_order0.t_order${0..1}"),
-- 分表策略
TABLE_STRATEGY (
TYPE=STANDARD,
SHARDING_COLUMN=order_id,
SHARDING_ALGORITHM=alg_inline_order
),
-- 分布式序列策略
KEY_GENERATE_STRATEGY (
COLUMN=id,
KEY_GENERATOR=alg_snowflake
)
);
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
# -------------------------------------------- YAML 配置方式 --------------------------------------------

# 逻辑数据库(Schema)的名称
schemaName: sharding_db

# 配置数据源
dataSources:
# 配置第 1 个数据源
server_order0:
url: jdbc:mysql://192.168.2.191:3310/db_order?serverTimezone=UTC&useSSL=false
username: root
password: 123456
connectionTimeoutMilliseconds: 30000
idleTimeoutMilliseconds: 60000
maxLifetimeMilliseconds: 1800000
maxPoolSize: 50
minPoolSize: 1

# 配置分片规则
rules:
- !SHARDING
# 配置分片表规则
tables:
t_order:
# 配置数据节点
actualDataNodes: server_order0.t_order${0..1}
# 配置分表策略
tableStrategy:
standard:
shardingColumn: order_id
shardingAlgorithmName: alg_inline_order
# 配置分布式序列策略
keyGenerateStrategy:
column: id
keyGeneratorName: alg_snowflake
# 配置分片算法
shardingAlgorithms:
alg_inline_order:
type: INLINE
props:
algorithm-expression: t_order${order_id % 2}
# 配置分布式序列算法
keyGenerators:
alg_snowflake:
type: SNOWFLAKE
props:
max-vibration-offset: 1
max-tolerate-time-difference-milliseconds: 10
  • 此时,需要将实体类中的 MyBatis-Plus 的 ID 生成策略修改为 NONE
1
2
3
4
5
6
7
8
9
10
11
12
@TableName("t_order")
@Data
public class Order {

/**
* MyBatis-Plus 不自动生成 ID <br>
* 当 ShardingSphere-Proxy 配置了分布式序列策略,会自动注入 ID
*/
@TableId(type = IdType.NONE)
private Long id;

}
  • ShardingSphere-Proxy 的 SNOWFLAKE 分布式序列算法支持配置以下属性:
属性名称数据类型说明默认值
max-vibration-offsetint最大抖动上限值,范围是 [0, 4096)
注意:若使用此算法生成值作分片值(分片列的值),建议配置此属性。此算法在不同毫秒内所生成的 Key 取模 2^n(这里的 2^n 一般为分库或分表数量)之后结果总为 0 或 1。
该属性的作用是为了让同一毫秒生成的 ID,最终的分片取模结果不总是落在同一个库 / 表上,用于避免分片倾斜(热点分片)问题。
为防止上述分片问题,建议将此属性值配置为 (2^n) - 1
1
max-tolerate-time-difference-millisecondslong最大容忍时钟回退时间,单位:毫秒 10
  • SNOWFLAKE 分布式序列算法中,max-vibration-offset 属性的配置示例:
分库数量 2^nmax-vibration-offset 的建议值 (2^n) - 1
2 库 2¹=21
4 库 2²=43
8 库 2³=87
16 库 2⁴=1615
32 库 2⁵=3231

总结

在 ShardingSphere-Proxy 的 SNOWFLAKE 分布式序列算法中,max-vibration-offset 属性用来给 Snowflake ID 在同一毫秒内增加随机性,避免分片时总落到某几个库 / 表,防止热点库 / 表的出现。

UUID 算法

  • 这里以单库分表举例,演示如何配置 ShardingSphere-Proxy 使用 UUID 分布式序列算法(有 DistSQL 和 YAML 两种配置方式,任选一种方式即可)
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
-------------------------------------------- DistSQL 配置方式 --------------------------------------------

-- 创建逻辑数据库(Schema)
CREATE DATABASE sharding_db;

-- 切换到逻辑数据库(Schema)
USE sharding_db;

-- 创建数据源
ADD RESOURCE server_order0 (
URL="jdbc:mysql://192.168.2.191:3310/db_order?serverTimezone=UTC&useSSL=false",
USER=root,
PASSWORD=123456,
PROPERTIES(
"connectionTimeoutMilliseconds"="30000",
"idleTimeoutMilliseconds"="60000",
"maxLifetimeMilliseconds"="1800000",
"maxPoolSize"="50",
"minPoolSize"="1"
)
);

-- 创建分片算法
CREATE SHARDING ALGORITHM alg_inline_order (
TYPE(NAME=INLINE, PROPERTIES(
"algorithm-expression"="t_order${order_id % 2}"
))
);

-- 创建分布式序列算法
CREATE SHARDING KEY GENERATOR alg_uuid (
TYPE(NAME=UUID)
);

-- 创建分片规则
CREATE SHARDING TABLE RULE t_order (
-- 数据节点
DATANODES("server_order0.t_order${0..1}"),
-- 分表策略
TABLE_STRATEGY (
TYPE=STANDARD,
SHARDING_COLUMN=order_id,
SHARDING_ALGORITHM=alg_inline_order
),
-- 分布式序列策略
KEY_GENERATE_STRATEGY (
COLUMN=id,
KEY_GENERATOR=alg_uuid
)
);
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
# -------------------------------------------- YAML 配置方式 --------------------------------------------

# 逻辑数据库(Schema)的名称
schemaName: sharding_db

# 配置数据源
dataSources:
# 配置第 1 个数据源
server_order0:
url: jdbc:mysql://192.168.2.191:3310/db_order?serverTimezone=UTC&useSSL=false
username: root
password: 123456
connectionTimeoutMilliseconds: 30000
idleTimeoutMilliseconds: 60000
maxLifetimeMilliseconds: 1800000
maxPoolSize: 50
minPoolSize: 1

# 配置分片规则
rules:
- !SHARDING
# 配置分片表规则
tables:
t_order:
# 配置数据节点
actualDataNodes: server_order0.t_order${0..1}
# 配置分表策略
tableStrategy:
standard:
shardingColumn: order_id
shardingAlgorithmName: alg_inline_order
# 配置分布式序列策略
keyGenerateStrategy:
column: id
keyGeneratorName: alg_uuid
# 配置分片算法
shardingAlgorithms:
alg_inline_order:
type: INLINE
props:
algorithm-expression: t_order${order_id % 2}
# 配置分布式序列算法
keyGenerators:
alg_uuid:
type: UUID
  • 此时,需要将实体类中的 MyBatis-Plus 的 ID 生成策略修改为 NONE
1
2
3
4
5
6
7
8
9
10
11
12
@TableName("t_order")
@Data
public class Order {

/**
* MyBatis-Plus 不自动生成 ID <br>
* 当 ShardingSphere-Proxy 配置了分布式序列策略,会自动注入 ID
*/
@TableId(type = IdType.NONE)
private String id;

}

ShardingSphere-Proxy 分片算法

分片算法的类型

ShardingSphere-Proxy 与 ShardingSphere-JDBC 在底层实现上使用同一套分布式序列算法实现,只是两者在配置与管理能力上并不完全一致,其中内置的分片算法如下所示:

  • 自动分片算法

    • 取模分片算法(MOD
      • 概述:对分片键取模,决定路由的库 / 表序号。
      • 特点:算法简单、性能高、均匀分布。
      • 适用场景:用户 ID、订单 ID 等数值型字段且写请求均匀分布的场景。
    • 哈希取模分片算法(HASH_MOD
      • 概述:对分片键先做哈希,再取模。
      • 特点:分布更均匀,避免 ID 递增导致热点。
      • 适用场景:字符串类型分片键(如手机号、Email、UUID)。
    • 基于分片容量的范围分片算法(VOLUME_RANGE
      • 概述:按单分片最大承载容量进行范围分片。
      • 特点:按数据量增长自动落到不同库 / 表。
      • 适用场景:数据量随时间增长、按容量控制每个分片大小(如日志类业务)。
    • 基于分片边界的范围分片算法(BOUNDARY_RANGE
      • 概述:在配置中预先定义各分片的边界范围。
      • 特点:控制精确,可与业务范围区间对应。
      • 适用场景:省份编码、分等级、金额区间等明确范围的业务。
    • 自动时间段分片算法(AUTO_INTERVAL
      • 概述:按时间自动生成分片,比如每天 / 每月自动建表。
      • 特点:避免手动扩容,时间分片自动推进。
      • 适用场景:日志表、订单表、流水表的按时间分表。
  • 标准分片算法

    • 行表达式分片算法(INLINE
      • 概述:使用 Groovy 表达式生成路由,如 t_order_$->{user_id % 4}
      • 特点:灵活、配置简单、可自定义表达式。
      • 适用场景:分片条件规则清晰,可用简单表达式定义的场景。
    • 时间范围分片算法(INTERVAL
      • 概述:通过时间区间计算应该路由到哪个时间分片。
      • 特点:支持 “时间 → 表名” 的表达式映射。
      • 适用场景:按年 / 月 / 天的时间序列数据分表(如日志、订单流水)。
  • 复合分片算法

    • 复合行表达式分片算法(COMPLEX_INLINE
      • 概述:支持多个分片键,通过表达式组合路由。
      • 特点:多维条件路由,灵活性高。
      • 适用场景:订单场景:需按 user_idorder_time 等联合多个键决定路由。
  • Hint 分片算法

    • Hint 行表达式分片算法(HINT_INLINE
      • 概述:基于 Hint(SQL 注入式强制路由值)的表达式算法。
      • 特点:程序员通过代码显式指定分片,不依赖 SQL 条件。
      • 适用场景:
        • SQL 本身没有分片字段(例如跨库 JOIN 时强制路由)
        • 使用中间件或服务层统一指定分片键
        • 灰度 / 运营类特殊请求

自定义类分片算法

ShardingSphere-Proxy 除了提供内置的分片算法,还支持开发者自定义类分片算法(CLASS_BASED),可通过配置分片策略类型和算法类名,实现自定义扩展。

分片算法的使用

特别注意

ShardingSphere-Proxy 内置的分片算法同时适用于垂直分片(垂直分库、垂直分表)和水平分片(水平分库、水平分表)。由于篇幅限制,下面仅给出部分分片算法的配置示例。无论 ShardingSphere-Proxy 是使用 YAML 配置 还是 DistSQL 配置,都必须注意 ShardingSphere-Proxy 的版本差异。不同版本之间支持的 DistSQL 命令、YAML 配置语法以及参数格式可能存在较大差异,同一份配置在不同版本下可能无法直接执行或行为不一致,因此在编写和迁移配置时必须结合 ShardingSphere-Proxy 具体版本进行验证。

水平分库

这里以水平分库为例子,演示如何使用 ShardingSphere-Proxy 提供的分片算法进行分库。

  • 分库规则:

    • t_order 逻辑表中 user_id 为偶数时,数据插入到订单数据库服务器一(server_order0);user_id 为奇数时,数据插入到订单数据库服务器二(server_order1)。
    • 这样分库的好处是,同一个用户的订单数据,一定会被插入到同一台数据库服务器上,这样查询某个用户的所有订单时效率较高。
    • 值得一提的,由于这里每个库只有一张表,所以只需要配置分库策略(DATABASE_STRATEGY),不需要配置分表策略(TABLE_STRATEGY)。
  • 数据结构:

    1
    2
    3
    4
    server_order0
    └── t_order
    server_order1
    └── t_order
行表达式分片算法
YAML 配置模式
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
# 逻辑数据库(Schema)的名称
schemaName: sharding_db

# 配置数据源
dataSources:
# 配置第 1 个数据源
server_order0:
url: jdbc:mysql://192.168.2.191:3310/db_order?serverTimezone=UTC&useSSL=false
username: root
password: 123456
connectionTimeoutMilliseconds: 30000
idleTimeoutMilliseconds: 60000
maxLifetimeMilliseconds: 1800000
maxPoolSize: 50
minPoolSize: 1

# 配置第 2 个数据源
server_order1:
url: jdbc:mysql://192.168.2.191:3310/db_order?serverTimezone=UTC&useSSL=false
username: root
password: 123456
connectionTimeoutMilliseconds: 30000
idleTimeoutMilliseconds: 60000
maxLifetimeMilliseconds: 1800000
maxPoolSize: 50
minPoolSize: 1

# 配置分片规则
rules:
- !SHARDING
# 配置分片表规则
tables:
t_order:
# 配置数据节点
actualDataNodes: server_order${0..1}.t_order
# 配置分库策略
databaseStrategy:
standard:
shardingColumn: user_id
shardingAlgorithmName: alg_inline_userid
# 配置分片算法
shardingAlgorithms:
alg_inline_userid:
type: INLINE
props:
algorithm-expression: server_order${user_id % 2}
DistSQL 配置模式
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
-- 创建逻辑数据库(Schema)
CREATE DATABASE sharding_db;

-- 切换到逻辑数据库(Schema)
USE sharding_db;

-- 创建第 1 个数据源
ADD RESOURCE server_order0 (
URL="jdbc:mysql://192.168.2.191:3310/db_order?serverTimezone=UTC&useSSL=false",
USER=root,
PASSWORD=123456,
PROPERTIES(
"connectionTimeoutMilliseconds"="30000",
"idleTimeoutMilliseconds"="60000",
"maxLifetimeMilliseconds"="1800000",
"maxPoolSize"="50",
"minPoolSize"="1"
)
);

-- 创建第 2 个数据源
ADD RESOURCE server_order1 (
URL="jdbc:mysql://192.168.2.191:3311/db_order?serverTimezone=UTC&useSSL=false",
USER=root,
PASSWORD=123456,
PROPERTIES(
"connectionTimeoutMilliseconds"="30000",
"idleTimeoutMilliseconds"="60000",
"maxLifetimeMilliseconds"="1800000",
"maxPoolSize"="50",
"minPoolSize"="1"
)
);

-- 创建分片算法
CREATE SHARDING ALGORITHM alg_inline_userid (
TYPE(NAME=INLINE, PROPERTIES(
'algorithm-expression'='server_order${user_id % 2}'
))
);

-- 创建分片表规则
CREATE SHARDING TABLE RULE t_order (
-- 数据节点
DATANODES('server_order${0..1}.t_order'),
-- 分库策略
DATABASE_STRATEGY (
TYPE=STANDARD,
SHARDING_COLUMN=user_id,
SHARDING_ALGORITHM=alg_inline_userid
)
);
取模分片算法
YAML 配置模式
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
# 逻辑数据库(Schema)的名称
schemaName: sharding_db

# 配置数据源
dataSources:
# 配置第 1 个数据源
server_order0:
url: jdbc:mysql://192.168.2.191:3310/db_order?serverTimezone=UTC&useSSL=false
username: root
password: 123456
connectionTimeoutMilliseconds: 30000
idleTimeoutMilliseconds: 60000
maxLifetimeMilliseconds: 1800000
maxPoolSize: 50
minPoolSize: 1

# 配置第 2 个数据源
server_order1:
url: jdbc:mysql://192.168.2.191:3311/db_order?serverTimezone=UTC&useSSL=false
username: root
password: 123456
connectionTimeoutMilliseconds: 30000
idleTimeoutMilliseconds: 60000
maxLifetimeMilliseconds: 1800000
maxPoolSize: 50
minPoolSize: 1

# 配置分片规则
rules:
- !SHARDING
# 配置分片表规则
tables:
t_order:
# 配置数据节点
actualDataNodes: server_order${0..1}.t_order
# 配置分库策略
databaseStrategy:
standard:
shardingColumn: user_id
shardingAlgorithmName: alg_mod
# 配置分片算法
shardingAlgorithms:
alg_mod:
type: MOD
props:
sharding-count: 2
DistSQL 配置模式
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
-- 创建逻辑数据库(Schema)
CREATE DATABASE sharding_db;

-- 切换到逻辑数据库(Schema)
USE sharding_db;

-- 创建第 1 个数据源
ADD RESOURCE server_order0 (
URL="jdbc:mysql://192.168.2.191:3310/db_order?serverTimezone=UTC&useSSL=false",
USER=root,
PASSWORD=123456,
PROPERTIES(
"connectionTimeoutMilliseconds"="30000",
"idleTimeoutMilliseconds"="60000",
"maxLifetimeMilliseconds"="1800000",
"maxPoolSize"="50",
"minPoolSize"="1"
)
);

-- 创建第 2 个数据源
ADD RESOURCE server_order1 (
URL="jdbc:mysql://192.168.2.191:3311/db_order?serverTimezone=UTC&useSSL=false",
USER=root,
PASSWORD=123456,
PROPERTIES(
"connectionTimeoutMilliseconds"="30000",
"idleTimeoutMilliseconds"="60000",
"maxLifetimeMilliseconds"="1800000",
"maxPoolSize"="50",
"minPoolSize"="1"
)
);

-- 创建分片算法
CREATE SHARDING ALGORITHM alg_mod (
TYPE(NAME=MOD,PROPERTIES(
"sharding-count"="2"
))
);

-- 创建分片表规则
CREATE SHARDING TABLE RULE t_order (
-- 数据节点
DATANODES("server_order${0..1}.t_order"),
-- 分库策略
DATABASE_STRATEGY(
TYPE=STANDARD,
SHARDING_COLUMN=user_id,
SHARDING_ALGORITHM=alg_mod
)
);
哈希取模分片算法
YAML 配置模式
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
# 逻辑数据库(Schema)的名称
schemaName: sharding_db

# 配置数据源
dataSources:
# 配置第 1 个数据源
server_order0:
url: jdbc:mysql://192.168.2.191:3310/db_order?serverTimezone=UTC&useSSL=false
username: root
password: 123456
connectionTimeoutMilliseconds: 30000
idleTimeoutMilliseconds: 60000
maxLifetimeMilliseconds: 1800000
maxPoolSize: 50
minPoolSize: 1

# 配置第 2 个数据源
server_order1:
url: jdbc:mysql://192.168.2.191:3311/db_order?serverTimezone=UTC&useSSL=false
username: root
password: 123456
connectionTimeoutMilliseconds: 30000
idleTimeoutMilliseconds: 60000
maxLifetimeMilliseconds: 1800000
maxPoolSize: 50
minPoolSize: 1

# 配置分片规则
rules:
- !SHARDING
# 配置分片表规则
tables:
t_order:
# 配置数据节点
actualDataNodes: server_order${0..1}.t_order
# 配置分库策略
databaseStrategy:
standard:
shardingColumn: user_id
shardingAlgorithmName: alg_hash_mod
# 配置分片算法
shardingAlgorithms:
alg_hash_mod:
type: HASH_MOD
props:
sharding-count: 2
DistSQL 配置模式
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
-- 创建逻辑数据库(Schema)
CREATE DATABASE sharding_db;

-- 切换到逻辑数据库(Schema)
USE sharding_db;

-- 创建第 1 个数据源
ADD RESOURCE server_order0 (
URL="jdbc:mysql://192.168.2.191:3310/db_order?serverTimezone=UTC&useSSL=false",
USER=root,
PASSWORD=123456,
PROPERTIES(
"connectionTimeoutMilliseconds"="30000",
"idleTimeoutMilliseconds"="60000",
"maxLifetimeMilliseconds"="1800000",
"maxPoolSize"="50",
"minPoolSize"="1"
)
);

-- 创建第 2 个数据源
ADD RESOURCE server_order1 (
URL="jdbc:mysql://192.168.2.191:3311/db_order?serverTimezone=UTC&useSSL=false",
USER=root,
PASSWORD=123456,
PROPERTIES(
"connectionTimeoutMilliseconds"="30000",
"idleTimeoutMilliseconds"="60000",
"maxLifetimeMilliseconds"="1800000",
"maxPoolSize"="50",
"minPoolSize"="1"
)
);

-- 创建分片算法
CREATE SHARDING ALGORITHM alg_hash_mod (
TYPE(NAME=HASH_MOD,PROPERTIES(
"sharding-count"="2"
))
);

-- 创建分片表规则
CREATE SHARDING TABLE RULE t_order (
-- 数据节点
DATANODES("server_order${0..1}.t_order"),
-- 分库策略
DATABASE_STRATEGY(
TYPE=STANDARD,
SHARDING_COLUMN=user_id,
SHARDING_ALGORITHM=alg_hash_mod
)
);

水平分表

这里以水平分表为例子,演示如何使用 ShardingSphere-Proxy 提供的分片算法进行分表。由于篇幅有限,这里仅介绍哈希取模分片算法的使用,其他分片算法可以参考上面 水平分库 的使用。

  • 分表规则:

    • t_order 逻辑表中 order_no 的哈希值为偶数时,数据插入对应数据库服务器的 t_order0 表;order_no 的哈希值为奇数时,数据插入对应数据库服务器的 t_order1 表。
    • 值得一提的是,由于这里只有一个数据库(即单库分表),所以只需要配置分表策略(TABLE_STRATEGY),不需要配置分库策略(DATABASE_STRATEGY)。
    • 因为 order_no 是字符串类型,所以不能直接取模,需要对其进行哈希计算再取模。
  • 数据结构:

    1
    2
    3
    server_order0
    ├── t_order0
    └── t_order1
哈希取模分片算法
YAML 配置模式
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
# 逻辑数据库(Schema)的名称
schemaName: sharding_db

# 配置数据源
dataSources:
# 配置第 1 个数据源
server_order0:
url: jdbc:mysql://192.168.2.191:3310/db_order?serverTimezone=UTC&useSSL=false
username: root
password: 123456
connectionTimeoutMilliseconds: 30000
idleTimeoutMilliseconds: 60000
maxLifetimeMilliseconds: 1800000
maxPoolSize: 50
minPoolSize: 1

# 配置分片规则
rules:
- !SHARDING
# 配置分片表规则
tables:
t_order:
# 配置数据节点
actualDataNodes: server_order0.t_order${0..1}
# 配置分表策略
tableStrategy:
standard:
shardingColumn: order_no
shardingAlgorithmName: alg_hash_mod
# 配置分片算法
shardingAlgorithms:
alg_hash_mod:
type: HASH_MOD
props:
sharding-count: 2
DistSQL 配置模式
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
-- 创建逻辑数据库(Schema)
CREATE DATABASE sharding_db;

-- 切换到逻辑数据库(Schema)
USE sharding_db;

-- 创建第 1 个数据源
ADD RESOURCE server_order0 (
URL="jdbc:mysql://192.168.2.191:3310/db_order?serverTimezone=UTC&useSSL=false",
USER=root,
PASSWORD=123456,
PROPERTIES(
"connectionTimeoutMilliseconds"="30000",
"idleTimeoutMilliseconds"="60000",
"maxLifetimeMilliseconds"="1800000",
"maxPoolSize"="50",
"minPoolSize"="1"
)
);

-- 创建分片算法
CREATE SHARDING ALGORITHM alg_hash_mod (
TYPE(NAME=HASH_MOD,PROPERTIES(
"sharding-count"="2"
))
);

-- 创建分片表规则
CREATE SHARDING TABLE RULE t_order (
DATANODES("server_order0.t_order${0..1}"),
TABLE_STRATEGY(
TYPE="STANDARD",
SHARDING_COLUMN="order_no",
SHARDING_ALGORITHM="alg_hash_mod"
)
);

水平分库与水平分表

这里以水平分库 + 水平分表为例子,演示如何使用 ShardingSphere-Proxy 提供的分片算法。

  • 分库规则:

    • t_order 逻辑表中 user_id 为偶数时,数据插入到订单数据库服务器一(server_order0);user_id 为奇数时,数据插入到订单数据库服务器二(server_order1)。
    • 这样分库的好处是,同一个用户的订单数据,一定会被插入到同一台数据库服务器上,这样查询某个用户的所有订单时效率较高。
  • 分表规则:

    • t_order 逻辑表中 order_no 的哈希值为偶数时,数据插入对应数据库服务器的 t_order0 表;order_no 的哈希值为奇数时,数据插入对应数据库服务器的 t_order1 表。
    • 因为 order_no 是字符串类型,所以不能直接取模,需要对其进行哈希计算再取模。
  • 数据结构:

    1
    2
    3
    4
    5
    6
    server_order0
    ├── t_order0
    └── t_order1
    server_order1
    ├── t_order0
    └── t_order1
YAML 配置模式
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
# 逻辑数据库(Schema)的名称
schemaName: sharding_db

# 配置数据源
dataSources:
# 配置第 1 个数据源
server_order0:
url: jdbc:mysql://192.168.2.191:3310/db_order?serverTimezone=UTC&useSSL=false
username: root
password: 123456
connectionTimeoutMilliseconds: 30000
idleTimeoutMilliseconds: 60000
maxLifetimeMilliseconds: 1800000
maxPoolSize: 50
minPoolSize: 1

# 配置第 2 个数据源
server_order1:
url: jdbc:mysql://192.168.2.191:3311/db_order?serverTimezone=UTC&useSSL=false
username: root
password: 123456
connectionTimeoutMilliseconds: 30000
idleTimeoutMilliseconds: 60000
maxLifetimeMilliseconds: 1800000
maxPoolSize: 50
minPoolSize: 1

# 配置分片规则
rules:
- !SHARDING
# 配置分片表规则
tables:
t_order:
# 配置数据节点
actualDataNodes: server_order${0..1}.t_order${0..1}
# 配置分库策略
databaseStrategy:
standard:
shardingColumn: user_id
shardingAlgorithmName: alg_mod
# 配置分表策略
tableStrategy:
standard:
shardingColumn: order_no
shardingAlgorithmName: alg_hash_mod
# 配置分片算法
shardingAlgorithms:
alg_mod:
type: MOD
props:
sharding-count: 2
alg_hash_mod:
type: HASH_MOD
props:
sharding-count: 2
DistSQL 配置模式
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
-- 创建逻辑数据库(Schema)
CREATE DATABASE sharding_db;

-- 切换到逻辑数据库(Schema)
USE sharding_db;

-- 创建第 1 个数据源
ADD RESOURCE server_order0 (
URL="jdbc:mysql://192.168.2.191:3310/db_order?serverTimezone=UTC&useSSL=false",
USER=root,
PASSWORD=123456,
PROPERTIES(
"connectionTimeoutMilliseconds"="30000",
"idleTimeoutMilliseconds"="60000",
"maxLifetimeMilliseconds"="1800000",
"maxPoolSize"="50",
"minPoolSize"="1"
)
);

-- 创建第 2 个数据源
ADD RESOURCE server_order1 (
URL="jdbc:mysql://192.168.2.191:3311/db_order?serverTimezone=UTC&useSSL=false",
USER=root,
PASSWORD=123456,
PROPERTIES(
"connectionTimeoutMilliseconds"="30000",
"idleTimeoutMilliseconds"="60000",
"maxLifetimeMilliseconds"="1800000",
"maxPoolSize"="50",
"minPoolSize"="1"
)
);

-- 创建分片算法
CREATE SHARDING ALGORITHM alg_mod (
TYPE(NAME=MOD,PROPERTIES(
"sharding-count"="2"
)
)
);

-- 创建分片算法
CREATE SHARDING ALGORITHM alg_hash_mod (
TYPE(NAME=HASH_MOD,PROPERTIES(
"sharding-count"="2"
)
)
);

-- 创建分片规则
CREATE SHARDING TABLE RULE t_order (
-- 数据节点
DATANODES("server_order${0..1}.t_order${0..1}"),
-- 分库策略
DATABASE_STRATEGY(
TYPE=STANDARD,
SHARDING_COLUMN=user_id,
SHARDING_ALGORITHM=alg_mod
),
-- 分表策略
TABLE_STRATEGY(
TYPE=STANDARD,
SHARDING_COLUMN=order_no,
SHARDING_ALGORITHM=alg_hash_mod
)
);