1、什么是shardingSphere
Apache ShardingSphere 是一套开源的分布式数据库中间件解决方案组成的生态圈,它由 JDBC、Proxy 和 Sidecar(规划中)这 3 款相互独立,却又能够混合部署配合使用的产品组成。 它们均提供标准化的数据分片、分布式事务和数据库治理功能,可适用于如 Java 同构、异构语言、云原生等各种多样化的应用场景。
Apache ShardingSphere 定位为关系型数据库中间件,旨在充分合理地在分布式的场景下利用关系型数据库的计算和存储能力,而并非实现一个全新的关系型数据库。 它通过关注不变,进而抓住事物本质。关系型数据库当今依然占有巨大市场,是各个公司核心业务的基石,未来也难于撼动,我们目前阶段更加关注在原有基础上的增量,而非颠覆。
Apache ShardingSphere 5.x 版本开始致力于可插拔架构,项目的功能组件能够灵活的以可插拔的方式进行扩展。 目前,数据分片、读写分离、多数据副本、数据加密、影子库压测等功能,以及 MySQL、PostgreSQL、SQLServer、Oracle 等 SQL 与协议的支持,均通过插件的方式织入项目。 开发者能够像使用积木一样定制属于自己的独特系统。Apache ShardingSphere 目前已提供数十个 SPI 作为系统的扩展点,仍在不断增加中。
ShardingSphere 已于2020年4月16日成为 Apache 软件基金会的顶级项目。
1、sharding-JDCB
定位为轻量级Java框架,在Java的JDBC层提供的额外服务。 它使用客户端直连数据库,以jar包形式提供服务,无需额外部署和依赖,可理解为增强版的JDBC驱动,完全兼容JDBC和各种ORM框架。
-
适用于任何基于JDBC的ORM框架,如:JPA, Hibernate, Mybatis, Spring JDBC Template或直接使用JDBC。
-
支持任何第三方的数据库连接池,如:DBCP, C3P0, BoneCP, Druid, HikariCP等。
-
支持任意实现JDBC规范的数据库。目前支持MySQL,Oracle,SQLServer,PostgreSQL以及任何遵循SQL92标准的数据库。
2、sharding-proxy
定位为透明化的数据库代理端,提供封装了数据库二进制协议的服务端版本,用于完成对异构语言的支持。 目前先提供MySQL/PostgreSQL版本,它可以使用任何兼容MySQL/PostgreSQL协议的访问客户端(如:MySQL Command Client, MySQL Workbench, Navicat等)操作数据,对DBA更加友好。
-
向应用程序完全透明,可直接当做MySQL/PostgreSQL使用。
-
适用于任何兼容MySQL/PostgreSQL协议的的客户端。
3、sharding-sidecar
定位为Kubernetes的云原生数据库代理,以Sidecar的形式代理所有对数据库的访问。 通过无中心、零侵入的方案提供与数据库交互的的啮合层,即Database Mesh,又可称数据网格。
Database Mesh的关注重点在于如何将分布式的数据访问应用与数据库有机串联起来,它更加关注的是交互,是将杂乱无章的应用与数据库之间的交互有效的梳理。使用Database Mesh,访问数据库的应用和数据库终将形成一个巨大的网格体系,应用和数据库只需在网格体系中对号入座即可,它们都是被啮合层所治理的对象。
Sharding-JDBC采用无中心化架构,适用于Java开发的高性能的轻量级OLTP应用;Sharding-Proxy提供静态入口以及异构语言的支持,适用于OLAP应用以及对分片数据库进行管理和运维的场景。
ShardingSphere是多接入端共同组成的生态圈。 通过混合使用Sharding-JDBC和Sharding-Proxy,并采用同一注册中心统一配置分片策略,能够灵活的搭建适用于各种场景的应用系统,架构师可以更加自由的调整适合于当前业务的最佳系统架构。
2.为什么要用ShardingShere
原因分析
在分布式架构下,一般是伴随着高并发、数据量庞大等场景,我们很容易想到读写分离,但是读写分离只是在请求层面进行了分散,提高了系统处理的能力。
但是,当数据量达到一定规模时,单库可能难以承载所有的数据和请求,这时候就需要通过分库分表来进一步分散存储和计算压力,也就是引入ShardingShere。
ShardingShere能做到什么
-
数据分片:将数据水平分割到多个数据库中,每个数据库可以独立地进行数据的存储和计算,从而提高了系统的可伸缩性和性能。
-
分布式事务:在分库分表后,跨库的事务管理变得复杂。ShardingSphere 提供了分布式事务的支持,确保了事务的一致性和完整性。
-
读写分离:ShardingSphere 支持读写分离策略,可以智能地将读操作和写操作路由到合适的数据库,进一步提高了系统的读取性能。
-
数据库治理:ShardingSphere 提供了数据库的动态配置、监控、弹性伸缩等治理功能,使得数据库的管理更加方便和高效。
3.什么是垂直/水平分片
垂直分库:
按照业务拆分的方式称为垂直分片,又称为纵向拆分
,它的核心理念是专库专用。 在拆分之前,一个数据库由多个数据表构成,每个表对应着不同的业务。而拆分之后,则是按照业务将表进行归类,分布到不同的数据库中,从而将压力分散至不同的数据库。如下图所示:
这样通过将用户、商品、订单数据库分为三个独立的数据库,缓解了数据存储的压力,但是表也存在存储上限;如果垂直拆分之后,表中的数据量依然超过单节点所能承载的阈值,则需要水平分片来进一步处理。
垂直/水平分表:
垂直分表,适合将表中某些不常用的列,或者是占了大量空间的列拆分出去。
比如,一个用户表可能包含用户的基本信息和地址信息,如果地址信息很少被查询,那么可以将地址信息拆分到另一个表中。垂直分表有助于减少单个表的数据量,提高查询效率 。
水平分表,即将一张表中的记录横向拆成几份,由新的表(表结构相同)来存储
比如,对于日志存储表,我们可以以时间为维度,去进行水平拆分,把不同日期的日志放在不同的表里,也方便整理。
水平分片:
水平分片又称为横向拆分。 相对于垂直分片,它不再将数据根据业务逻辑分类,而是通过某个字段(或某几个字段),根据某种规则将数据分散至多个库或表中,每个分片仅包含数据的一部分。 例如:根据主键分片,偶数主键的记录放入 0 库(或表),奇数主键的记录放入 1 库(或表),如下图所示。
单表进行切分后,是否将多个表分散在不同的数据库服务器中,可以根据实际的切分效果来确定。
PS:
水平分表:单表切分为多表后,新的表即使在同一个数据库服务器中,也可能带来可观的性能提升,如果性能能够满足业务要求,可以不拆分到多台数据库服务器,毕竟业务分库也会引入很多复杂性;
水平分库:如果单表拆分为多表后,单台服务器依然无法满足性能要求,那就需要将多个表分散在不同的数据库服务器中。
阿里巴巴Java开发手册:
【推荐】单表行数超过 500 万行或者单表容量超过 2GB,才推荐进行分库分表。
说明:如果预计三年后的数据量根本达不到这个级别,请不要在创建表时就分库分表
。
4.Springboot整合ShardingShere
引入依赖:
<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>
<!-- 其他依赖省略 -->
配置文件application.yaml:
参数概览:
rules:
- !SHARDING
tables: # 数据分片规则配置
<logic_table_name> (+): # 逻辑表名称
actualDataNodes (?): # 由数据源名 + 表名组成(参考 Inline 语法规则)
databaseStrategy (?): # 分库策略,缺省表示使用默认分库策略,以下的分片策略只能选其一
standard: # 用于单分片键的标准分片场景
shardingColumn: # 分片列名称
shardingAlgorithmName: # 分片算法名称
complex: # 用于多分片键的复合分片场景
shardingColumns: # 分片列名称,多个列以逗号分隔
shardingAlgorithmName: # 分片算法名称
hint: # Hint 分片策略
shardingAlgorithmName: # 分片算法名称
none: # 不分片
tableStrategy: # 分表策略,同分库策略
keyGenerateStrategy: # 分布式序列策略
column: # 自增列名称,缺省表示不使用自增主键生成器
keyGeneratorName: # 分布式序列算法名称
auditStrategy: # 分片审计策略
auditorNames: # 分片审计算法名称
- <auditor_name>
- <auditor_name>
allowHintDisable: true # 是否禁用分片审计hint
autoTables: # 自动分片表规则配置
t_order_auto: # 逻辑表名称
actualDataSources (?): # 数据源名称
shardingStrategy: # 切分策略
standard: # 用于单分片键的标准分片场景
shardingColumn: # 分片列名称
shardingAlgorithmName: # 自动分片算法名称
bindingTables (+): # 绑定表规则列表
- <logic_table_name_1, logic_table_name_2, ...>
- <logic_table_name_1, logic_table_name_2, ...>
defaultDatabaseStrategy: # 默认数据库分片策略
defaultTableStrategy: # 默认表分片策略
defaultKeyGenerateStrategy: # 默认的分布式序列策略
defaultShardingColumn: # 默认分片列名称
# 分片算法配置
shardingAlgorithms:
<sharding_algorithm_name> (+): # 分片算法名称
type: # 分片算法类型
props: # 分片算法属性配置
# ...
# 分布式序列算法配置
keyGenerators:
<key_generate_algorithm_name> (+): # 分布式序列算法名称
type: # 分布式序列算法类型
props: # 分布式序列算法属性配置
# ...
# 分片审计算法配置
auditors:
<sharding_audit_algorithm_name> (+): # 分片审计算法名称
type: # 分片审计算法类型
props: # 分片审计算法属性配置
# ...
- !BROADCAST
tables: # 广播表规则列表
- <table_name>
- <table_name>
读写分离(这里以一主二从为例):
# 应用名称
spring:
application:
name: sharding-jdbc-demo
# 开发环境设置
profiles:
active: dev
# 内存模式
shardingsphere:
mode:
type: Memory
datasource:
names: master,slave1,slave2
master:
type: com.zaxxer.hikari.HikariDataSource
driver-class-name: com.mysql.jdbc.Driver
jdbc-url: jdbc:mysql://127.0.0.1:3306/db_user
username: root
password: 123456
slave1:
type: com.zaxxer.hikari.HikariDataSource
driver-class-name: com.mysql.jdbc.Driver
jdbc-url: jdbc:mysql://127.0.0.1:3307/db_user
username: root
password: 123456
slave2:
type: com.zaxxer.hikari.HikariDataSource
driver-class-name: com.mysql.jdbc.Driver
jdbc-url: jdbc:mysql://127.0.0.1:3308/db_user
username: root
password: 123456
rules:
readwrite-splitting:
data-sources:
myds:
type: Static ## 使用静态读写分离策略
props:
write-data-source-name: master
read-data-source-names: slave1,slave2
load-balancers:
alg_round:
type: ROUND_ROBIN # 轮询负载均衡算法
alg_random:
type: RANDOM # 随机负载均衡算法
alg_weight:
type: WEIGHT # 加权负载均衡算法
props:
slave1: 1 # slave1 数据源的权重
slave2: 2 # slave2 数据源的权重
# 打印SQL
props:
sql-show: true # 开启 SQL 打印功能,方便调试
Ps:
-
静态读写分离 Static: 是指传统的主从数据库配置,通过 write-data-source-name 和 read-data-source-names 指定读写库,这个关系是静态的。
-
动态读写分离 Dynamic: 适用于 MGR 这种 DB 集群,集群内部的主节点是可以动态变换的,ShardingSphere 中需要动态去探测哪个节点是主节点。
数据分片:
-
rules: - !SHARDING tables: # 数据分片规则配置 <logic-table-name> (+): # 逻辑表名称 actualDataNodes (?): # 由数据源名 + 表名组成(参考 Inline 语法规则) databaseStrategy (?): # 分库策略,缺省表示使用默认分库策略,以下的分片策略只能选其一 standard: # 用于单分片键的标准分片场景 shardingColumn: # 分片列名称 shardingAlgorithmName: # 分片算法名称 complex: # 用于多分片键的复合分片场景 shardingColumns: # 分片列名称,多个列以逗号分隔 shardingAlgorithmName: # 分片算法名称 hint: # Hint 分片策略 shardingAlgorithmName: # 分片算法名称 none: # 不分片 tableStrategy: # 分表策略,同分库策略 keyGenerateStrategy: # 分布式序列策略 column: # 自增列名称,缺省表示不使用自增主键生成器 keyGeneratorName: # 分布式序列算法名称 autoTables: # 自动分片表规则配置 t_order_auto: # 逻辑表名称 actualDataSources (?): # 数据源名称 shardingStrategy: # 切分策略 standard: # 用于单分片键的标准分片场景 shardingColumn: # 分片列名称 shardingAlgorithmName: # 自动分片算法名称 bindingTables (+): # 绑定表规则列表 - <logic_table_name_1, logic_table_name_2, ...> - <logic_table_name_1, logic_table_name_2, ...> broadcastTables (+): # 广播表规则列表 - <table-name> - <table-name> defaultDatabaseStrategy: # 默认数据库分片策略 defaultTableStrategy: # 默认表分片策略 defaultKeyGenerateStrategy: # 默认的分布式序列策略 defaultShardingColumn: # 默认分片列名称 # 分片算法配置 shardingAlgorithms: <sharding-algorithm-name> (+): # 分片算法名称 type: # 分片算法类型 props: # 分片算法属性配置 # ... # 分布式序列算法配置 keyGenerators: <key-generate-algorithm-name> (+): # 分布式序列算法名称 type: # 分布式序列算法类型 props: # 分布式序列算法属性配置 # ...