关于分库分表

背景描述

  • 最初设计的系统只用了单机数据库
  • 随着用户的不断增多,考虑到系统的高可用和越来越多的用户请求,开始使用数据库主从架构
  • 当用户量级和业务进一步提升后,写请求越来越多,这时需要开始使用了分库分表

遇到的问题

  • 用户请求量太大
    单服务器TPS、内存、IO都是有上限的,需要将请求打散分布到多个服务器
  • 单库数据量太大
    单个数据库处理能力有限;单库所在服务器的磁盘空间有限;单库上的操作IO有瓶颈
  • 单表数据量太大
    查询、插入、更新操作都会变慢,在加字段、加索引、机器迁移都会产生高负载,影响服务

如何解决

垂直拆分

  • 垂直分库
    微服务架构时,业务切割得足够独立,数据也会按照业务切分,保证业务数据隔离,大大提升了数据库的吞吐能力

在这里插入图片描述

  • 垂直分表
    表中字段太多且包含大字段的时候,在查询时对数据库的IO、内存会受到影响,同时更新数据时,产生的binlog文件会很大,MySQL在主从同步时也会有延迟的风险
    在这里插入图片描述

水平拆分(数据分片)

  • 水平分表
    针对数据量巨大的单张表(比如订单表),按照规则把一张表的数据切分到多张表里面去。但是这些表还是在同一个库中,所以库级别的数据库操作还是有IO瓶颈。

在这里插入图片描述

  • 水平分库
    将单张表的数据切分到多个服务器上去,每个服务器具有相应的库与表,只是表中数据集合不同。 水平分库分表能够有效的缓解单机和单库的性能瓶颈和压力,突破IO、连接数、硬件资源等的瓶颈
    在这里插入图片描述

  • 水平分库规则
    不跨库、不跨表,保证同一类的数据都在同一个服务器上面。

    数据在切分之前,需要考虑如何高效的进行数据获取,如果每次查询都要跨越多个节点,就需要谨慎使用。

  • 水平分表规则

    • RANGE

      • 时间:按照年、月、日去切分。例如order_2020、order_202005、order_20200501

      • 地域:按照省或市去切分。例如order_beijing、order_shanghai、order_chengdu

      • 大小:从0到1000000一个表。例如1000001-2000000放一个表,每100万放一个表

    • HASH

      • 用户ID取模
        不同的业务使用的切分规则是不一样,就上面提到的切分规则,举例如下:

        • 站内信
          用户维度:用户只能看到发送给自己的消息,其他用户是不可见的,这种情况下是按照用户ID hash分库,在用户查看历史记录翻页查询时,所有的查询请求都在同一个库内

        • 用户表
          范围法:以用户ID为划分依据,将数据水平切分到两个数据库实例,如:1到1000W在一张表,1000W到2000W在一张表,这种情况会出现单表的负载较高

          按照用户ID HASH尽量保证用户数据均衡分到数据库中

          如果在登录场景下,用户输入手机号和验证码进行登录,这种情况下,登录时是不是需要扫描所有分库的信息?
          最终方案:用户信息采用ID做切分处理,同时存储用户ID和手机号的映射的关系表(新增一个关系表),关系表采用手机号进行切分。可以通过关系表根据手机号查询到对应的ID,再定位用户信息。

        • 流水表
          时间维度:可以根据每天新增的流水来判断,选择按照年份分库,还是按照月份分库,甚至也可以按照日期分库

        • 订单表
          在线招聘网站中,求职者(下面统称C端用户)投递企业(下面统称B端用户)的职位产生的记录称之为订单表。在线上的业务场景中,C端用户看自己的投递记录,每次的投递到了哪个状态,B端用户查看自己收到的简历,对于合适的简历会进行下一步沟通,同一个公司内的员工可以协作处理简历。

          如何能同时满足C端和B端对数据查询,不进行跨库处理?

          最终方案:为了同时满足两端用户的业务场景,采用空间换时间,将一次的投递记录存为两份,C端的投递记录以用户ID为分片键,B端收到的简历按照公司ID为分片键
          在这里插入图片描述

  • 主键选择

    • UUID:本地生成,不依赖数据库,缺点就是作为主键性能太差

    • SNOWFLAKE:百度UidGenerator、美团Leaf、基于SNOWFLAKE算法实现

  • 数据一致性

    • 强一致性:XA协议
    • 最终一致性:TCC、saga、Seata

  • 数据库扩容

    • 成倍增加数据节点,实现平滑扩容

    • 成倍扩容以后,表中的部分数据请求已被路由到其他节点上面,可以清理掉

  • 业务层改造

    • 基于代理层方式:Mycat、Sharding-Proxy、MySQL Proxy

    • 基于应用层方式:Sharding-jdbc

  • 分库后面临的问题

    • 事务问题:一次投递需要插入两条记录,且分布在不同的服务器上,数据需要保障一致性。

    • 跨库跨表的join问题,可以通过下面几种方式进行处理:

      • 全局表(字典表):基础数据/配置数据,所有库都拷贝一份
      • 字段冗余:可以使用字段冗余就不用join查询了
      • 系统层组装:可以在业务层分别查询出来,然后组装起来,逻辑较复杂
    • 额外的数据管理负担和数据运算压力:数据库扩容、维护成本变高

ShardingSphere介绍

官网地址

  Apache ShardingSphere是一款开源的分布式数据库中间件组成的生态圈。它由Sharding-JDBC、Sharding-Proxy和Sharding-Sidecar(规划中)这3款相互独立的产品组成。 他们均提供标准化的数据分片、分布式事务和数据库治理功能,可适用于如Java同构、异构语言、容器、云原生等各种多样化的应用场景。

ShardingSphere项目状态如下,目前已经更新到了5.0版本,但是本次学习任然使用4.1版本:
在这里插入图片描述
ShardingSphere定位为关系型数据库中间件,旨在充分合理地在分布式的场景下利用关系型数据库的计算存储能力,而并非实现一个全新的关系型数据库。
在这里插入图片描述

  • Sharding-JDBC:被定位为轻量级Java框架,在Java的JDBC层提供的额外服务,以jar包形式使用。

  • Sharding-Proxy:被定位为透明化的数据库代理端,提供封装了数据库二进制协议的服务端版本,用于完成对异构语言的支持。

  • Sharding-Sidecar:被定位为Kubernetes或Mesos的云原生数据库代理,以DaemonSet的形式代理所有对数据库的访问。

在这里插入图片描述
Sharding-JDBC、Sharding-Proxy和Sharding-Sidecar三者区别如下:

ShardingSphere-JDBCShardingSphere-ProxyShardingSphere-Sidecar
数据库任意MySQL/PostgreSQL MySQL/PostgreSQL
连接消耗数
异构语言仅 Java任意任意
性能损耗低损耗略高损耗低
无中心化
静态入口

  ShardingSphere-JDBC 采用无中心化架构,适用于 Java 开发的高性能的轻量级 OLTP 应用;ShardingSphere-Proxy 提供静态入口以及异构语言的支持,适用于 OLAP 应用以及对分片数据库进行管理和运维的场景。

  Apache ShardingSphere 是多接入端共同组成的生态圈。 通过混合使用 ShardingSphere-JDBC 和 ShardingSphere-Proxy,并采用同一注册中心统一配置分片策略,能够灵活的搭建适用于各种场景的应用系统,使得架构师更加自由地调整适合与当前业务的最佳系统架构。

ShardingSphere安装包下载:https://shardingsphere.apache.org/document/current/cn/downloads/
在这里插入图片描述
在这里插入图片描述
使用Git下载工程: https://github.com/apache/incubator-shardingsphere.git
在这里插入图片描述

Sharding-JDBC

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

  • 适用于任何基于Java的ORM框架,如:JPA, Hibernate, Mybatis, Spring JDBC Template或直接使用JDBC。

  • 基于任何第三方的数据库连接池,如:DBCP, C3P0, BoneCP, Druid, HikariCP等。

  • 支持任意实现JDBC规范的数据库。目前支持MySQL,Oracle,SQLServer和PostgreSQL。
    在这里插入图片描述

Sharding-JDBC主要功能:

  • 数据分片

    • 分库、分表

    • 读写分离

    • 分片策略

    • 分布式主键

  • 分布式事务

    • 标准化的事务接口
    • XA强一致性事务
    • 柔性事务
  • 数据库治理

    • 配置动态化
    • 编排和治理
    • 数据脱敏
    • 可视化链路追踪

Sharding-JDBC 内部结构:

在这里插入图片描述

  • 图中黄色部分表示的是Sharding-JDBC的入口API,采用工厂方法的形式提供。 目前有ShardingDataSourceFactory和MasterSlaveDataSourceFactory两个工厂类。

    • ShardingDataSourceFactory支持分库分表、读写分离操作

    • MasterSlaveDataSourceFactory支持读写分离操作

  • 图中蓝色部分表示的是Sharding-JDBC的配置对象,提供灵活多变的配置方式。ShardingRuleConfiguration是分库分表配置的核心和入口,它可以包含多个TableRuleConfiguration和MasterSlaveRuleConfiguration。

    • TableRuleConfiguration封装的是表的分片配置信息,有5种配置形式对应不同的Configuration类型。

    • MasterSlaveRuleConfiguration封装的是读写分离配置信息。

  • 图中红色部分表示的是内部对象,由Sharding-JDBC内部使用,应用开发者无需关注。Sharding-JDBC通过ShardingRuleConfiguration和MasterSlaveRuleConfiguration生成真正供ShardingDataSource和MasterSlaveDataSource使用的规则对象。ShardingDataSource和MasterSlaveDataSource实现了DataSource接口,是JDBC的完整实现方案。

Sharding-JDBC初始化流程:

  1. 根据配置的信息生成Configuration对象

  2. 通过Factory会将Configuration对象转化为Rule对象

  3. 通过Factory会将Rule对象与DataSource对象封装

  4. Sharding-JDBC使用DataSource进行分库分表和读写分离操作

Sharding-JDBC 使用过程:

  • 引入maven依赖
<dependency>
    <groupId>org.apache.shardingsphere</groupId>
    <artifactId>sharding-jdbc-core</artifactId>
    <version>${latest.release.version}</version>
</dependency>

注意: 请将${latest.release.version}更改为实际的版本号。

  • 规则配置
    Sharding-JDBC可以通过Java,YAML,Spring命名空间和Spring Boot Starter四种方式配置,开发者可根据场景选择适合的配置方式。

  • 创建DataSource
    通过ShardingDataSourceFactory工厂和规则配置对象获取ShardingDataSource,然后即可通过DataSource选择使用原生JDBC开发,或者使用JPA, MyBatis等ORM工具。

    DataSource dataSource = ShardingDataSourceFactory.createDataSource(dataSourceMap,shardingRuleConfig, props);
    

ShardingSphere核心概念

官网地址

表概念

  • 真实表
    数据库中真实存在的物理表。例如b_order0、b_order1

  • 逻辑表
    在分片之后,同一类表结构的名称(总成)。例如b_order。

  • 数据节点
    在分片之后,由数据源和数据表组成。例如ds0.b_order1

  • 绑定表
    指的是分片规则一致的关系表(主表、子表),例如b_order和b_order_item,均按照order_id分片,则此两个表互为绑定表关系。绑定表之间的多表关联查询不会出现笛卡尔积关联,可以提升关联查询效率。

    b_order:b_order0、b_order1
    b_order_item:b_order_item0、b_order_item1
    
    select * from b_order o join b_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);
    

    在配置绑定表关系后,路由的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);
    
  • 广播表
    在使用中,有些表没必要做分片,例如字典表、省份信息等,因为他们数据量不大,而且这种表可能需要与海量数据的表进行关联查询。广播表会在不同的数据节点上进行存储,存储的表结构和数据完全相同。

分片概念

分片键

  用于分片的数据库字段,是将数据库(表)水平拆分的关键字段。例:将订单表中的订单主键的尾数取模分片,则订单主键为分片字段。 SQL中如果无分片字段,将执行全路由,性能较差。 除了对单分片字段的支持,ShardingSphere也支持根据多个字段进行分片。

分片算法(ShardingAlgorithm)

  由于分片算法和业务实现紧密相关,因此并未提供内置分片算法,而是通过分片策略将各种场景提炼出来,提供更高层级的抽象,并提供接口让应用开发者自行实现分片算法。目前提供4种分片算法。

  • 精确分片算法PreciseShardingAlgorithm
    用于处理使用单一键作为分片键的=与IN进行分片的场景。

  • 范围分片算法RangeShardingAlgorithm
    用于处理使用单一键作为分片键的BETWEEN AND、>、<、>=、<=进行分片的场景。

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

  • Hint分片算法HintShardingAlgorithm
    用于处理使用Hint行分片的场景。对于分片字段非SQL决定,而由其他外置条件决定的场景,可使用SQL Hint灵活的注入分片字段。例:内部系统,按照员工登录主键分库,而数据库中并无此字段。SQL Hint支持通过Java API和SQL注释两种方式使用。

分片策略

  包含分片键和分片算法,由于分片算法的独立性,将其独立抽离。真正可用于分片操作的是分片键 + 分片算法,也就是分片策略。目前提供5种分片策略。

  • 标准分片策略
    对应StandardShardingStrategy。提供对SQL语句中的=, >, <, >=, <=, IN和BETWEEN AND的分片操作支持。StandardShardingStrategy只支持单分片键,提供PreciseShardingAlgorithm和RangeShardingAlgorithm两个分片算法。PreciseShardingAlgorithm是必选的,用于处理=和IN的分片。RangeShardingAlgorithm是可选的,用于处理BETWEEN AND, >, <, >=, <=分片,如果不配置RangeShardingAlgorithm,SQL中的BETWEEN AND将按照全库路由处理。

  • 复合分片策略
    对应ComplexShardingStrategy。复合分片策略。提供对SQL语句中的=, >, <, >=, <=, IN和BETWEEN AND的分片操作支持。ComplexShardingStrategy支持多分片键,由于多分片键之间的关系复杂,因此并未进行过多的封装,而是直接将分片键值组合以及分片操作符透传至分片算法,完全由应用开发者实现,提供最大的灵活度。

  • 行表达式分片策略
    对应InlineShardingStrategy。使用Groovy的表达式,提供对SQL语句中的=和IN的分片操作支持,只支持单分片键。对于简单的分片算法,可以通过简单的配置使用,从而避免繁琐的Java代码开发,如: t_user_$->{u_id % 8} 表示t_user表根据u_id模8,而分成8张表,表名称为t_user_0到t_user_7。

  • Hint分片策略
    对应HintShardingStrategy。通过Hint指定分片值而非从SQL中提取分片值的方式进行分片的策略。

  • 不分片策略
    对应NoneShardingStrategy。不分片的策略。

分片策略配置

对于分片策略存有数据源分片策略和表分片策略两种维度,两种策略的API完全相同。

  • 数据源分片策略
    用于配置数据被分配的目标数据源。

  • 表分片策略
    用于配置数据被分配的目标表,由于表存在与数据源内,所以表分片策略是依赖数据源分片
    策略结果的。

流程剖析

ShardingSphere 3个产品的数据分片功能主要流程是完全一致的,如下图所示。
在这里插入图片描述

  • SQL解析
    SQL解析分为词法解析和语法解析。 先通过词法解析器将SQL拆分为一个个不可再分的单词。再使用语法解析器对SQL进行理解,并最终提炼出解析上下文。
    Sharding-JDBC采用不同的解析器对SQL进行解析,解析器类型如下:

    • MySQL解析器

    • Oracle解析器

    • SQLServer解析器

    • PostgreSQL解析器

    • 默认SQL解析器

  • 查询优化
    负责合并和优化分片条件,如OR等。

  • SQL路由
    根据解析上下文匹配用户配置的分片策略,并生成路由路径。目前支持分片路由和广播路由。

  • SQL改写
    将SQL改写为在真实数据库中可以正确执行的语句。SQL改写分为正确性改写和优化改写。

  • SQL执行
    通过多线程执行器异步执行SQL。

  • 结果归并
    将多个执行结果集归并以便于通过统一的JDBC接口输出。结果归并包括流式归并、内存归并和使
    用装饰者模式的追加归并这几种方式。

SQL使用规范

  • SQL使用规范

    • 支持项
      • 路由至单数据节点时,目前MySQL数据库100%全兼容,其他数据库完善中。

      • 路由至多数据节点时,全面支持DQL、DML、DDL、DCL、TCL。支持分页、去重、排序、分组、聚合、关联查询(不支持跨库关联)。以下用最为复杂的查询为例:

        • SELECT主语句
          	SELECT select_expr [, select_expr ...] FROM table_reference [, table_reference ...]
          	[WHERE predicates]
          	[GROUP BY {col_name | position} [ASC | DESC], ...]
          	[ORDER BY {col_name | position} [ASC | DESC], ...]
          	[LIMIT {[offset,] row_count | row_count OFFSET offset}]
          
  • 不支持项

    • 路由至多数据节点

    • 不支持CASE WHEN、HAVING、UNION (ALL),有限支持子查询。

除了分页子查询的支持之外(详情请参考分页),也支持同等模式的子查询。无论嵌套多少层,ShardingSphere都可以解析至第一个包含数据表的子查询,一旦在下层嵌套中再次找到包含数据表的子查询将直接抛出解析异常。

例如,以下子查询可以支持:

SELECT COUNT(*) FROM (SELECT * FROM t_order o)

以下子查询不支持:

SELECT COUNT(*) FROM (SELECT * FROM t_order o WHERE o.id IN (SELECT id FROM t_order WHERE status = ?))

简单来说,通过子查询进行非功能需求,在大部分情况下是可以支持的。比如分页、统计总数等;而通过子查询实现业务查询当前并不能支持。

  • 由于归并的限制,子查询中包含聚合函数目前无法支持。

  • 不支持包含schema的SQL。因为ShardingSphere的理念是像使用一个数据源一样使用多数据源,因此对SQL的访问都是在同一个逻辑schema之上。

  • 当分片键处于运算表达式或函数中的SQL时,将采用全路由的形式获取结果。
    例如下面SQL,create_time为分片键:

SELECT * FROM t_order WHERE to_date(create_time, 'yyyy-mm-dd') = '2019-01-01';

由于ShardingSphere只能通过SQL字面提取用于分片的值,因此当分片键处于运算表达式或函数中时,ShardingSphere无法提前获取分片键位于数据库中的值,从而无法计算出真正的分片值。

当出现此类分片键处于运算表达式或函数中的SQL时,ShardingSphere将采用全路由的形式获取结果。


不支持的SQL示例:

SQL不支持原因
INSERT INTO tbl_name (col1, col2, …) VALUES(1+2, ?, …)VALUES语句不支持运算表达式
INSERT INTO tbl_name (col1, col2, …) SELECT col1, col2, … FROM tbl_name WHERE col3 = ?INSERT … SELECT
SELECT COUNT(col1) as count_alias FROM tbl_name GROUP BY col1 HAVING count_alias > ?HAVING
SELECT * FROM tbl_name1 UNION SELECT * FROM tbl_name2UNION
SELECT * FROM tbl_name1 UNION ALL SELECT * FROM tbl_name2UNION ALL
SELECT * FROM ds.tbl_name1包含schema
SELECT SUM(DISTINCT col1), SUM(col1) FROM tbl_name详见DISTINCT支持情况详细说明
SELECT * FROM tbl_name WHERE to_date(create_time, ‘yyyy-mm-dd’) = ?会导致全路由

分页查询

完全支持MySQL和Oracle的分页查询,SQLServer由于分页查询较为复杂,仅部分支持.

  • 性能瓶颈:
    查询偏移量过大的分页会导致数据库获取数据性能低下,以MySQL为例:
SELECT * FROM t_order ORDER BY id LIMIT 1000000, 10

这句SQL会使得MySQL在无法利用索引的情况下跳过1000000条记录后,再获取10条记录,其性能可想而知。 而在分库分表的情况下(假设分为2个库),为了保证数据的正确性,SQL会改写为:

SELECT * FROM t_order ORDER BY id LIMIT 0, 1000010

即将偏移量前的记录全部取出,并仅获取排序后的最后10条记录。这会在数据库本身就执行很慢的情况下,进一步加剧性能瓶颈。 因为原SQL仅需要传输10条记录至客户端,而改写之后的SQL则会传输1,000,010 * 2的记录至客户端。

  • ShardingSphere的优化
    ShardingSphere进行了2个方面的优化。

    • 首先,采用流式处理 + 归并排序的方式来避免内存的过量占用。由于SQL改写不可避免的占用了额外的带宽,但并不会导致内存暴涨。 与直觉不同,大多数人认为ShardingSphere会将1,000,010 * 2记录全部加载至内存,进而占用大量内存而导致内存溢出。 但由于每个结果集的记录是有序的,因此ShardingSphere每次比较仅获取各个分片的当前结果集记录,驻留在内存中的记录仅为当前路由到的分片的结果集的当前游标指向而已。 对于本身即有序的待排序对象,归并排序的时间复杂度仅为O(n),性能损耗很小。

    • 其次,ShardingSphere对仅落至单分片的查询进行进一步优化。 落至单分片查询的请求并不需要改写SQL也可以保证记录的正确性,因此在此种情况下,ShardingSphere并未进行SQL改写,从而达到节省带宽的目的。

  • 分页方案优化
    由于LIMIT并不能通过索引查询数据,因此如果可以保证ID的连续性,通过ID进行分页是比较好的解决方案:

SELECT * FROM t_order WHERE id > 100000 AND id <= 100010 ORDER BY id

或通过记录上次查询结果的最后一条记录的ID进行下一页的查询:

SELECT * FROM t_order WHERE id > 100000 LIMIT 10

行表达式

  • Inline行表达式
    InlineShardingStrategy:采用Inline行表达式进行分片的配置。
    Inline是可以简化数据节点和分片算法配置信息。主要是解决配置简化、配置一体化。

语法格式:
行表达式的使用非常直观,只需要在配置中使用 e x p r e s s i o n 或 { expression }或 expression->{ expression }标识行表达式即可。例如:

${['online', 'offline']}_table${1..3}

最终会解析为:

online_table1, online_table2, online_table3, offline_table1, offline_table2, offline_table3

配置数据节点:
对于均匀分布的数据节点,如果数据结构如下:

db0
  ├── t_order0 
  └── t_order1 
db1
  ├── t_order0 
  └── t_order1

用行表达式可以简化为:

db${0..1}.t_order${0..1}

或者

db$->{0..1}.t_order$->{0..1}

对于自定义的数据节点,如果数据结构如下:

db0
  ├── t_order0 
  └── t_order1 
db1
  ├── t_order2
  ├── t_order3
  └── t_order4

用行表达式可以简化为:

db0.t_order${0..1},db1.t_order${2..4}

或者

db0.t_order$->{0..1},db1.t_order$->{2..4}
  • 分片算法配置
    对于只有一个分片键的使用=和IN进行分片的SQL,可以使用行表达式代替编码方式配置。

    行表达式内部的表达式本质上是一段Groovy代码,可以根据分片键进行计算的方式,返回相应的真实数据源或真实表名称。

    例如:分为10个库,尾数为0的路由到后缀为0的数据源, 尾数为1的路由到后缀为1的数据源,以此类推。用于表示分片算法的行表达为:

    ds${id % 10}
    
    或者
    
    ds$->{id % 10}
    

    结果为:ds0、ds1、ds2… ds9

分布式主键

ShardingSphere不仅提供了内置的分布式主键生成器,例如UUID、SNOWFLAKE,还抽离出分布式主键生成器的接口,方便用户自行实现自定义的自增主键生成器。

内置主键生成器:

  • UUID
    采用UUID.randomUUID()的方式产生分布式主键。

  • SNOWFLAKE
    在分片规则配置模块可配置每个表的主键生成策略,默认使用雪花算法,生成64bit的长整型数据,详细规则参考下面的官网地址。
    https://shardingsphere.apache.org/document/legacy/4.x/document/cn/features/sharding/other-features/key-generator/

自定义主键生成器:

  • 自定义主键类,实现ShardingKeyGenerator接口

  • 按SPI规范配置自定义主键类
    在Apache ShardingSphere中,很多功能实现类的加载方式是通过SPI注入的方式完成的。注意:在resources目录下新建META-INF文件夹,再新建services文件夹,然后新建文件的名字为org.apache.shardingsphere.spi.keygen.ShardingKeyGenerator,打开文件,复制自定义主键类全路径到文件中保存。

  • 自定义主键类应用配置

     #对应主键字段名
    spring.shardingsphere.sharding.tables.t_book.key-generator.column=id
    #对应主键类getType返回内容
    spring.shardingsphere.sharding.tables.t_book.keygenerator.type=SELFKEY
    
Logo

为开发者提供学习成长、分享交流、生态实践、资源工具等服务,帮助开发者快速成长。

更多推荐