首页 > 其他分享 >shardingsphere

shardingsphere

时间:2023-01-04 22:22:40浏览次数:60  
标签:product 分库 spring id shardingsphere order

shardingsphere

目录

1.面试题

1.1 业务增长-数据库性能优化

  • 数据库-单表1千万数据,未来1年还会增长500多万,性能较慢,怎么优化

    • 根据实际情况优化

      • 不分库分表

        • 硬优化:提升系统硬件(更快的IO、更多的内存):宽带、CPU、硬盘
        • 软优化:
          • 数据库参数调优(运维做的)
          • 分析慢查询SQL语句,分析执行计划,SQL优化
          • 优化数据库索引
          • 优化数据表结构优化
          • 引入NOSQL和程序架构调整(数据库搭建主从,读写分离)
      • 分库分表

        • 根据业务情况而定,选择适合的分库分表策略(没有通用的策略)

          • 外卖、物流、电商领域
        • 先看只分表是否满足业务需求和未来增长

          数据库分表能够解决单表数据量很大的时候,数据查询效率问题;
          但无法给数据库的并发操作带来效率提高,分表的实质还是在操作同一个数据库,会受IO性能的限制
          
        • 如果分表不能满足需求,再进行分库分表

      结论:在数据量访问压力不是特别大的情况,首先考虑缓存、主从分离、索引等技术方法
      如果数据量极大,且业务增长快,再考虑分库分表
      

2.分库分表带来的优点

  • 分库分表解决的问题

    • 解决数据库本身的瓶颈

      • 解决连接数不足问题:连接数超过数据库设置的最大连接数,会出现问题
        • MySQL默认连接数是100,,⽽mysql服务允 许的最⼤连接数为16384
      • 解决海量数据的查询问题
      • 解决单台数据库访问并发压力问题
    • 解决系统本身IO、CPU瓶颈

      • 磁盘读写IO瓶颈:热点数据太多,大量IO操作,导致sql执行慢

      • 网络IO瓶颈,请求数据太多,数据传输大,宽带不够,导致链路响应时间边长

      • CPU瓶颈,尤其在基础数据量⼤单机复杂SQL计算,SQL语 句执⾏占⽤CPU使⽤率⾼,也有扫描⾏数⼤、锁冲突、锁 等待等原因;

        使用explain执行计划分析
        

3.分库分表带来的问题

  • 分库后,跨节点数据库Join关联查询和多维度查询

    • 数据库切分前,多表关联查询,可以通过sql join进行实现
    • 分库分表后,数据可能分布在不同的节点上,sql join带来的问题就比较麻烦
  • 不同维度查看数据,利用的partitionKey是不一样的

    • 例如
      • 订单表 的partionKey是user_id,用户查看自己的订单列表方便
      • 但商家查看自己店铺的订单列表就麻烦,分布在不同数据节点
  • 分库后,会带来分布式事务问题

  • 分库后,执行的SQL排序、翻页、函数计算等问题

    • 分库后,数据在不同节点上,跨节点多库查询,会出现limit分页、order by排序等问题
  • 分库后,会带来数据库全局主键重复问题

    • 常规表的id是使⽤⾃增id进⾏实现,分库分表后,由于表 中数据同时存在不同数据库中,如果⽤⾃增id,则会出现 冲突问题
  • 容量规划,分库分表后⼆次扩容问题

    • 业务发展快,初次分库分表后,满⾜不了数据存储,导致 需要多次扩容
  • 分库分表技术选型问题

    • 市场上分库分表中间件较多,怎么选择

4.分库分表核心概念

4.1 垂直分表

  • 需求:商品表字段太多,每个字段的访问频次不一样,浪费IO资源,需要进行优化
  • 垂直分表:
    • 基于表的字段进行拆分,“大表拆分为小表”;把不常用或数据大的字段,拆分到“扩展表”,如text类型字段
    • 访问频次低、字段大的商品描述信息单独存放一张表中;将访问频次高的商品基本信息单独放在一张表中
  • 垂直拆分原则
    • 把不常⽤的字段单独放在⼀张表;
    • 把text,blob等⼤字段拆分出来放在附表中;
    • 业务经常组合查询的列放在⼀张表中;
例子:商品详情一般是拆分主表和附表
  • 拆分前

    id
    title 视频标题
    cover_img 封面图
    price 价格,分
    total 总库存
    left_num 剩余
    learn_base 课前须知,学习基础
    learn_result 达到水平
    summary 概述
    detail 视频商品详情
    
  • 拆分后

    商品表(主表):经常访问,比如商品界面
    id
    title 视频标题
    cover_img 封面图
    price 价格,分
    total 总库存
    left_num 剩余
    ------------------
    附表  点击进入商品之后的信息
    id
    productId 商品id
    learn_base 课前须知,学习基础
    learn_result 达到水平
    summary 概述
    detail 视频商品详情
    

4.2 垂直分库

  • 需求:C端项目里,单个数据库的CPU、内存长期处于90+%的情况,数据库连接经常不够,需要优化。

  • 垂直分库

    垂直分库是针对一个系统中的不同业务进行拆分,数据库连接资源不够且单机处理能力有限
    
    没拆分前,全部数据在单库上,单库处理能力成为瓶颈,磁盘空间不足,内存,tps等限制
    
    拆分之后,避免不同库竞争同⼀个物理机的CPU、内存、⽹络IO、磁盘,所以在⾼并发场景下,垂直分库⼀定程度上能够突破IO、连接数及单机硬件资源的瓶颈
    
    • 垂直分库垂直分库可以更好解决业务层⾯的耦合,业务清晰,且⽅便管 理和维护
    • 使用场景:单体项⽬升级改造为微服务项⽬,就是垂直分库

    image-20230104210900697

  • 问题:

    • 垂直分库,可以提高并发,但并没有解决单表数据量大的情况

4.3 水平分表

  • 需求:当一张表数据达到几千万时,就算使用索引也查询时间过长,需要进行优化,缩短查询时间
  • 水平分表:对数据进行拆分
    • 把⼀个表的数据分到⼀个数据库的多张表中,每个表只有这个 表的部分数据
    • 核心:把数据量大的表,分割成N个小表;N个小表数据合起来就是原来大表数据
    • 针对数据量巨大的单张表(比如订单表),按照某种规则(RANGE,HASH取模等),切分到多张表里面去
    • 但是这些表还是在同⼀个库中,所以单数据库操作还是有IO 瓶颈,主要是解决单表数据量过⼤的问题
  • 优点:
    • 减少锁表时间,没分表前,如果是DDL(create/alter/add等) 语句,当需要添加⼀列的时候mysql会锁表,期间所有的读写 操作只能等待;分表后,只会锁住部分表数据

image-20230104211321692

4.4 水平分库

  • 需求:高并发项目中,⽔平分表后依旧在单个库上⾯,1个数 据库资源瓶颈 CPU/内存/带宽等限制导致响应慢,需要进⾏优化

  • 水平分库

    • 把表的数据按照⼀定规则分到不同的数据库中,数据库在 不同的服务器上
    • 水平分库是把不同表拆到不同数据库中,它是对数据行的拆分,不影响表结构
    • 每个库的结构都⼀样,但每个库的数据都不⼀样,没有交集, 所有库的并集就是全量数据
    • 水平分库的粒度,比水平分表更大

    image-20230104211420677

4.5 分库分表总结

  • 技术负责人前瞻性思维

    • 我们需要提前考虑系统一年到两年左右的业务情况

    • 对数据库服务器的QPS、连接数、容量等做合理评估和规划

    • 常规开发⾥⾯单表建议1千万内,推荐是百万级别单表存储,常 规sql和索引优化先⾏,然后结合缓存+异步+nosql+mq

  • 垂直角度

    • 垂直分表::将⼀个表字段拆分多个表,每个表存储部分字段
      • 好处:避免了IO时,锁表次数,分离热点字段和⾮热点字段, 避免⼤字段IO导致性能下降
      • 原则:业务经常组合查询的字段⼀个表;不常⽤字段⼀个 表;text、blob类型字段作为附属表
    • 垂直分库:根据业务将表分类,放到不同的数据库服务器上
      • 好处:避免表之间竞争同个物理机的资源,⽐如CPU/内 存/硬盘/⽹络IO
      • 原则:根据业务相关性进⾏划分,领域模型,微服务划分 ⼀般就是垂直分库
  • ⽔平⻆度(表结构⼀样)

    • ⽔平分库:把同个表的数据按照⼀定规则分到不同的数据库 中,数据库在不同的服务器上
      • 好处: 多个数据库,降低了系统的IO和CPU压⼒
      • 原则
        • 选择合适的分⽚键和分⽚策略,和业务场景配合
        • 避免数据热点和访问不均衡、避免⼆次扩容难度⼤
    • ⽔平分表:同个数据库内,把⼀个表的数据按照⼀定规则拆分 到多个表中,对数据进⾏拆分,不影响表结构
      • 单个表的数据量少了,业务SQL执⾏效率⾼,降低了系统 的IO和CPU压⼒
      • 原则
        • 选择合适的分⽚键和分⽚策略,和业务场景配合
        • 避免数据热点和访问不均衡、避免⼆次扩容难度⼤

5.水平分库分表策略

5.1 range(范围)

  • 方案1:自增id,根据ID范围进行分表(左闭右开)

    • 规则案例

      • 1~1,000,000 是 table_1
      • 1,000,000 ~2,000,000 是 table_2
      • 2,000,000~3,000,000 是 table_3
      • ...
    • 优点

      • id是⾃增⻓,可以⽆限增⻓
      • 扩容不⽤迁移数据,容易理解和维护
    • 缺点:

      • ⼤部分读和写都访会问新的数据,有IO瓶颈,整体资源利 ⽤率低
      • 数据倾斜严重,热点数据过于集中,部分节点有瓶颈

      image-20230104211510135

  • 其他根据范围进行水平分库分表(范围一般是分表

    • 数字
      • 自增id范围
    • 时间
      • 年、月、日范围:⽐如按照⽉份⽣成 库或表 pay_log_2022_01、 pay_log_2022_02
    • 空间
      • 地理位置:省份、区域(华东、华北、华南):地理位置:省份、区域(华东、华北、华南)

image-20230104211533437

  • 基于Range范围分库分表业务场景
    • 微博发送记录、微信消息记录、⽇志记录,适用于id增⻓/时间分区 都⾏
      • ⽔平分表为主,⽔平分库则容易造成资源的浪费
    • ⽹站签到等活动流⽔数据时间分区最好
      • ⽔平分表为主,⽔平分库则容易造成资源的浪费
    • ⼤区划分(⼀⼆线城市和五六线城市活跃度不⼀样,如果能避 免热点问题,即可选择)
      • saas业务⽔平分库(华东、华南、华北等)

5.2 Hash取模

  • ⽅案⼆:hash取模(Hash分库分表是最普遍的⽅案)

  • 取模计算规则

    • 如:⽤户ID是整数型的,要分2库,每个库表数量4表,⼀共8张表

    • 用户ID取模后,值是0到7的要平均分配到每张表

      库ID = userId % 库数量 2
      表ID = userId / 库数量 2 % 表数量4
      
    • 例子

      userId id % 库数量 (库id) (id/库数量)%表数量(表id)
      1 1 0
      2 0 1
      3 1 1
      4 0 2
      5 1 2
    • 优点:

      • 保证数据较均匀的分散落在不同的库、表中,可以有效的避免 热点数据集中问题,
    • 缺点:

      • 扩容不是很⽅便,需要数据迁移

6.分库分表技术选型

常见分库分表中间件

  • TDDL

    • 淘宝根据自己的业务特点开发了 TDDL (Taobao Distributed Data Layer)
    • 基于JDBC规范,没有server,以client-jar的形式存在,引入项目即可使用
    • 开源功能比较少,阿里内部使用为主
  • MyCat

    • 地址 http://www.mycat.org.cn/
    • Java语言编写的MySQL数据库网络协议的开源中间件,前身 Cobar
    • 遵守Mysql原生协议,跨语言,跨平台,跨数据库的通用中间件代理
    • 是基于 Proxy,它复写了 MySQL 协议,将 Mycat Server 伪装成一个 MySQL 数据库
    • 和ShardingShere下的Sharding-Proxy作用类似,需要单独部署

    image-20221203104239922

  • ShardingSphere 下的Sharding-JDBC

    • 地址:https://shardingsphere.apache.org/

    • Apache ShardingSphere 是一套开源的分布式数据库中间件解决方案组成的生态圈

      • 它由 Sharding-JDBC、Sharding-Proxy 和 Sharding-Sidecar 3个独立产品组合
    • Sharding-JDBC

      • 基于jdbc驱动,不用额外的proxy,支持任意实现 JDBC 规范的数据库
      • 它使用客户端直连数据库,以 jar 包形式提供服务,无需额外部署和依赖
      • 可理解为加强版的 JDBC 驱动,兼容 JDBC 和各类 ORM 框架

      image-20221203104335140

  • Mycat和ShardingJdbc区别

    • 两者设计理念相同,主流程都是SQL解析-->SQL路由-->SQL改写-->结果归并
    • sharding-jdbc
      • 基于jdbc驱动,不用额外的proxy,在本地应用层重写Jdbc原生的方法,实现数据库分片形式
      • 是基于 JDBC 接口的扩展,是以 jar 包的形式提供轻量级服务的,性能高
      • 代码有侵入性
    • Mycat
      • 是基于 Proxy,它复写了 MySQL 协议,将 Mycat Server 伪装成一个 MySQL 数据库
      • 客户端所有的jdbc请求都必须要先交给MyCat,再有MyCat转发到具体的真实服务器
      • 缺点是效率偏低,中间包装了一层
      • 代码无侵入性

7.ShardingSphere的认知

  • 什么是ShardingSphere

    • 是⼀套开源的分布式数据库解决⽅案组成的⽣态圈,定位为 Database Plus
    • 它由 JDBCProxySidecar这 3 款既能够独⽴部署,⼜⽀ 持混合部署配合使⽤的产品组成
  • 三大构成

    • ShardingSphere-JDBC

      • 它使⽤客户端直连数据库,以 jar 包形式提供服务
      • ⽆需额外部署和依赖,可理解为增强版的 JDBC 驱动,完 全兼容 JDBC 和各种 ORM 框架
      • 适⽤于任何基于 JDBC 的 ORM 框架,如:JPA, Hibernate, Mybatis,或直接使⽤ JDBC ⽀持任何第三⽅的数据库连接池,如:DBCP, C3P0, BoneCP, HikariCP 等;
      • ⽀持任意实现 JDBC 规范的数据库,⽬前⽀持 MySQL, PostgreSQL,Oracle,SQLServer 以及任何可使⽤ JDBC 访问的数据库
      • 采⽤⽆中⼼化架构,与应⽤程序共享资源,适⽤于 Java 开 发的⾼性能的轻量级 OLTP 应⽤

      image-20230104211936579

    • ShardingSphere-Proxy

      • 数据库代理端,提供封装了数据库⼆进制协议的服务端版 本,⽤于完成对异构语⾔的⽀持
      • 向应⽤程序完全透明,可直接当做 MySQL/PostgreSQL
      • 它可以使⽤任何兼容 MySQL/PostgreSQL 协议的访问客户 端(如:MySQL Command Client, MySQL Workbench, Navicat 等)操作数据

      image-20230104211950882

    • ShardingSphere-Sidecar(规划中,简单知道就⾏)

      • 定位为 Kubernetes 的云原⽣数据库代理,以 Sidecar 的 形式代理所有对数据库的访问
      • 通过⽆中⼼、零侵⼊的⽅案提供与数据库交互的啮合层, 即 Database Mesh,⼜可称数据库⽹格

8.分库分表及ShardingJDBC常见术语

  • 数据节点Node

    • 数据分片的最小单元
    • 比如:分库分表后,某数据库中的一张表;ds_0.product_order_0
  • 真实表

    • 在分⽚的数据库中真实存在的物理表
    • ⽐如订单表 product_order_0、product_order_1、 product_order_2
  • 逻辑表

    • ⽔平拆分的数据库(表)的相同逻辑和数据结构表的总称
    • ⽐如订单表 product_order_0、product_order_1、 product_order_2,逻辑表就是拆分前的表product_order
  • 绑定表

    • 指分⽚规则⼀致的主表和⼦表
    • ⽐如product_order表和product_order_item表,均按照 order_id分⽚,则此两张表互为绑定表关系
    • 绑定表之间的多表关联查询不会出现笛卡尔积关联,关联查询 效率将⼤⼤提升

    image-20230104212053301

  • ⼴播表

    • 指所有的分⽚数据源中都存在的表,表结构和表中的数据在每 个数据库中均完全⼀致
    • 适⽤于数据量不⼤且需要与海量数据的表进⾏关联查询的场景
    • 例如:字典表、配置表,类似冗余表

9.SpringBoot整合MyBatis-plus及Sharding-JDBC

  • 新建maven项目

  • 导入依赖

    <?xml version="1.0" encoding="UTF-8"?>
    <project xmlns="http://maven.apache.org/POM/4.0.0"
             xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
             xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
        <modelVersion>4.0.0</modelVersion>
    
        <groupId>net.xdclass</groupId>
        <artifactId>sharding-jdbc</artifactId>
        <version>1.0-SNAPSHOT</version>
    
        <properties>
            <!--JDK版本,如果是jdk8则这⾥是 1.8-->
            <java.version>11</java.version>
            <maven.compiler.source>11</maven.compiler.source>
            <maven.compiler.target>11</maven.compiler.target>
            <spring.boot.version>2.5.5</spring.boot.version>
            <mybatisplus.boot.starter.version>3.4.0</mybatisplus.boot.starter.version>
            <lombok.version>1.18.16</lombok.version>
            <sharding-jdbc.version>4.1.1</sharding-jdbc.version>
            <junit.version>4.12</junit.version>
            <druid.version>1.1.16</druid.version>
            <!--跳过单元测试-->
            <skipTests>true</skipTests>
        </properties>
    
        <dependencies>
    <!--        导入springBoot 依赖 begin-->
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-starter-web</artifactId>
                <version>${spring.boot.version}</version>
            </dependency>
            <!--<dependency>-->
            <!--
           <groupId>org.springframework.boot</groupId>-->
            <!--<artifactId>spring-boot-test</artifactId>-->
            <!--</dependency>-->
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-starter-test</artifactId>
                <version>${spring.boot.version}</version>
                <scope>test</scope>
            </dependency>
            <!--        导入springBoot 依赖 end-->
    
    
            <!--mybatis plus和springboot整合 begin-->
            <dependency>
                <groupId>com.baomidou</groupId>
                <artifactId>mybatis-plus-boot-starter</artifactId>
                <version>${mybatisplus.boot.starter.version}</version>
            </dependency>
           <!--    end    -->
           
           <!--       mysql与SpringBoot整合 begin-->
            <dependency>
                <groupId>mysql</groupId>
                <artifactId>mysql-connector-java</artifactId>
                <version>8.0.27</version>
            </dependency>
           <!--        end -->
    <!--        lombok 插件依赖 begin-->
            <dependency>
                <groupId>org.projectlombok</groupId>
                <artifactId>lombok</artifactId>
                <version>${lombok.version}</version>
                <!--<scope>provided</scope>-->
            </dependency>
    <!--        end-->
    <!--      导入shardingsphere依赖 begin  -->
            <dependency>
                <groupId>org.apache.shardingsphere</groupId>
                <artifactId>sharding-jdbc-spring-boot-starter</artifactId>
                <version>${sharding-jdbc.version}</version>
            </dependency>
    <!--        end  -->
            <dependency>
                <!--            配置⽂件修改-->
                <groupId>junit</groupId>
                <artifactId>junit</artifactId>
                <version>${junit.version}</version>
            </dependency>
        </dependencies>
    
        <build>
            <plugins>
                <plugin>
                    <groupId>org.springframework.boot</groupId>
                    <artifactId>spring-boot-maven-plugin</artifactId>
                    <version>${spring.boot.version}</version>
                    <configuration>
                        <fork>true</fork>
                        <addResources>true</addResources>
                    </configuration>
                </plugin>
            </plugins>
        </build>
    
    </project>
    
  • 数据库

    • xdclass_shop_order_0

      • product_order_0
      • product_order_1
    • xdclass_shop_order_1

      • product_order_0
      • product_order_1
  • 脚本

    CREATE TABLE `product_order_0` (
     `id` bigint NOT NULL AUTO_INCREMENT,
     `out_trade_no` varchar(64) DEFAULT NULL COMMENT '订
    单唯⼀标识',
     `state` varchar(11) DEFAULT NULL COMMENT 'NEW 未⽀
    付订单,PAY已经⽀付订单,CANCEL超时取消订单',
     `create_time` datetime DEFAULT NULL COMMENT '订单⽣
    成时间',
     `pay_amount` decimal(16,2) DEFAULT NULL COMMENT '订
    单实际⽀付价格',
     `nickname` varchar(64) DEFAULT NULL COMMENT '昵称',
     `user_id` bigint DEFAULT NULL COMMENT '⽤户id',
     PRIMARY KEY (`id`)
    ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4
    COLLATE=utf8mb4_bin;
    
  • 实体类创建

    @Data
    @EqualsAndHashCode(callSuper = false)
    @TableName("product_order")
    public class ProductOrderDO {
        private static final long serialVersionUID = 1L;
    
        @TableId(value = "id", type = IdType.AUTO)
        private Long id;
    
        /**
         * 订	单唯⼀标识
         */
        private String outTradeNo;
    
        /**
         * NEW 未⽀	付订单,PAY已经⽀付订单,CANCEL超时取消订单
         */
        private String state;
    
        /**
         * 订单⽣	成时间
         */
        private Date createTime;
    
        /**
         * 订	单实际⽀付价格
         */
        private BigDecimal payAmount;
    
        /**
         * 昵称
         */
        private String nickname;
    
        /**
         * ⽤户id
         */
        private Long userId;
    }
    
    
  • 配置

    server.port=8080
    spring.application.name=xdclass-sharding-jdbc
    
    logging.level.root=INFO
    # 打印执⾏的数据库以及语句
    spring.shardingsphere.props.sql.show=true
    # 设置数据源名称 ds0,ds1
    spring.shardingsphere.datasource.names=ds0,ds1
    # 第⼀个数据库 基本配置
    spring.shardingsphere.datasource.ds0.type=com.zaxxer.hikari.HikariDataSource
    spring.shardingsphere.datasource.ds0.driver-class-name=com.mysql.cj.jdbc.Driver
    spring.shardingsphere.datasource.ds0.jdbc-url=jdbc:mysql://127.0.0.1:3306/xdclass_shop_order_0?serverTimezone=GMT&useUnicode=true&characterEncoding=utf-8&useSSL=false
    spring.shardingsphere.datasource.ds0.username=root
    spring.shardingsphere.datasource.ds0.password=root
    #第二个数据库 配置
    spring.shardingsphere.datasource.ds1.type=com.zaxxer.hikari.HikariDataSource
    spring.shardingsphere.datasource.ds1.driver-class-name=com.mysql.cj.jdbc.Driver
    spring.shardingsphere.datasource.ds1.jdbc-url=jdbc:mysql://127.0.0.1:3306/xdclass_shop_order_1?serverTimezone=GMT&useUnicode=true&characterEncoding=utf-8&useSSL=false
    spring.shardingsphere.datasource.ds1.username=root
    spring.shardingsphere.datasource.ds1.password=root
    

10.Sharding-Jdbc常见分片算法

  • 数据库表分片

    • 分片键 和 分片策略
  • 分片键

    • ⽤于分⽚的数据库字段,是将数据库(表)⽔平拆分的关键字段

    • ⽐如prouduct_order订单表,根据用户ID 做哈 希取模,则userId是分⽚键

    • 除了对单分⽚字段的⽀持,ShardingSphere也⽀持根据多个 字段进⾏分⽚

      image-20230104212209957

  • 分片策略

    • 行表达式分片策略 InlineShardingStrategy

      • 只支持【单分片键】使用Groovy的表达式,提供对SQL语句中的 =和IN 的分片操作支持

      • 可以通过简单的配置使用,无需自定义分片算法,从而避免繁琐的Java代码开发

        prouduct_order_$->{user_id % 8}` 表示订单表根据user_id模8,而分成8张表,表名称为`prouduct_order_0`到`prouduct_order_7
        
    • 标准分片策略StandardShardingStrategy

      • 只支持【单分片键】,提供PreciseShardingAlgorithm和RangeShardingAlgorithm两个分片算法
      • PreciseShardingAlgorithm 精准分片 是必选的,用于处理=和IN的分片
      • RangeShardingAlgorithm 范围分配 是可选的,用于处理BETWEEN AND分片
      • 如果不配置RangeShardingAlgorithm,如果SQL中用了BETWEEN AND语法,则将按照全库路由处理,性能下降
    • 复合分片策略ComplexShardingStrategy

      • 支持【多分片键】,多分片键之间的关系复杂,由开发者自己实现,提供最大的灵活度
      • 提供对SQL语句中的=, IN和BETWEEN AND的分片操作支持
      • prouduct_order_0_0、prouduct_order_0_1、prouduct_order_1_0、prouduct_order_1_1
    • Hint分片策略HintShardingStrategy

      • 这种分片策略无需配置分片健,分片健值也不再从 SQL中解析,外部手动指定分片健或分片库,让 SQL在指定的分库、分表中执行
      • 用于处理使用Hint行分片的场景,通过Hint而非SQL解析的方式分片的策略
      • Hint策略会绕过SQL解析的,对于这些比较复杂的需要分片的查询,Hint分片策略性能可能会更好
    • 不分片策略 NoneShardingStrategy

      • 不分片的策略。
  • 自己实现分片策略的优缺点

    • 优点:可以根据分片策略代码里面自己拼装 真实的数据库、真实的表,灵活控制分片规则

    • 缺点:增加了编码,不规范的sql容易造成全库表扫描,部分sql语法支持不友好

10.1 行表达式分片策略

  • 只⽀持【单分⽚键】使⽤Groovy的表达式,提供对SQL语 句中的 =和IN 的分⽚操作⽀持

  • 可以通过简单的配置使⽤,⽆需⾃定义分⽚算法,从⽽避 免繁琐的Java代码开发

  • 配置

    # 指定product_order表的数据分布情况,配置数据节点,⾏表达式标识符使⽤ ${...} 或 $->{...},
    # 但前者与 Spring 本身的⽂件占位符冲突,所以在 Spring 环境中建议使⽤ $->{...}
    spring.shardingsphere.sharding.tables.product_order.actual-data-nodes=ds0.product_order_$->{0..1}
    # ---------------------指定product_order表 ⾏表达式分⽚策略-----------------------
    #指定 分⽚键
    spring.shardingsphere.sharding.tables.product_order.table-strategy.inline.sharding-column=user_id
    #指定 分⽚算法
    spring.shardingsphere.sharding.tables.product_order.table-strategy.inline.algorithm-expression=product_order_$->{user_id % 2}
    
  • 测试

    @RunWith(SpringRunner.class)
    @SpringBootTest(classes = DemoApplication.class)
    @Slf4j
    public class DbTest {
    
        @Autowired
        private ProductOrderMapper productOrderMapper;
    
        @Test
        public void testSaveProductOrder() {
    
            for(int i=0;i<10;i++){
                ProductOrderDO productOrderDO = new ProductOrderDO();
                productOrderDO.setNickname("小滴"+i);
                productOrderDO.setOutTradeNo(UUID.randomUUID().toString().substring(0,32));
                productOrderDO.setPayAmount(BigDecimal.valueOf(100.00));
                productOrderDO.setState("好");
    
                productOrderDO.setUserId(Long.valueOf(i));
    
                productOrderMapper.insert(productOrderDO);
            }
        }
    }
    
    
  • 效果:进行插入操作,会根据 分片策略算法,分别插入两个表中

image-20221203170928804

  • 问题:常规表的id是使⽤⾃增id进⾏实现,分表后,由于表 中数据同时存在不同数据库中,如果⽤⾃增id,则会出现 冲突问题
  • 解决方案
    • id生成策略雪花算法

10.2 标准分⽚策略StandardShardingStrategy

  • 只⽀持【单分⽚键】,提供PreciseShardingAlgorithm和RangeShardingAlgorithm两个分⽚算法
  • PreciseShardingAlgorithm 精准分⽚ 是必选的,⽤于处理=和IN的分⽚
  • RangeShardingAlgorithm 范围分配 是可选的,⽤于处理BETWEEN AND分⽚如果不配置RangeShardingAlgorithm,如果SQL中⽤了BETWEEN AND语法,则将按照全库路由处理,性能下降

10.3 Hint分⽚策略HintShardingStrategy

  • 这种分⽚策略⽆需配置分⽚健,分⽚健值也不再从 SQL中解析,外部⼿动指定分⽚健或分⽚库,让 SQL在指定的分库、分表中执⾏
  • ⽤于处理使⽤Hint⾏分⽚的场景,通过Hint⽽⾮SQL解析的⽅式分⽚的策略
  • Hint策略会绕过SQL解析的,对于这些⽐较复杂的需要分⽚的查询,Hint分⽚策略性能可能会更好

11. id生成策略之雪花算法

11.1雪花算法介绍

  • 单库下⼀般使⽤Mysql⾃增ID, 但是分库分表后,会造成不同分⽚ 上的数据表主键会重复。

  • 需求

    • 性能强劲
    • 全局唯⼀
    • 防⽌恶意⽤户规矩id的规则来获取数据
  • 业界常用id解决方案

    • 数据库⾃增ID

      • 利⽤⾃增id, 设置不同的⾃增步⻓,

        • auto_increment_offset:表示自增长字段从那个数开始

        • auto-increment-increment:表示自增长字段每次递增的量

        • show variables like '%auto_inc%';           
          show session variables like '%auto_inc%';   --  //session会话变量 
          show global variables like '%auto_inc%';   --  //全局变量 
            SET @auto_increment_increment = 3 ;
            SET session auto_invrement_increment=2; 
            SET global auto_increment_increment=1;
          
      DB1: 单数
      //从1开始、每次加2
      
      DB2: 偶数
      //从2开始,每次加2
      
      • 依靠数据库系统的功能实现,但是未来扩容麻烦
      • 主从切换时的不⼀致可能会导致重复发号
      • 性能瓶颈存在单台sql上
    • UUID

      • 性能⾮常⾼,没有⽹络消耗
      • 缺点
        • ⽆序的字符串,不具备趋势⾃增特性
        • UUID太⻓,不易于存储,浪费存储空间,很多场景不 适⽤
    • Redis发号器

      • 利⽤Redis的INCR和INCRBY来实现,原⼦操作,线程安 全,性能⽐Mysql强劲
      • 缺点
        • 需要占⽤⽹络资源,增加系统复杂度
    • Snowflake雪花算法

      • twitter 开源的分布式 ID ⽣成算法,代码实现简单、不占 ⽤宽带、数据迁移不受影响
      • ⽣成的 id 中包含有时间戳,所以⽣成的 id 按照时间递增
      • 注意事项:多台服务器,需要保证系统时间⼀样,机器编号不 ⼀样
      • 缺点
        • 依赖系统时钟(多台服务器时间⼀定要⼀样)
雪花算法
  • 什么是雪花算法Snowflake
    • twitter⽤scala语⾔编写的⾼效⽣成唯⼀ID的算法
    • 优点
      • ⽣成的ID不重复
      • 算法性能⾼
      • 基于时间戳,基本保证有序递增
bit 与 byte

bit(位):电脑中存储的最⼩单位,可以存储⼆进制中的0或1

byte(字节):⼀个byte由8个bit组成

int:4 个字节
short:2 个字节
long:8 个字节
byte:1 个字节
float:4 个字节
double:8 个字节
char:2 个字节


注意:
数据类型在不同位数机器的平台下⻓度不同(怼⾯试官的严谨性)
16位平台 int 2个字节16位
32位平台 int 4个字节32位
64位平台 int 4个字节32位
  • 雪花算法生成的数字,long类型,即 8 byte ,64 bit

    • 64 位表示的范围:表示的值 -9223372036854775808(-2的63次⽅) ~ 9223372036854775807(2的63次⽅-1)
    • 但生成唯一id是数据库主键,所以不能是负数;
      • 即生成id范围:0~9223372036854775807(2的63次⽅-1)

    image-20221203184934003

11.2 雪花算法生成分布式ID的坑

  • 全局唯⼀不能重复-坑

    • 坑一
      • 分布式部署就需要分配不同的workId, 如果workId相同, 可能会导致⽣成的id相同
    • 坑二
      • 分布式情况下,需要保证各个系统时间⼀致,如果服务器 的时钟回拨,就会导致⽣成的 id 重复
      • 啥时候会有系统回拨????
        • ⼩滴课堂-⽼王闲着,⼈⼯去⽣产环境做了系统时间 调整,应该不会这么傻吧
        • 业务需求,代码⾥⾯做了系统时间同步
  • 解决时间回拨的方法

    • 服务器时钟回拨会导致产生重复的 ID,SNOWFLAKE 方案中对原有雪花算法做了改进,增加了一个最大容忍的时钟回拨毫秒数。

      如果时钟回拨的时间超过最大容忍的毫秒数阈值,则程序直接报错;如果在可容忍的范围内,默认分布式主键生成器,会等待时钟同步到最后一次主键生成的时间后再继续工作。

      最大容忍的时钟回拨毫秒数,默认值为 0,可通过属性 max.tolerate.time.difference.milliseconds 设置。

    # 最大容忍的时钟回拨毫秒数
    spring.shardingsphere.sharding.tables.product_order.key-generator.max.tolerate.time.difference.milliseconds=5
    

11.3 雪花算法使用方法

  • 配置实操

    #配置workID
    spring.shardingsphere.sharding.tables.product_order.key-generator.props.worker.id=1
    
    # 最大容忍的时钟回拨毫秒数
    spring.shardingsphere.sharding.tables.product_order.key-generator.max.tolerate.time.difference.milliseconds=5
    
    • 方式一:使⽤MybatisPlus的配置

      • 在DO类配置
      Data
      @EqualsAndHashCode(callSuper = false)
      @TableName("product_order")
      public class ProductOrderDO {
          private static final long serialVersionUID = 1L;
      
          //id默认是自增,设置为 雪花算法 生成id
          @TableId(value = "id", type = IdType.ASSIGN_ID)
          private Long id;
      
      
    • 方式二:添加配置

      #id⽣成策略
      spring.shardingsphere.sharding.tables.product_order.key-generator.column=id
      spring.shardingsphere.sharding.tables.product_order.key-generator.type=SNOWFLAKE
      

12.Sharding-Jdbc广播表和绑定配置表实战

12.1广播表介绍配置和实战

  • 什么是广播表

    • 指所有的分⽚数据源中都存在的表,表结构和表中的数据在每 个数据库中均完全⼀致
    • 适⽤于数据量不⼤且需要与海量数据的表进⾏关联查询的场景 (解决跨库关联查询问题)
    • 例如:字典表、配置表;类似冗余表
  • 添加配置

    #配置⼴播表
    spring.shardingsphere.sharding.broadcast-tables=ad_config
    spring.shardingsphere.sharding.tables.ad_config.key-generator.column=id
    spring.shardingsphere.sharding.tables.ad_config.key-generator.type=SNOWFLAKE
    

12.2水平分库+水平分表实战

  • 库表结构

    • 2个数据库、每个库2张表
    • 需求 插⼊订单数据,分布在不同的库和表上
  • 分库分表配置

    • 分库规则 根据 user_id 进⾏分库
    • 分表规则 根据 product_order_id 订单号进⾏分表
  • 配置

    # 数据源 db0
    spring.shardingsphere.datasource.names=ds0,ds1
    
    # 第一个数据库
    spring.shardingsphere.datasource.ds0.type=com.zaxxer.hikari.HikariDataSource
    spring.shardingsphere.datasource.ds0.driver-class-name=com.mysql.cj.jdbc.Driver
    spring.shardingsphere.datasource.ds0.jdbc-url=jdbc:mysql://120.25.217.15:3306/xdclass_shop_order_0?useUnicode=true&characterEncoding=utf-8&useSSL=false&serverTimezone=Asia/Shanghai&allowPublicKeyRetrieval=true
    spring.shardingsphere.datasource.ds0.username=root
    spring.shardingsphere.datasource.ds0.password=xdclass.net168
    
    
    # 第二个数据库
    spring.shardingsphere.datasource.ds1.type=com.zaxxer.hikari.HikariDataSource
    spring.shardingsphere.datasource.ds1.driver-class-name=com.mysql.cj.jdbc.Driver
    spring.shardingsphere.datasource.ds1.jdbc-url=jdbc:mysql://120.25.217.15:3306/xdclass_shop_order_1?useUnicode=true&characterEncoding=utf-8&useSSL=false&serverTimezone=Asia/Shanghai&allowPublicKeyRetrieval=true
    spring.shardingsphere.datasource.ds1.username=root
    spring.shardingsphere.datasource.ds1.password=xdclass.net168
    
    
    #配置workId
    spring.shardingsphere.sharding.tables.product_order.key-generator.props.worker.id=1
    
    
    #配置广播表
    spring.shardingsphere.sharding.broadcast-tables=ad_config
    spring.shardingsphere.sharding.tables.ad_config.key-generator.column=id
    spring.shardingsphere.sharding.tables.ad_config.key-generator.type=SNOWFLAKE
    
    
    #配置【默认分库策略】
    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.tables.product_order.database-strategy.inline.sharding-column=user_id
    spring.shardingsphere.sharding.tables.product_order.database-strategy.inline.algorithm-expression=ds$->{user_id % 2 }
    
    
    #id生成策略
    spring.shardingsphere.sharding.tables.product_order.key-generator.column=id
    spring.shardingsphere.sharding.tables.product_order.key-generator.type=SNOWFLAKE
    
    # 指定product_order表的数据分布情况,配置数据节点,行表达式标识符使用 ${...} 或 $->{...},
    # 但前者与 Spring 本身的文件占位符冲突,所以在 Spring 环境中建议使用 $->{...}
    #spring.shardingsphere.sharding.tables.product_order.actual-data-nodes=ds0.product_order_$->{0..1}
    spring.shardingsphere.sharding.tables.product_order.actual-data-nodes=ds$->{0..1}.product_order_$->{0..1}
    # 指定product_order表的分片策略,分片策略包括【分片键和分片算法】
    spring.shardingsphere.sharding.tables.product_order.table-strategy.inline.sharding-column=id
    spring.shardingsphere.sharding.tables.product_order.table-strategy.inline.algorithm-expression=product_order_$->{id % 2}
    
    
    # 指定product_order_item表的分片策略,分片策略包括【分片键和分片算法】
    spring.shardingsphere.sharding.tables.product_order_item.actual-data-nodes=ds$->{0..1}.product_order_item_$->{0..1}
    spring.shardingsphere.sharding.tables.product_order_item.table-strategy.inline.sharding-column=product_order_id
    spring.shardingsphere.sharding.tables.product_order_item.table-strategy.inline.algorithm-expression=product_order_item_$->{product_order_id % 2}
    

注意:数据库和表的下标如果不想从0开始,则hash取模后+1 {user_id % 2+1

12.3 绑定表配置实战

  • 什么是绑定表
    • 指分⽚规则⼀致的主表和⼦表
    • ⽐如product_order表和product_order_item表,均按照 order_id分⽚,则此两张表互为绑定表关系
    • 绑定表之间的多表关联查询不会出现笛卡尔积关联,关联查询 效率将⼤⼤提升

image-20221203234439195

  • 库表数量

    image-20221203234529781

  • 配置实战

    #配置workId
    spring.shardingsphere.sharding.tables.product_order.key-generator.props.worker.id=1
    # 指定product_order表的数据分布情况,配置数据节点,⾏表达式标识符使⽤ ${...} 或 $->{...},
    # 但前者与 Spring 本身的⽂件占位符冲突,所以在 Spring 环境中建议使⽤ $->{...}
    spring.shardingsphere.sharding.tables.product_order.actual-data-nodes=ds0.product_order_$->{0..1}
    ## ---------------------指定product_order表 ⾏表达式分⽚策略-----------------------
    ##指定 分⽚键
    spring.shardingsphere.sharding.tables.product_order.table-strategy.inline.sharding-column=user_id
    ##指定 分⽚算法
    spring.shardingsphere.sharding.tables.product_order.table-strategy.inline.algorithm-expression=product_order_$->{user_id % 2}
    # 配置product_order表的id⽣成策略
    spring.shardingsphere.sharding.tables.product_order.key-generator.column=id
    spring.shardingsphere.sharding.tables.product_order.key-generator.type=SNOWFLAKE
    
    #配置⼴播表
    spring.shardingsphere.sharding.broadcast-tables=ad_config
    #ad_config表id⽣成策略
    spring.shardingsphere.sharding.tables.ad_config.key-generator.column=id
    spring.shardingsphere.sharding.tables.ad_config.key-generator.type=SNOWFLAKE
    
    #绑定表 product_order,product_order_item
    spring.shardingsphere.sharding.binding‐tables[0] =product_order,product_order_item
    

标签:product,分库,spring,id,shardingsphere,order
From: https://www.cnblogs.com/snail05/p/17026160.html

相关文章

  • 使用线程池和shardingsphere-jdbc对统计进行分表查询优化
    记录之前的一次优化过程,之前发布在wiki上,现摘出发布。0.前言主要查询表为还款计划表xx_plan(近4000w,日新增10~20w)、实还记录表xx_actual(2600w+,日新增5~10w)、代偿记录表x......
  • VIP06-ShardingSphere5.x新版本特性
    一、整体理解新版本二、5.X部分新特性1、DistSQL2、可插拔内核3、数据迁移三、全部内容总结 一、整体理解新版本​ShardingSphere在2021年十月份推出了5.0......
  • dynamic + shardingSphere整合
    背景按查询时间来走分表,分表根据年份依赖<dependency><groupId>com.baomidou</groupId><artifactId>dynamic-datasource-spring-boot-starter</artifactId......
  • MySql整合Shardingsphere分库分表
    前言前面一篇文章将MySql主从复制模式就搭建完毕了,但是在主从复制模式情况下不能解决单表数据量大了的性能问题,如一张表书记量太大了,查询效率会比较低,那么此时就需要对数据......
  • OpenSergo & ShardingSphere 社区共建微服务视角的数据库治理标准
    作者:赵奕豪(宿何)为什么需要微服务治理与OpenSergo?在经典微服务架构中,我们通常将服务调用中各角色划分为三部分:服务提供者、服务消费者、注册中心。经典的微服务架构可以解决......
  • OpenSergo & ShardingSphere 社区共建微服务视角的数据库治理标准
    作者:赵奕豪(宿何)为什么需要微服务治理与OpenSergo?在经典微服务架构中,我们通常将服务调用中各角色划分为三部分:服务提供者、服务消费者、注册中心。经典的微服务架构可以......
  • shardingsphere-jdbc 水平分表学习记录
    放在自己博客里搬过来一份~前司使用的是自己魔改的TDDL,在家时间比较多就尝试学一些业内比较常用的中间件.这里记录一下学习中遇到的一些问题.环境设置的比较简单(太......
  • 墨天轮沙龙 | SphereEx代野:Apache ShardingSphere-从中间件到分布式生态演进之路
    在9月22日举办的【墨天轮数据库沙龙第十期—国产中间件专场】中,SphereEx解决方案专家代野分享了ApacheShardingSphere:从中间件到分布式生态演进之路》主题演讲,本文为整......
  • ShardingSphere的配置中心
    ShardingSphere的配置中心本篇文章源码基于4.0.1版本使用配置中心来管理配置文件非常方便灵活,实现配置信息的动态加载,ShardingSphere支持很多配置中心,包括Apollo、Zooke......
  • ShardingSphere的注册中心
    ShardingSphere的注册中心本篇文章源码基于4.0.1版本注册中心在ShardingSphere的作用就是用来管理各种数据源,在使用的时候,所有数据源通过向注册中心的指定目录下创建节......