ShardingSphere简介与分表使用
一、ShardingSphere简介
1、简介
ShardingSphere 已于 2020 年 4 月 16 日成为 Apache 软件基金会的顶级项目。
ShardingSphere 是一套开源的分布式数据库中间件解决方案。
ShardingSphere 产品定位为 Database Plus,旨在构建异构数据库上层的标准和生态圈。
它关注如何充分合理地利用数据库的计算和存储能力,而并非实现一个全新的数据库。
ShardingSphere 站在数据库的上层视角,关注他们之间的协作多于数据库自身。
它由ShardingSphere-JDBC、ShardingSphere-Proxy 和 ShardingSphere-Sidecar这3款相互独立的产品组成。
- ShardingSphere-JDBC:定位为轻量级 Java 框架,在 Java 的 JDBC 层提供的额外服务。
- ShardingSphere-Proxy:定位为透明化的数据库代理端,提供封装了数据库二进制协议的服务端版本,用于完成对异构语言的支持。
- ShardingSphere-Sidecar:定位为 Kubernetes 的云原生数据库代理,以 Sidecar 的形式代理所有对数据库的访问。
2、核心概念
2.1 表概念
1)真实表
在数据库中真实存在的物理表。例如:t_order_0、t_order_1
2)逻辑表
在分片之后,同一类表结构的名称(总成)。例如b_order。
水平拆分的数据库(表)的相同逻辑和数据结构表的总称。例如:订单表根据主键尾数拆分为10张真实表(t_order_0到t_order_9),他们的逻辑表名为t_order。
3)数据节点
在分片之后,由数据源和数据表组成。例如ds0.b_order1
数据分片的最小单元。由数据源名称和数据表组成,例如:ds_0.t_order_0。
4)绑定表
指的是分片规则一致的关系表(主表、子表)。
例如:t_order表和t_order_item表,均按照order_id分片,则此两张表互为绑定表关系。绑定表之间的多表关联查询不会出现笛卡尔积关联,关联查询效率将大大提升。
举例说明,如果SQL为:
SELECT i.* FROM t_order o JOIN t_order_item i ON o.order_id=i.order_id WHERE o.order_id in (10, 11);
在不配置绑定表关系时,假设分片键order_id将数值10路由至第0片,将数值11路由至第1片,那么路由后的SQL应该为4条,它们呈现为笛卡尔积:
SELECT i.* FROM t_order_0 o JOIN t_order_item_0 i ON o.order_id=i.order_id WHERE o.order_id in (10, 11);
SELECT i.* FROM t_order_0 o JOIN t_order_item_1 i ON o.order_id=i.order_id WHERE o.order_id in (10, 11);
SELECT i.* FROM t_order_1 o JOIN t_order_item_0 i ON o.order_id=i.order_id WHERE o.order_id in (10, 11);
SELECT i.* FROM t_order_1 o JOIN t_order_item_1 i ON o.order_id=i.order_id WHERE o.order_id in (10, 11);
在配置绑定表关系后,路由的SQL应该为2条:
SELECT i.* FROM t_order_0 o JOIN t_order_item_0 i ON o.order_id=i.order_id WHERE o.order_id in (10, 11);
SELECT i.* FROM t_order_1 o JOIN t_order_item_1 i ON o.order_id=i.order_id WHERE o.order_id in (10, 11);
其中t_order在FROM的最左侧,ShardingSphere将会以它作为整个绑定表的主表。 所有路由计算将会只使用主表的策略,那么t_order_item表的分片计算将会使用t_order的条件。故绑定表之间的分区键要完全相同。
5)广播表
广播表是指所有的分片数据源中都存在的表,表结构和表中的数据在每个数据库中均完全一致。
适用于数据量不大且需要与海量数据的表进行关联查询的场景,这些表没必要做分片。
例如:例如字典表、省份信息等,因为他们数据量不大,而且这种表可能需要与海量数据的表进行关联查询。
2.2 分片概念
1)分片键
用于分片的数据库字段,是将数据库(表)水平拆分的关键字段。
例如:将订单表中的订单主键的尾数取模分片,则订单主键为分片字段。 SQL中如果无分片字段,将执行全路由,性能较差。 除了对单分片字段的支持,ShardingSphere也支持根据多个字段进行分片。
2)分片算法
通过分片算法(ShardingAlgorithm)将数据分片,支持通过=、>=、<=、>、<、BETWEEN和IN分片。
分片算法需要应用方开发者自行实现,可实现的灵活度非常高。
目前提供4种分片算法。由于分片算法和业务实现紧密相关,因此并未提供内置分片算法,而是通过分片策略将各种场景提炼出来,提供更高层级的抽象,并提供接口让应用开发者自行实现分片算法。
- 精确分片算法,
对应PreciseShardingAlgorithm,用于处理使用单一键作为分片键的=与IN进行分片的场景。需要配合StandardShardingStrategy使用。 - 范围分片算法
对应RangeShardingAlgorithm,用于处理使用单一键作为分片键的BETWEEN AND、>、<、>=、<=进行分片的场景。需要配合StandardShardingStrategy使用。 - 复合分片算法
对应ComplexKeysShardingAlgorithm,用于处理使用多键作为分片键进行分片的场景,包含多个分片键的逻辑较复杂,需要应用开发者自行处理其中的复杂度。需要配合ComplexShardingStrategy使用。 - Hint分片算法
对应HintShardingAlgorithm,用于处理使用Hint行分片的场景。需要配合HintShardingStrategy使用。
3)分片策略
包含分片键和分片算法,由于分片算法的独立性,将其独立抽离。真正可用于分片操作的是分片键 + 分片算法,也就是分片策略。
目前提供5种分片策略:
- 标准分片策略,对应StandardShardingStrategy。
- 复合分片策略,对应ComplexShardingStrategy。
- 行表达式分片策略,对应InlineShardingStrategy。
- Hint分片策略,对应HintShardingStrategy。
- 不分片策略,对应NoneShardingStrategy。
4)分片策略配置
对于分片策略存有数据源分片策略和表分片策略两种维度,两种策略的API完全相同。
- 数据源分片策略
用于配置数据被分配的目标数据源。
- 表分片策略
用于配置数据被分配的目标表,由于表存在与数据源内,所以表分片策略是依赖数据源分片策略结果的。
二、简单入门
ShardingJDBC是整个ShardingSphere最早也是最为核心的一个功能模块,它的主要功能就是数据分片和读写分离等。
下面通过一个单数据源分表的实例来了解 ShardingSphere的使用。
- 创建数据库 sharding_db1
- 在数据库创建两张表 course_1 和 course_2
约定分片规则
:如果添加课程 id 是偶数,则把数据添加 course_1表,如果是奇数添加到 course_2表。
CREATE TABLE course_1 (
id BIGINT(20) PRIMARY KEY,
gmt_create timestamp NULL DEFAULT NULL,
name VARCHAR(50) NOT NULL,
user_id BIGINT(20) NOT NULL,
status varchar(10) NOT NULL
);
CREATE TABLE course_2 (
id BIGINT(20) PRIMARY KEY,
gmt_create timestamp NULL DEFAULT NULL,
name VARCHAR(50) NOT NULL,
user_id BIGINT(20) NOT NULL,
status varchar(10) NOT NULL
);
1、引入依赖
创建一个springboot项目。
<!-- shardingJDBC核心依赖 -->
<dependency>
<groupId>org.apache.shardingsphere</groupId>
<artifactId>sharding-jdbc-spring-boot-starter</artifactId>
<version>4.1.1</version>
</dependency>
<!--druid连接池-->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid</artifactId>
<version>1.2.8</version>
</dependency>
<!-- mysql连接驱动 -->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>8.0.23</version>
</dependency>
<!--mybatis-plus依赖-->
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-boot-starter</artifactId>
<version>3.4.1</version>
</dependency>
2、编写代码
创建实体类,mapper。这里使用 MybatisPlus 比较简单,CRUD基本满足我们的示例。
我们重点关注分库分表的数据落库。
3、application.properties 配置文件
在项目 application.properties 配置文件中进行 ShardingSphere配置。
# 配置真实数据源
spring.shardingsphere.datasource.names=db1
# 配置第1个数据源
spring.shardingsphere.datasource.db1.type=com.alibaba.druid.pool.DruidDataSource
spring.shardingsphere.datasource.db1.driver-class-name=com.mysql.cj.jdbc.Driver
spring.shardingsphere.datasource.db1.url=jdbc:mysql://localhost:3306/sharding_db1?useUnicode=true&characterEncoding=utf8&useSSL=true&serverTimezone=GMT
spring.shardingsphere.datasource.db1.username=root
spring.shardingsphere.datasource.db1.password=123456
# 指定表的分布情况
spring.shardingsphere.sharding.tables.course.actual-data-nodes=db1.course_$->{1..2}
# 指定表的主键生成策略,雪花算法
spring.shardingsphere.sharding.tables.course.key-generator.column=id
spring.shardingsphere.sharding.tables.course.key-generator.type=SNOWFLAKE
spring.shardingsphere.sharding.tables.course.key-generator.props.worker.id=1
##指定分片策略,约定id值为偶数添加到 course_1表,奇数添加到 course_2表。
#表策略
spring.shardingsphere.sharding.tables.course.table-strategy.inline.sharding-column=id
spring.shardingsphere.sharding.tables.course.table-strategy.inline.algorithm-expression=course_$->{id%2+1}
# 打开shardingsphere的sql日志输出。
spring.shardingsphere.props.sql.show=true
spring.main.allow-bean-definition-overriding=true
4、测试代码
1) 保存
@Test
public void testSave() throws InterruptedException {
for (int i = 0; i < 20; i++) {
Course course = new Course();
course.setGmtCreate(new Date());
course.setName("java");
course.setUserId(1001L + i);
course.setStatus("1");
TimeUnit.MILLISECONDS.sleep(50);
int count = courseMapper.insert(course);
System.out.println("id ->" + course.getId());
}
}
数据按照我们的分表规则落库ok,
2)查询
@Test
public void testGetById() {
QueryWrapper<Course> wrapper = new QueryWrapper<Course>();
// wrapper.eq("id",1513890338544734210L);
wrapper.in("id",1513890338544734210L, 1513890342613209090L);
List<Course> courses = courseMapper.selectList(wrapper);
System.out.println(courses.size());
courses.forEach(course -> System.out.println(course));
}
因为使用的是 行表达式分片策略(inline),只支持分片键的=与IN进行分片的场景
wrapper.between(“id”, 1513890338544734210L, 1513890342613209090L);
到此,ShardingSphere简单使用就算入门了。
参考文章:
- ShardingSphere官方网址:https://shardingsphere.apache.org/document/current/cn/overview/
- ShardingSphere基本介绍及核心概念:https://blog.csdn.net/Kiven_ch/article/details/119087048
– 求知若饥,虚心若愚。