3

分库分表Sharding-JDBC介绍

 1 month ago
source link: https://blog.51cto.com/maguobin/10676734
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.

1.ShardingSphere生态简介

Apache ShardingSphere 是一套开源的分布式数据库解决方案组成的生态圈,核心由: JDBC、Proxy 和 Sidecar(规划中)这 3 款既能够独立部署,又支持混合部署配合使用的产品组成;

功能特性:它们均提供标准化的数据水平扩展分布式事务分布式治理等功能,可适用于如 Java 同构、异构语言、云原生等各种多样化的应用场景。

官方网站:https://shardingsphere.apache.org/index_zh.html

文档地址:https://shardingsphere.apache.org/document/legacy/4.x/document/cn/overview

Sharding-jdbc是ShardingSphere的其中一个模块,定位为轻量级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的核心功能为数据分片读写分离,通过Sharding-JDBC,应用可以透明的使用jdbc访问已经分库分表、读写分离的多个数据源,而不用关心数据源的数量以及数据如何分布。

2.Sharding-jdbc相关名词解释

参考官网-核心概念

  • 逻辑表(LogicTable):进行水平拆分的时候同一类型(逻辑、数据结构相同)的表的总称。例:用户数据根据主键尾数拆分为2张表,分别是tab_user_0到tab_user_1,他们的逻辑表名为tab_user。
  • 真实表(ActualTable):在分片的数据库中真实存在的物理表。即上个示例中的tab_user_0到tab_user_1。
  • 数据节点(DataNode):数据分片的最小单元。由数据源名称和数据表组成,例:spring-boot_0.tab_user_0,spring-boot_0.tab_user_1,spring-boot_1.tab_user_0,spring-boot_1.tab_user_1。
    说白了,具体到指定库下的指定表就是一个数据节点;
  • 动态表(DynamicTable):逻辑表和物理表不一定需要在配置规则中静态配置。如,按照日期分片的场景,物理表的名称随着时间的推移会产生变化(股票流水)。
  • 广播表(公共表):指所有的分片数据源中都存在的表,表结构和表中的数据在每个数据库中均完全一致。适用于数据量不大且需要与海量数据的表进行关联查询的场景,例如:字典表。
  • 绑定表(BindingTable):指E。例如:t_order表和t_order_item表,均按照order_no分片,则此两张表互为绑定表关系。绑定表之间的多表关联查询不会出现笛卡尔积关联,关联查询效率将大大提升。举例说明,如果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的数据落库位置,与order_item落库的位置在同一个数据节点。

在不配置绑定表关系时,假设分片键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);

其中t_order在FROM的最左侧,ShardingSphere将会以它作为整个绑定表的主表。 所有路由计算将会只使用主表的策略,那么t_order_item表的分片计算将会使用t_order`的条件。故绑定表之间的分区键要完全相同。【解决多表关联查询造成笛卡尔积问题】

  • 分片键(ShardingColumn):分片字段用于将数据库(表)水平拆分的字段,支持单字段及多字段分片。例如上例中的order_id。
    一般在业务中经常查询使用的字段会作为分片键;

3.Sharding-JDBC执行原理

分库分表Sharding-JDBC介绍_数据

参考官网-内部剖析:

逻辑表:t_user

物理表:ds0.t_user_1,ds0.t_user_2,ds1.t_user_1,ds1.t_user_2

shardingSphere的3个产品的数据分片主要流程是完全一致的。 核心由SQL解析 => 执行器优化 => SQL路由 => SQL改写 => SQL执行 => 结果归并的流程组成。

例如现在有一条查询语句:

# 此时t_user对应的表是不存在的,是逻辑上表
select * from t_user where id=10

进行了分库分表操作,2个库ds0,ds1,采用的分片键为id,逻辑表为t_user,真实表为t_user_0、t_user_1两张表,分库、分表算法为均为取余(%2)。

  • sql解析:通过解析sql语句提取分片键列与值进行分片,例如比较符 =、in 、between and,及查询的表等。
  • 执行器优化:合并和优化分片条件,如OR 转化成 in等。
select * from t_user where id=1 or id=2 or id=3 自动优化:select * from t_user where id in (1,2,3)
  • sql路由:找到sql需要去哪个库、哪个表执行语句,上例sql根据采用的策略可以得到将在ds0库,t_user_0表执行语句。说白了,就是根据逻辑表查找物理表的过程;
  • sql改写:根据解析结果,及采用的分片逻辑改写sql,SQL改写分为正确性改写和优化改写。
    上例经过sql改写后,真实语句为:
select * from ds0.t_user_0 where id=10;==>ds0.t_user_0 2S
select * from ds0.t_user_1 where id=10;==>ds0.t_user_1 2S
select * from ds1.t_user_0 where id=10;==>ds1.t_user_0 2S
select * from ds1.t_user_1 where id=10;==>ds1.t_user_1 2S
  • sql执行:通过多线程执行器异步执行。
  • 结果归并:将多个执行结果集归并以便于通过统一的JDBC接口输出。结果归并包括流式归并、内存归并和使用装饰者模式的追加归并这几种方式;

4.Sharding-jdbc分片方式介绍

Sharding-jdbc参考地址

sharding-jdbc实现数据分片有4种策略:

  • inline模式
通过groovy表达式来表示分库分表的策略;
db0
  ├── t_order0
  └── t_order1
db1
  ├── t_order0
  └── t_order1
  表达式:db${0..1}.t_order${0..1}
  	     t_order${orderId % 2}
  • 使用最简单,开发成本比较低;
  • 只能使用单个字段作为分片键;
  • 基于行表达式定义分片规则;
  • standard标准分片模式
  • 用户可通过代码自定义复杂的分片策略;
  • 同样只能使用单个字段作为分片键;
  • complex复合分片模式
  • 用于多分片键的复合分片策略(多片键)
  • Hint强制分片模式
  • 不指定片键,通过代码动态指定路由规则
  • 强制分片策略(强制路由)

About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK