赞
踩
在 spring boot
和 dynamic-datasource
实现了数据库的读写分离的基础上,增加分库分表的功能。
<properties> <java.version>8</java.version> <snakeyaml.version>1.33</snakeyaml.version> </properties> <dependencies> <!-- druid连接池 --> <dependency> <groupId>com.alibaba</groupId> <artifactId>druid-spring-boot-starter</artifactId> <version>1.2.20</version> </dependency> <!--dynamic-datasource--> <dependency> <groupId>com.baomidou</groupId> <artifactId>dynamic-datasource-spring-boot-starter</artifactId> <version>3.6.1</version> </dependency> <!-- shardingsphere-jdbc --> <dependency> <groupId>org.apache.shardingsphere</groupId> <artifactId>shardingsphere-jdbc-core</artifactId> <version>5.4.1</version> </dependency> </dependencies>
snakeyaml
版本spring boot
可以通过properties
进行配置<snakeyaml.version>1.33</snakeyaml.version>
shardingsphere-jdbc-core-spring-boot-starter
与 shardingsphere-jdbc-core
选型5.2.1
版本之后修改了配置方式,不再单独提供spring boot
版本依赖,统一使用shardingsphere-jdbc-core
shardingsphere-jdbc-core-spring-boot-starter
:配置文件写在application.yml
里shardingsphere-jdbc-core
:使用专门的驱动类,配置文件写在单独的yaml文件里shardingsphere-jdbc-core
Maven Centraldynamic-datasource-spring-boot-starter
Maven Centraldruid-spring-boot-starter
Maven Centralspring boot
配置文件:application.yml
spring: datasource: dynamic: primary: master strict: false datasource: master: url: jdbc:mysql://localhost:3306/dirk?serverTimezone=UTC&useSSL=false&useUnicode=true&characterEncoding=UTF-8 username: root password: root driver-class-name: com.mysql.cj.jdbc.Driver slave_1: url: jdbc:mysql://localhost:3306/dirk?serverTimezone=UTC&useSSL=false&useUnicode=true&characterEncoding=UTF-8 username: root password: root driver-class-name: com.mysql.cj.jdbc.Driver sharding: url: jdbc:shardingsphere:classpath:sharding-sphere-config.yaml driver-class-name: org.apache.shardingsphere.driver.ShardingSphereDriver
shardingsphere-jdbc
配置文件mode: type: Standalone repository: type: JDBC dataSources: write: dataSourceClassName: com.alibaba.druid.pool.DruidDataSource driverClassName: com.mysql.jdbc.Driver url: jdbc:mysql://localhost:3306/dirk?serverTimezone=UTC&useSSL=false&useUnicode=true&characterEncoding=UTF-8 username: root password: root read: dataSourceClassName: com.alibaba.druid.pool.DruidDataSource driverClassName: com.mysql.jdbc.Driver url: jdbc:mysql://localhost:3306/dirk?serverTimezone=UTC&useSSL=false&useUnicode=true&characterEncoding=UTF-8 username: root password: root rules: - !SHARDING autoTables: sharding_test: actualDataSources: write keyGenerateStrategy: column: id keyGeneratorName: snowflake shardingStrategy: standard: shardingColumn: id shardingAlgorithmName: auto_mod shardingAlgorithms: auto_mod: type: MOD props: sharding-count: 3 keyGenerators: snowflake: type: SNOWFLAKE - !READWRITE_SPLITTING dataSources: write: writeDataSourceName: write readDataSourceNames: - read loadBalancerName: round_robin loadBalancers: round_robin: type: ROUND_ROBIN props: sql-show: true
spring boot
默认数据库配置spring:
datasource:
# 配置 DataSource Driver
driver-class-name: org.apache.shardingsphere.driver.ShardingSphereDriver
# 指定 YAML 配置文件
url: jdbc:shardingsphere:classpath:xxx.yaml
dynamic-datasource
配置数据库spring: datasource: dynamic: primary: master strict: false datasource: master: url: jdbc:mysql://localhost:3306/dirk?serverTimezone=UTC&useSSL=false&useUnicode=true&characterEncoding=UTF-8 username: root password: root driver-class-name: com.mysql.jdbc.Driver slave_1: url: jdbc:mysql://localhost:3306/dirk?serverTimezone=UTC&useSSL=false&useUnicode=true&characterEncoding=UTF-8 username: root password: root driver-class-name: com.mysql.jdbc.Driver sharding: url: jdbc:shardingsphere:classpath:sharding-sphere-config.yaml driver-class-name: org.apache.shardingsphere.driver.ShardingSphereDriver
ShardingSphere-JDBC 支持所有的数据库 JDBC 驱动和连接池。
示例的数据库驱动为 MySQL,连接池为 HikariCP,可以更换为其他数据库驱动和连接池。当使用 ShardingSphere-JDBC 时,JDBC 池的属性名取决于各自 JDBC 池自己的定义,并不由 ShardingSphere 定义,相关的处理可以参考类org.apache.shardingsphere.infra.datasource.pool.creator.DataSourcePoolCreator
。例如对于 Alibaba Druid 1.2.9 而言,使用 url
代替如下示例中的 jdbcUrl
是预期行为。
dataSources: # 数据源配置,可配置多个 <data-source-name>
<data_source_name>: # 数据源名称
dataSourceClassName: # 数据源完整类名
driverClassName: # 数据库驱动类名,以数据库连接池自身配置为准
jdbcUrl: # 数据库 URL 连接,以数据库连接池自身配置为准
username: # 数据库用户名,以数据库连接池自身配置为准
password: # 数据库密码,以数据库连接池自身配置为准
# ... 数据库连接池的其它属性
dataSources:
write:
dataSourceClassName: com.alibaba.druid.pool.DruidDataSource
driverClassName: com.mysql.jdbc.Driver
url: jdbc:mysql://localhost:3306/dirk?serverTimezone=UTC&useSSL=false&useUnicode=true&characterEncoding=UTF-8
username: root
password: root
read:
dataSourceClassName: com.alibaba.druid.pool.DruidDataSource
driverClassName: com.mysql.jdbc.Driver
url: jdbc:mysql://localhost:3306/dirk?serverTimezone=UTC&useSSL=false&useUnicode=true&characterEncoding=UTF-8
username: root
password: root
相同结构的水平拆分数据库(表)的逻辑名称,是 SQL 中表的逻辑标识。 例:订单数据根据主键尾数拆分为 10 张表,分别是 t_order_0
到 t_order_9
,他们的逻辑表名为 t_order
。
在水平拆分的数据库中真实存在的物理表。 即上个示例中的 t_order_0
到 t_order_9
。
指分片规则一致的一组分片表。 使用绑定表进行多表关联查询时,必须使用分片键进行关联,否则会出现笛卡尔积关联或跨库关联,从而影响查询效率。 例如:t_order
表和 t_order_item
表,均按照 order_id
分片,并且使用 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);
在配置绑定表关系,并且使用 order_id
进行关联后,路由的 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
表由于指定了分片条件,ShardingSphere 将会以它作为整个绑定表的主表。 所有路由计算将会只使用主表的策略,那么 t_order_item
表的分片计算将会使用 t_order
的条件。
注意:绑定表中的多个分片规则,需要按照逻辑表前缀组合分片后缀的方式进行配置,例如:
rules:
- !SHARDING
tables:
t_order:
actualDataNodes: ds_${0..1}.t_order_${0..1}
t_order_item:
actualDataNodes: ds_${0..1}.t_order_item_${0..1}
指所有的数据源中都存在的表,表结构及其数据在每个数据库中均完全一致。 适用于数据量不大且需要与海量数据的表进行关联查询的场景,例如:字典表。
指所有的分片数据源中仅唯一存在的表。 适用于数据量不大且无需分片的表。
注意:符合以下条件的单表会被自动加载:
其余不符合上述条件的单表,ShardingSphere 不会自动加载,用户可根据需要配置单表规则进行管理。
用于将数据库(表)水平拆分的数据库字段。 例:将订单表中的订单主键的尾数取模分片,则订单主键为分片字段。 SQL 中如果无分片字段,将执行全路由,性能较差。 除了对单分片字段的支持,Apache ShardingSphere 也支持根据多个字段进行分片。
用于将数据分片的算法,支持 =
、>=
、<=
、>
、<
、BETWEEN
和 IN
进行分片。 分片算法可由开发者自行实现,也可使用 Apache ShardingSphere 内置的分片算法语法糖,灵活度非常高。
分片算法语法糖,用于便捷的托管所有数据节点,使用者无需关注真实表的物理分布。 包括取模、哈希、范围、时间等常用分片算法的实现。
提供接口让应用开发者自行实现与业务实现紧密相关的分片算法,并允许使用者自行管理真实表的物理分布。 自定义分片算法又分为:
用于处理使用单一键作为分片键的 =
、IN
、BETWEEN AND
、>
、<
、>=
、<=
进行分片的场景。
用于处理使用多键作为分片键进行分片的场景,包含多个分片键的逻辑较复杂,需要应用开发者自行处理其中的复杂度。
用于处理使用 Hint
行分片的场景。
包含分片键和分片算法,由于分片算法的独立性,将其独立抽离。 真正可用于分片操作的是分片键 + 分片算法,也就是分片策略。
对于分片字段并非由 SQL 而是其他外置条件决定的场景,可使用 SQL Hint 注入分片值。 例:按照员工登录主键分库,而数据库中并无此字段。 SQL Hint 支持通过 Java API 和 SQL 注释两种方式使用。 详情请参见强制分片路由。
行表达式是为了解决配置的简化与一体化这两个主要问题。在繁琐的数据分片规则配置中,随着数据节点的增多,大量的重复配置使得配置本身不易被维护。 通过行表达式可以有效地简化数据节点配置工作量。
对于常见的分片算法,使用 Java 代码实现并不有助于配置的统一管理。 通过行表达式书写分片算法,可以有效地将规则配置一同存放,更加易于浏览与存储。
行表达式作为字符串由两部分组成,分别是字符串开头的对应 SPI 实现的 Type Name 部分和表达式部分。 以 <GROOVY>t_order_${1..3}
为例,字符
串<GROOVY>
部分的子字符串 GROOVY
为此行表达式使用的对应 SPI 实现的 Type Name,其被 <>
符号包裹来识别。而字符串 t_order_${1..3}
为此行表达式的表达式部分。当行表达式不指定 Type Name 时,例如 t_order_${1..3}
,行表示式默认将使用 InlineExpressionParser
SPI 的
GROOVY
实现来解析表达式。
以下部分介绍 GROOVY
实现的语法规则。
行表达式的使用非常直观,只需要在配置中使用 ${ expression }
或 $->{ expression }
标识行表达式即可。 目前支持数据节点和分片算法这两个部分的配置。 行表达式的内容使用的是 Groovy 的语法,Groovy 能够支持的所有操作,行表达式均能够支持。 例如:
${begin..end}
表示范围区间
${[unit1, unit2, unit_x]}
表示枚举值
行表达式中如果出现连续多个 ${ expression }
或 $->{ expression }
表达式,整个表达式最终的结果将会根据每个子表达式的结果进行笛卡尔组合。
例如,以下行表达式:
${['online', 'offline']}_table${1..3}
最终会解析为:
online_table1, online_table2, online_table3, offline_table1, offline_table2, offline_table3
传统数据库软件开发中,主键自动生成技术是基本需求。而各个数据库对于该需求也提供了相应的支持,比如 MySQL 的自增键,Oracle 的自增序列等。 数据分片后,不同数据节点生成全局唯一主键是非常棘手的问题。同一个逻辑表内的不同实际表之间的自增键由于无法互相感知而产生重复主键。 虽然可通过约束自增主键初始值和步长的方式避免碰撞,但需引入额外的运维规则,使解决方案缺乏完整性和可扩展性。
目前有许多第三方解决方案可以完美解决这个问题,如 UUID 等依靠特定算法自生成不重复键,或者通过引入主键生成服务等。为了方便用户使用、满足不同用户不同使用场景的需求, Apache ShardingSphere 不仅提供了内置的分布式主键生成器,例如 UUID、SNOWFLAKE,还抽离出分布式主键生成器的接口,方便用户自行实现自定义的自增主键生成器。
数据分片 YAML 配置方式具有非凡的可读性,通过 YAML 格式,能够快速地理解分片规则之间的依赖关系,ShardingSphere 会根据 YAML 配置,自动完成 ShardingSphereDataSource 对象的创建,减少用户不必要的编码工作。
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>
数据分片 YAML 配置示例如下:
rules: - !SHARDING autoTables: sharding_test: actualDataSources: write keyGenerateStrategy: column: id keyGeneratorName: snowflake shardingStrategy: standard: shardingColumn: id shardingAlgorithmName: auto_mod shardingAlgorithms: auto_mod: type: MOD props: sharding-count: 3 keyGenerators: snowflake: type: SNOWFLAKE - !READWRITE_SPLITTING dataSources: write: writeDataSourceName: write readDataSourceNames: - read loadBalancerName: round_robin loadBalancers: round_robin: type: ROUND_ROBIN
通过 YamlShardingSphereDataSourceFactory 的 createDataSource 方法,读取 YAML 配置完成数据源的创建。
YamlShardingSphereDataSourceFactory.createDataSource(getFile("/META-INF/sharding-databases-tables.yaml"));
mode (?): # 不配置则默认单机模式
type: # 运行模式类型。可选配置:Standalone、Cluster
repository (?): # 持久化仓库配置
mode:
type: Standalone # 单机模式
repository:
type: JDBC
props
配置Apache ShardingSphere 提供属性配置的方式配置系统级配置。
名称 | 数据类型 | 说明 | 默认值 |
---|---|---|---|
sql-show (?) | boolean | 是否在日志中打印 SQL 打印 SQL 可以帮助开发者快速定位系统问题。日志内容包含:逻辑 SQL,真实 SQL 和 SQL 解析结果。 如果开启配置,日志将使用 Topic ShardingSphere-SQL ,日志级别是 INFO | false |
sql-simple (?) | boolean | 是否在日志中打印简单风格的 SQL | false |
kernel-executor-size (?) | int | 用于设置任务处理线程池的大小 每个 ShardingSphereDataSource 使用一个独立的线程池,同一个 JVM 的不同数据源不共享线程池 | infinite |
max-connections-size-per-query (?) | int | 一次查询请求在每个数据库实例中所能使用的最大连接数 | 1 |
check-table-metadata-enabled (?) | boolean | 在程序启动和更新时,是否检查分片元数据的结构一致性 | false |
属性配置直接配置在 ShardingSphere-JDBC 所使用的配置文件中,格式如下:
props:
sql-show: true
props:
# 打印sql
sql-show: true
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。