ShardingSphere-JDBC篇

Posted dotaer-df

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了ShardingSphere-JDBC篇相关的知识,希望对你有一定的参考价值。

一、前言

ShardingSphere-JDBC 是 Apache ShardingSphere 的第一个产品,现已更名为 ShardingSphere。 定位为轻量级 Java 框架,在 Java 的 JDBC 层提供的额外服务。 它使用客户端直连数据库,以 jar 包形式提供服务,无需额外部署和依赖,可理解为增强版的 JDBC 驱动,完全兼容 JDBC 和各种 ORM 框架。

在学习Sharding-JDBC分库分表之前,我们有必要先了解分库分表的一些知识。

分库分表

一般的机器(4核16G),单库的mysql并发(QPS+TPS)超过了2k,系统基本就完蛋了。最好是并发量控制在1k左右。这里就引出一个问题,为什么要分库分表?

分库分表目的:解决高并发,和数据量大的问题。

分库分表的维度有两个:垂直和水平

  • 水平拆分 :把一个库或者一个表的数据,按照时间,地区或者某个业务键划分到不同的表或者不同的库中,拆分过后每个库表结构是一致的
  • 垂直拆分 :把一个大表拆分成多个小表,每个库表的结构都不一样,从而达到冷热字段拆分,也可以按照业务进行垂直分库,如分成用户库,订单库,拆分过后每个库表都只包含部分字段

 一般公司都会按照上图的模式进行拆分,先按照业务进行垂直分库,然后再根据需要分表的库进行水平拆分。

二、核心概念

1、分片

一般我们在提到分库分表的时候,大多是以水平切分模式(水平分库、分表)为基础来说的,而分片的可以理解为用于数据库(表)水平拆分的数据库字段,这个字段就叫做分片键,SQL 中如果无分片字段,将执行全路由,性能较差

2、逻辑表or真实表

逻辑表非真实存在的表,如一个订单表order,select * from order,这里的order指的就是逻辑表,并不存在,如果我们将order拆分成order_1,order_2....order_n,其中order_n才是真实存在的物理表

3、数据节点

 数据分片的最小单元,它由数据源名称和数据表组成,例如上图中 order_db_1.t_order_0就表示一个数据节点。

4、分布式主键

数据分⽚后,不同数据节点⽣成全局唯⼀主键是⾮常棘⼿的问题,同⼀个逻辑表(t_order)内的不同真实表(t_order_n)之间的⾃增键由于⽆法互相感知而产⽣重复主键,而sharding 内置了UUIDSNOWFLAKE 两种分布式主键⽣成器,默认使⽤雪花算法(snowflake)⽣成64bit的⻓整型数据。不仅如此它还抽离出分布式主键⽣成器的接口,⽅便我们实现⾃定义的⾃增主键⽣成算法。

5、分片策略&分片算法

分片策略只是抽象出的概念,它是由分片算法和分片健组合而成,分片算法做具体的数据分片逻辑。从执行 SQL 的角度来看,分库分表可以看作是一种路由机制,把 SQL 语句路由到我们期望的数据库或数据表中并获取数据,分片算法可以理解成一种路由规则。

分片策略:

  • 标准分片策略(StandardShardingStrategy)

    仅支持单分片键,可提供对SQL语句中的=, >, <, >=, <=, IN和BETWEEN AND的分片操作支持。
  • 复合分片策略(ComplexShardingStrategy)

    与标准分片一致,但支持多分片键
  • 行表达式分片策略(InlineShardingStrategy)

    使用Groovy的表达式,提供对SQL语句中的=和IN的分片操作支持,只支持单分片键
  • Hint分片策略 (HintShardingStrategy)

    强制路由到某库某表,此策略无需配置分片键,但需要通过外部 HintManager 指定分库、分表信息
  • 不分片策略(NoneShardingStrategy)

分片算法:

  • 精确分片算法(PreciseShardingAlgorithm)

    用于处理使用单一键作为分片键的=与IN进行分片的场景。需要配合StandardShardingStrategy使用,且是Standard策略必须算法。
  • 范围分片算法(RangeShardingAlgorithm)

    用于处理使用单一键作为分片键的BETWEEN AND、>、<、>=、<=进行分片的场景。需要配合StandardShardingStrategy使用,是Standard策略可选算法。
  • 复合分片算法(ComplexKeysShardingAlgorithm)

    用于处理使用多键作为分片键进行分片的场景,包含多个分片键的逻辑较复杂,需要应用开发者自行处理其中的复杂度。需要配合ComplexShardingStrategy使用。
  • Hint分片算法(HintShardingAlgorithm)

    用于处理使用Hint行分片的场景。需要配合HintShardingStrategy使用。

值得注意的是,sharding只提供了算法的接口,具体算法的实现还需要我们自己去实现。

列举了怎么多的分片策略,分片算法,大家一定很懵,下面来看一些具体的案例 

三、配置

sharding提供了4种配置方式,java APIYAMLSpring Boot StarterSpring命名空间,用于不同的使用场景。 通过配置,应用开发者可以灵活的使用数据分片、读写分离、数据加密、影子库等功能,并且能够叠加使用。

了解了核心概念,首先我们分别建立两个数据库,每个库包含两张表,如下图

下面我们通过YAML和java API两种方式来测试

1、YAML

YAML分库分表的配置(注意不同版本的sharding配置属性略有差异,详情参加官方文档)本文采用4.x版本

server:
  port: 8085
spring:
  shardingsphere:
    # 参数配置,显示sql
    props:
      sql:
        show: true
    # 配置数据源
    datasource:
      # 给每个数据源取别名,下面的ds1,ds1任意取名字
      names: ds0,ds1
      # 给master-ds1每个数据源配置数据库连接信息
      ds0:
        # 配置druid数据源
        type: com.alibaba.druid.pool.DruidDataSource
        driver-class-name: com.mysql.cj.jdbc.Driver
        url: jdbc:mysql://127.0.0.1:3306/ksd_user?useUnicode=true&characterEncoding=utf8&tinyInt1isBit=false&useSSL=false&serverTimezone=GMT
        username: root
        password: 123456
        maxPoolSize: 100
        minPoolSize: 5
      # 配置ds1-slave
      ds1:
        type: com.alibaba.druid.pool.DruidDataSource
        driver-class-name: com.mysql.cj.jdbc.Driver
        url: jdbc:mysql://127.0.0.1:3307/ksd_user?useUnicode=true&characterEncoding=utf8&tinyInt1isBit=false&useSSL=false&serverTimezone=GMT
        username: root
        password: 123456
        maxPoolSize: 100
        minPoolSize: 5
    sharding:
      # 配置分表的规则
      tables:
        # ksd_user 逻辑表名
        ksd_user:
          # 数据节点:数据源$->0..N.逻辑表名$->0..N
          actual-data-nodes: ds$->0..1.ksd_user$->0..1
          # 拆分库策略,也就是什么样子的数据放入放到哪个数据库中。
          database-strategy:
            inline:
              sharding-column: sex    # 分片字段(分片键)
              algorithm-expression: ds$->sex % 2 # 分片算法表达式
          # 拆分表策略,也就是什么样子的数据放入放到哪个数据表中。
          table-strategy:
            inline:
              sharding-column: age    # 分片字段(分片键)
              algorithm-expression: ksd_user$->age % 2 # 分片算法表达式

mybatis:
  mapper-locations: classpath:mapper/*.xml
  type-aliases-package: com.lb.shardingtest.entity

我们一段段来解释

spring:
  shardingsphere:
    # 配置数据源
    datasource:
      # 给每个数据源取别名,下面的ds0,ds1任意取名字
      names: ds0,ds1
      # 给每个数据源配置数据库连接信息
      ds0:
        # 配置druid数据源
        type: com.alibaba.druid.pool.DruidDataSource
        driver-class-name: com.mysql.cj.jdbc.Driver
        url: jdbc:mysql://127.0.0.1:3306/ksd_user?useUnicode=true&characterEncoding=utf8&tinyInt1isBit=false&useSSL=false&serverTimezone=GMT
        username: root
        password: 123456
        maxPoolSize: 100
        minPoolSize: 5
      # 配置ds1-slave
      ds1:
        type: com.alibaba.druid.pool.DruidDataSource
        driver-class-name: com.mysql.cj.jdbc.Driver
        url: jdbc:mysql://127.0.0.1:3307/ksd_user?useUnicode=true&characterEncoding=utf8&tinyInt1isBit=false&useSSL=false&serverTimezone=GMT
        username: root
        password: 123456
        maxPoolSize: 100
        minPoolSize: 5

这里配置了两个库(数据源)并分别取了别名ds0和ds1 

    sharding:
      # 配置分表的规则
      tables:
        # ksd_user 逻辑表名
        ksd_user:
          # 数据节点:数据源$->0..N.逻辑表名$->0..N
          actual-data-nodes: ds$->0..1.ksd_user$->0..1
          # 拆分库策略,也就是什么样子的数据放入放到哪个数据库中。
          database-strategy:
            inline:
              sharding-column: sex    # 分片字段(分片键)
              algorithm-expression: ds$->sex % 2 # 分片算法表达式
          # 拆分表策略,也就是什么样子的数据放入放到哪个数据表中。
          table-strategy:
            inline:
              sharding-column: age    # 分片字段(分片键)
              algorithm-expression: ksd_user$->age % 2 # 分片算法表达式

其中ksd_user为要分片表的逻辑表名,使用的分库和分表策略都为inline,也是是上文所说的行表达式分片策略(InlineShardingStrategy),数据节点分别为:

ds0.ksd_user0  ds0.ksd_user1  ds1.ksd_user0  ds1.ksd_user1

其中分库算法的分片列为sex(假设男为0,女为1),那么男通过取模会得到ds0库,女会得到ds1库,然后再根据分表算法的分片列age取模再次选择放到哪一张表。

测试数据为:sex为男(0) 年龄偶数(20)预期应该插入ds0.ksd_user0

测试结果:符合预期


2、java API

现在我们再来通过 java API这种方式来实现同样的分库分表策略,因为是单个分片键,所以我们的算法只需实现PreciseShardingAlgorithm接口即可

import org.apache.shardingsphere.api.sharding.standard.PreciseShardingAlgorithm;
import org.apache.shardingsphere.api.sharding.standard.PreciseShardingValue;
import org.springframework.stereotype.Component;

import java.util.Collection;

/**
 * 分表算法
 * @date 2022/6/7
 **/
@Component
public class MyAgeAlgorithm implements PreciseShardingAlgorithm<Integer> 

    @Override
    public String doSharding(Collection<String> availableTargetNames, PreciseShardingValue<Integer> preciseShardingValue) 
        //分片列值
        Integer value = preciseShardingValue.getValue();
        String shardingValue = String.valueOf(value % 2);
        for (String targetName : availableTargetNames) 
            if(targetName.endsWith(shardingValue)) 
                return targetName;
            
        
        return null;
    
import org.apache.shardingsphere.api.sharding.standard.PreciseShardingAlgorithm;
import org.apache.shardingsphere.api.sharding.standard.PreciseShardingValue;
import org.springframework.stereotype.Component;

import java.util.Collection;


/**
 * 分库算法
 * @date 2022/6/7
 **/
@Component
public class MySexAlgorithm implements PreciseShardingAlgorithm<Integer> 

    /**
     *
     * @param availableTargetNames 实际库别名或者表名集合
     * @param preciseShardingValue 分片列 其中包含3个属性:
     * columnName 分片列  value 分片列值  logicTableName 逻辑表名
     *
     * @return
     */
    @Override
    public String doSharding(Collection<String> availableTargetNames, PreciseShardingValue<Integer> preciseShardingValue) 
        //分片列值
        Integer value = preciseShardingValue.getValue();
        String shardingValue = String.valueOf(value % 2);
        for (String targetName : availableTargetNames) 
            if(targetName.endsWith(shardingValue)) 
                return targetName;
            
        
        return null;
    

然后修改一下配置文件的分库分表策略即可

          database-strategy:
            standard:
              sharding-column: sex    # 分片字段(分片键)
              preciseAlgorithmClassName: com.lb.shardingtest.sharding.algorithm.MySexAlgorithm 
            # 拆分表策略,也就是什么样子的数据放入放到哪个数据表中。
          table-strategy:
            standard:
              sharding-column: age    # 分片字段(分片键)
              preciseAlgorithmClassName: com.lb.shardingtest.sharding.algorithm.MyAgeAlgorithm 

 测试数据为:sex为女(1) 年龄奇数(20)预期应该插入ds1.ksd_user1

 测试结果:符合预期

 

参考文章:

概览 :: ShardingSphere

【学相伴】ShardingJDBC最新完整教程IDEA版通俗易懂 | KuangStudy | 飞哥 | 狂神说 | 学相伴_哔哩哔哩_bilibili

初识-Sharding-JDBC_天亮i的博客-CSDN博客_sharding-jdbc

Sharding-JDBC分片策略详解(二)


 

以上是关于ShardingSphere-JDBC篇的主要内容,如果未能解决你的问题,请参考以下文章

ShardingSphere-JDBC入门

ShardingSphere-JDBC入门

java将字符串转成算术表达式

看完这一篇,ShardingSphere-jdbc 实战再也不怕了

看完这一篇,ShardingSphere-jdbc 实战再也不怕了

js和java将字符串转成算术表达式