简介
ShardingSphere 是一套开源的分布式数据库解决方案组成的生态圈,它由 JDBC、Proxy 和 Sidecar(规划中)这 3 款既能够独立部署,又支持混合部署配合使用的产品组成。 它们均提供标准化的数据水平扩展、分布式事务和分布式治理等功能,可适用于如 Java 同构、异构语言、云原生等各种多样化的应用场景。
ShardingSphere 已于2020年4月16日成为 Apache 软件基金会的顶级项目。
主要功能
数据分片 | 分布式事务 | 数据库治理 |
分库分表 | 标准化事务接口 | 配置动态化 |
读写分离 | XA强一致事务 | 编排治理 |
分片策略定制化 | 柔性事务 | 数据脱敏 |
无中心化分布式主键 | 可视化链路追踪 |
核心三件套
Sharding-JDBC | Sharding-Proxy | Sharding-Sidecar | |
数据库 | 任意 | MySQL | MySQL |
连接消耗数 | 高 | 低 | 高 |
异构语言 | JAVA | 任意 | 任意 |
性能 | 损耗低 | 损耗略高 | 损耗低 |
无中心化 | 是 | 否 | 是 |
静态入口 | 无 | 有 | 无 |
Sharding-JDBC
客户端直连数据库,以jar包形式提供服务,无需额外部署和依赖,可以理解为增强版的JDBC驱动,完全兼容JDBC和各种ORM框架。
- 适用于任何基于JDBC的ORM框架:JPA、Hibernate、Mybatis、Spring JDBC Template或直接使用JDBC。
- 支持任务第三方的数据库连接池:DBCP、C3P0、BoneCP、Druid、HikariCP等。
- 支持任意实现JDBC规范的数据库。支持MySQL、Oracle、SQLServer、PostgreSQL等数据库。
Sharding-Proxy
透明化的数据库代理端,兼容所有MySQL/PostgreSQL协议的客户端。
- 向应用程序完全透明,可直接当做MySQL服务使用。
- 适用于任何兼容MySQL/PostgreSQL协议的客户端。
核心概念
逻辑表
水平拆分的数据库(表)的相同逻辑和数据结构表的总称。例如:订单表拆分成t_order_0到t_order_9,他们的逻辑表名为t_order。
真实表
在分片的数据库中真实存在的物理表,即t_order_0到t_order_9。
数据节点
数据分片的最小单元。由数据源名称和数据表组成,例如:database_0.t_order_0。
绑定表
分片规则一致的主表和从表。例如:t_order和t_order_item,均按照order_id分片,则此两表互为绑定表关系。绑定表之间的多表关联查询不会出现笛卡尔集,关联查询效率大大提升。
广播表
指所有的分片数据源都存在的表,表结构和数据完全一致。适用于数据量不大且需要与海量数据的表进行关联查询的场景,例如字典表。
实战配置
SpringBoot+Mybatis+Sharding-JDBC
<dependency>
<groupId>org.apache.shardingsphere</groupId>
<artifactId>shardingsphere-jdbc-core-spring-boot-starter</artifactId>
<version>${shardingsphere.version}</version>
</dependency>
分库分表配置
# 配置ds0 和ds1两个数据源
spring.shardingsphere.datasource.names=ds0,ds1
#ds0 配置
spring.shardingsphere.datasource.ds0.type=com.zaxxer.hikari.HikariDataSource
spring.shardingsphere.datasource.ds0.driver-class-name=com.mysql.jdbc.Driver
spring.shardingsphere.datasource.ds0.jdbc-url=jdbc:mysql://localhost:3306/shop_ds_0?serverTimezone=UTC&useSSL=false&useUnicode=true&characterEncoding=UTF-8
spring.shardingsphere.datasource.ds0.username=root
spring.shardingsphere.datasource.ds0.password=root
#ds1 配置
spring.shardingsphere.datasource.ds1.type=com.zaxxer.hikari.HikariDataSource
spring.shardingsphere.datasource.ds1.driver-class-name=com.mysql.jdbc.Driver
spring.shardingsphere.datasource.ds1.jdbc-url=jdbc:mysql://localhost:3306/shop_ds_1?serverTimezone=UTC&useSSL=false&useUnicode=true&characterEncoding=UTF-8
spring.shardingsphere.datasource.ds1.username=root
spring.shardingsphere.datasource.ds1.password=root
# 分库策略 根据id取模确定数据进哪个数据库
spring.shardingsphere.sharding.default-database-strategy.inline.sharding-column=user_id
spring.shardingsphere.sharding.default-database-strategy.inline.algorithm-expression=ds$->{user_id % 2}
spring.shardingsphere.sharding.binding-tables=t_order,t_order_item
spring.shardingsphere.sharding.broadcast-tables=t_address
# 具体分表策略
# 节点 ds0.t_order_0,ds0.t_order_1,ds1.t_order_0,ds1.t_order_1
spring.shardingsphere.sharding.tables.t_order.actual-data-nodes=ds$->{0..1}.t_order_$->{0..1}
# 分表字段id
spring.shardingsphere.sharding.tables.t_order.table-strategy.inline.sharding-column=order_id
# 分表策略 根据id取模,确定数据最终落在那个表中
spring.shardingsphere.sharding.tables.t_order.table
-strategy.inline.algorithm-expression = t_order_$->{order_id % 2}
# 使用SNOWFLAKE算法生成主键
spring.shardingsphere.sharding.tables.t_order.key-generator.column=order_id
spring.shardingsphere.sharding.tables.t_order.key-generator.type=SNOWFLAKE
spring.shardingsphere.sharding.tables.t_order.key-generator.props.worker.id=123
# 节点 ds0.t_order_item_0,ds0.t_order_item_1,ds1.t_order_item_0,ds1.t_order_item_1
spring.shardingsphere.sharding.tables.t_order_item.actual-data-nodes=ds$->{0..1}.t_order_item_$->{0..1}
# 分表字段id
spring.shardingsphere.sharding.tables.t_order_item.table-strategy.inline.sharding-column=order_id
# 分表策略 根据id取模,确定数据最终落在那个表中
spring.shardingsphere.sharding.tables.t_order_item.table-strategy.inline.algorithm-expression=t_order_item_$->{order_id % 2}
# 使用SNOWFLAKE算法生成主键
spring.shardingsphere.sharding.tables.t_order_item.key-generator.column=order_item_id
spring.shardingsphere.sharding.tables.t_order_item.key-generator.type=SNOWFLAKE
spring.shardingsphere.sharding.tables.t_order_item.key-generator.props.worker.id=123
读写分离配置
#shardingsphere 读写分离,master-slave,可以一主多从
spring.shardingsphere.datasource.names=ds-master,ds-slave0
#主库
spring.shardingsphere.datasource.ds-master.type=com.zaxxer.hikari.HikariDataSource
spring.shardingsphere.datasource.ds-master.driver-class-name=com.mysql.jdbc.Driver
spring.shardingsphere.datasource.ds-master.jdbc-url=jdbc:mysql://localhost:3306/shop_ds_master?serverTimezone=UTC&useSSL=false&useUnicode=true&characterEncoding=UTF-8
spring.shardingsphere.datasource.ds-master.username=root
spring.shardingsphere.datasource.ds-master.password=root
#从库0
spring.shardingsphere.datasource.ds-slave0.type=com.zaxxer.hikari.HikariDataSource
spring.shardingsphere.datasource.ds-slave0.driver-class-name=com.mysql.jdbc.Driver
spring.shardingsphere.datasource.ds-slave0.jdbc-url=jdbc:mysql://localhost:3306/shop_ds_slave?serverTimezone=UTC&useSSL=false&useUnicode=true&characterEncoding=UTF-8
spring.shardingsphere.datasource.ds-slave0.username=root
spring.shardingsphere.datasource.ds-slave0.password=root
#从库1
#spring.shardingsphere.datasource.ds-slave1.type=com.zaxxer.hikari.HikariDataSource
#spring.shardingsphere.datasource.ds-slave1.driver-class-name=com.mysql.jdbc.Driver
#spring.shardingsphere.datasource.ds-slave1.jdbc-url=jdbc:mysql://localhost:3306/shop_ds_slave1?serverTimezone=UTC&useSSL=false&useUnicode=true&characterEncoding=UTF-8
#spring.shardingsphere.datasource.ds-slave1.username=root
#spring.shardingsphere.datasource.ds-slave1.password=root
#读写分离主从规则设置,当有2个以上从库时,从库读采用轮询的负载均衡机制
spring.shardingsphere.masterslave.load-balance-algorithm-type=round_robin
spring.shardingsphere.masterslave.name=ms
spring.shardingsphere.masterslave.master-data-source-name=ds-master
spring.shardingsphere.masterslave.slave-data-source-names=ds-slave0
读写分离+分库分表配置
#shardingsphere 读写分离+分库分表,master-slave-sharding,可以一主多从
spring.shardingsphere.datasource.names=ds-master0,ds-slave0,ds-master1,ds-slave1
#主库0
spring.shardingsphere.datasource.ds-master0.type=com.zaxxer.hikari.HikariDataSource
spring.shardingsphere.datasource.ds-master0.driver-class-name=com.mysql.jdbc.Driver
spring.shardingsphere.datasource.ds-master0.jdbc-url=jdbc:mysql://localhost:3306/shop_ds_master?serverTimezone=UTC&useSSL=false&useUnicode=true&characterEncoding=UTF-8
spring.shardingsphere.datasource.ds-master0.username=root
spring.shardingsphere.datasource.ds-master0.password=root
#从库0
spring.shardingsphere.datasource.ds-slave0.type=com.zaxxer.hikari.HikariDataSource
spring.shardingsphere.datasource.ds-slave0.driver-class-name=com.mysql.jdbc.Driver
spring.shardingsphere.datasource.ds-slave0.jdbc-url=jdbc:mysql://localhost:3306/shop_ds_slave?serverTimezone=UTC&useSSL=false&useUnicode=true&characterEncoding=UTF-8
spring.shardingsphere.datasource.ds-slave0.username=root
spring.shardingsphere.datasource.ds-slave0.password=root
#主库1
spring.shardingsphere.datasource.ds-master1.type=com.zaxxer.hikari.HikariDataSource
spring.shardingsphere.datasource.ds-master1.driver-class-name=com.mysql.jdbc.Driver
spring.shardingsphere.datasource.ds-master1.jdbc-url=jdbc:mysql://localhost:3306/shop_ds_master1?serverTimezone=UTC&useSSL=false&useUnicode=true&characterEncoding=UTF-8
spring.shardingsphere.datasource.ds-master1.username=root
spring.shardingsphere.datasource.ds-master1.password=root
#从库1
spring.shardingsphere.datasource.ds-slave1.type=com.zaxxer.hikari.HikariDataSource
spring.shardingsphere.datasource.ds-slave1.driver-class-name=com.mysql.jdbc.Driver
spring.shardingsphere.datasource.ds-slave1.jdbc-url=jdbc:mysql://localhost:3306/shop_ds_slave1?serverTimezone=UTC&useSSL=false&useUnicode=true&characterEncoding=UTF-8
spring.shardingsphere.datasource.ds-slave1.username=root
spring.shardingsphere.datasource.ds-slave1.password=root
# 分库策略 根据id取模确定数据进哪个数据库
spring.shardingsphere.sharding.default-database-strategy.inline.sharding-column=user_id
spring.shardingsphere.sharding.default-database-strategy.inline.algorithm-expression=ds_$->{user_id % 2}
spring.shardingsphere.sharding.binding-tables=t_order,t_order_item
spring.shardingsphere.sharding.broadcast-tables=t_address
#分表策略
spring.shardingsphere.sharding.tables.t_order.actual-data-nodes=ds_$->{0..1}.t_order_$->{0..1}
spring.shardingsphere.sharding.tables.t_order.table-strategy.inline.sharding-column=order_id
spring.shardingsphere.sharding.tables.t_order.table-strategy.inline.algorithm-expression=t_order_$->{order_id % 2}
spring.shardingsphere.sharding.tables.t_order.key-generator.column=order_id
spring.shardingsphere.sharding.tables.t_order.key-generator.type=SNOWFLAKE
spring.shardingsphere.sharding.tables.t_order.key-generator.props.worker.id=123
spring.shardingsphere.sharding.tables.t_order_item.actual-data-nodes=ds_$->{0..1}.t_order_item_$->{0..1}
spring.shardingsphere.sharding.tables.t_order_item.table-strategy.inline.sharding-column=order_id
spring.shardingsphere.sharding.tables.t_order_item.table-strategy.inline.algorithm-expression=t_order_item_$->{order_id % 2}
spring.shardingsphere.sharding.tables.t_order_item.key-generator.column=order_item_id
spring.shardingsphere.sharding.tables.t_order_item.key-generator.type=SNOWFLAKE
spring.shardingsphere.sharding.tables.t_order_item.key-generator.props.worker.id=123
#读写分离数据源0
spring.shardingsphere.sharding.master-slave-rules.ds_0.master-data-source-name=ds-master0
spring.shardingsphere.sharding.master-slave-rules.ds_0.slave-data-source-names=ds-slave0
#读写分离主从规则设置,当有2个以上从库时,从库读采用轮询的负载均衡机制
spring.shardingsphere.sharding.master-slave-rules.ds_0.load-balance-algorithm-type=ROUND_ROBIN
#读写分离数据源1
spring.shardingsphere.sharding.master-slave-rules.ds_1.master-data-source-name=ds-master1
spring.shardingsphere.sharding.master-slave-rules.ds_1.slave-data-source-names=ds-slave1
#读写分离主从规则设置,当有2个以上从库时,从库读采用轮询的负载均衡机制
spring.shardingsphere.sharding.master-slave-rules.ds_1.load-balance-algorithm-type=ROUND_ROBIN
实现原理
源码模块
模块名称 | 作用 |
sharding-core | sharding内核模块;定义了核心api,SQL解析,SQL重写,SQL路由,spi,引擎等等核心功能 |
sharding-distribution | 部署、运维相关zip包中的代码 |
sharding-integration-test | 整合测试 |
sharding-jdbc | app-分库分表jdbc增强 |
sharding-opentracing | 应用性能监控 |
sharding-orchestration | 数据库编排治理 |
sharding-proxy | 服务端代理分库分表模块 |
sharding-spring | 与spring集成 |
sharding-sql-test | SQL测试用例 |
sharding-transaction | 分布式事务 |
数据分片执行过程
解析引擎
解析过程分为词法解析和语法解析。 词法解析器用于将SQL拆解为不可再分的原子符号,称为Token。并根据不同数据库方言所提供的字典,将其归类为关键字,表达式,字面量和操作符。 再使用语法解析器将SQL转换为抽象语法树。
路由引擎
内置的分片策略大致可分为尾数取模、哈希、范围、标签、时间等。 由用户方配置的分片策略则更加灵活,可以根据使用方需求定制复合分片策略。
SQL改写
在分表的场景中,需要将分表配置中的逻辑表名称改写为路由之后所获取的真实表名称。
执行引擎
结果归并
将从各个数据节点获取的多数据结果集,组合成为一个结果集并正确的返回至请求客户端,称为结果归并。
三个核心类
核心类基本都是在jdbc的基础上封装了一层,扩展了路由、分片等逻辑。
- ShardingDataSource:增加了ShardingRule路由规则(包括分布式主键ShardingKeyGenerator),ShardingRuntimeContext上下文。
- ShardingConnection:增加了datasource数据源map,runtimeContext上下文,TransactiontType事务类型。
- ShardingStatement:主要实现了executeQuery()等查询方法,包括主要方法:清理准备环境clearPrevious()、准备分片shard(sql)、初始化查询器initStatementExecutor()、执行查询&归并引擎并归并结果MergeEngineFactory.newInstance()、清理工作准备环境clearPrevious()。