【ShardingSphere技术专题】「ShardingJDBC」(2) 进阶领略一下数据分片的核心概念

前提介绍

承接上一篇文章:(【ShardingSphere技术专题】「ShardingJDBC」(1)带你一同认识一下ShardingJDBC是什么?(高手勿入)),让我们了解了相关ShardingJDBC的作用和功能定位,以及技术本质,针对于它最核心的分片技术,接下来我们需要针对于ShardingJDBC的分片的核心概念进行介绍!

ShardingJDBC-表模型

ShardingJDBC的逻辑表概念,屏蔽下面的分片技术!

逻辑表

  • 水平拆分的数据库(表)的相同逻辑和数据结构表的总称。例:用户数据根据主键尾数拆分为 10 张表,分别是userinfo_0 到 userinfo_9,他们的逻辑表名为 userinfo。

物理表

  • 在分片的数据库中真实存在的物理表。即上个示例中的 userinfo_0 到 userinfo_9。

数据节点

  • 数据分片的最小单元。由数据源名称和数据表组成,例:ds0.userinfo_0。

绑定表

指分片规则一致的主表和子表。

  • 例如:userInfo 表和 userInfo_extend 表,均按照 user_id 分片,则此两张表互为绑定表关系。

  • 绑定表之间的多表关联查询不会出现笛卡尔积关联,关联查询效率将大大提升。

举例说明,如果SQL 为:
SELECT i.* FROM userInfo o JOIN userInfo_extend i ON o.user_id=i.user_id WHERE o.user_id in (10, 11);
  • 在不配置绑定表关系时,假设分片键user_id 将数值 10 路由至第 0 片,将数值 11 路由至第 1 片,那么路由后的 SQL 应该为 4 条,它们呈现为笛卡尔积:
SELECT i.* FROM userInfo_0 o JOIN userInfo_extend_0 i ON o.user_id=i.user_id WHERE o.user_id in (10, 11);

SELECT i.* FROM userInfo_0 o JOIN userInfo_extend_1 i ON o.user_id=i.user_id WHERE o.user_id in (10, 11);

SELECT i.* FROM userInfo_1 o JOIN userInfo_extend_0 i ON o.user_id=i.user_id WHERE o.user_id in (10, 11);

SELECT i.* FROM userInfo_1 o JOIN userInfo_extend_1 i ON o.user_id=i.user_id WHERE o.user_id in (10, 11);
  • 在配置绑定表关系后,路由的 SQL 应该为 2 条:
SELECT i.* FROM userInfo_0 o JOIN userInfo_extend_0 i ON o.user_id=i.user_id WHERE o.user_id in (10, 11);

SELECT i.* FROM userInfo_1 o JOIN userInfo_extend_1 i ON o.user_id=i.user_id WHERE o.user_id in (10, 11);
  • 其中 userInfo 在 FROM 的最左侧,ShardingSphere将会以它作为整个绑定表的主表。

  • 所有路由计算将会只使用主表的策略,那么 userInfo_extend 表的分片计算将会使用 userInfo 的条件。故绑定表之间的分区键要完全相同。

广播表

指所有的分片数据源中都存在的表,表结构和表中的数据在每个数据库中均完全一致。适用于数据量不大且需要与海量数据的表进行关联查询的场景,例如:字典表、配置信息表。

单表

指所有的分片数据源中只存在唯一一张的表。适用于数据量不大且不需要做任何分片操作的场景。

ShardingJDBC-分片配置

分片策略配置

对于分片策略存有数据源分片策略和表分片策略两种维度。

分片键

主要用于分片的数据库字段,是将数据库(表)水平拆分的关键字段。例:将用户表中的user主键的尾数取模分片,则user主键为分片字段。

SQL中如果无分片字段,将执行全路由,性能较差。 除了对单分片字段的支持,Apache ShardingSphere 也支持根据多个字段进行分片。

分片算法

通过分片算法将数据分片,支持通过 =、>=、<=、>、<、BETWEEN 和 IN 分片。 分片算法需要应用方开发者自行实现,可实现的灵活度非常高。

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

用于处理使用单一键作为分片键的 =、IN、BETWEEN AND、>、<、>=、<= 进行分片的场景,需要配合StandardShardingStrategy使用。

复合分片算法(ComplexKeysShardingAlgorithm)

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

Hint分片算法(HintShardingAlgorithm)

用于处理使用 Hint 行分片的场景。需要配合 HintShardingStrategy 使用,具体未来会进行详细介绍!

分片策略

  • 包含分片键和分片算法,由于分片算法的独立性,将其独立抽离。

  • 真正可用于分片操作的是分片键 + 分片算法,也就是分片策略。目前提供 4 种分片策略。

标准分片策略

对应 StandardShardingStrategy:提供对 SQL 语句中的 =, >, <, >=, <=, IN 和 BETWEEN AND 的分片操作支持。

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

对应ComplexShardingStrategy,复合分片策略,提供对 SQL 语句中的 =, >, <, >=, <=, IN和BETWEEN AND 的分片操作支持。

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

Hint分片策略

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

不分片策略

对应 NoneShardingStrategy。不分片的策略。

SQL Hint

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

实现动机

  • 通过解析 SQL 语句提取分片键列与值并进行分片是 Apache ShardingSphere 对 SQL 零侵入的实现方式。若 SQL 语句中没有分片条件,则无法进行分片,需要全路由。

  • 在一些应用场景中,分片条件并不存在于 SQL,而存在于外部业务逻辑。因此需要提供一种通过外部指定分片结果的方式,在 Apache ShardingSphere 中叫做 Hint。

实现机制

  • Apache ShardingSphere 使用 ThreadLocal 管理分片键值。可以通过编程的方式向 HintManager 中添加分片条件,该分片条件仅在当前线程内生效。

  • 除了通过编程的方式使用强制分片路由,Apache ShardingSphere 还计划通过 SQL 中的特殊注释的方式引用 Hint,使开发者可以采用更加透明的方式使用该功能。

  • 指定了强制分片路由的 SQL 将会无视原有的分片逻辑,直接路由至指定的真实数据节点。

分片规则

分片规则配置的总入口。包含数据源配置、表配置、绑定表配置以及读写分离配置等。

数据源配置

系统配置的相关的数据源信息列表。

表配置

  • 逻辑表名称、数据节点与分表规则的配置。

数据节点配置

  • 用于配置逻辑表与真实表的映射关系。可分为均匀分布和自定义分布两种形式。

均匀分布

  • 指数据表在每个数据源内呈现均匀分布的态势,例如:
db0
  ├── userInfo_0 
  └── userInfo_1 
db1
  ├── userInfo_0 
  └── userInfo_1
  • 那么数据节点的配置如下:
db0.userInfo_0, db0.userInfo_1, db1.userInfo_0, db1.userInfo_1

自定义分布

指数据表呈现有特定规则的分布,例如:

db0
  ├── userInfo_0 
  └── userInfo_1 
db1
  ├── userInfo_3
  └── userInfo_4

那么数据节点的配置如下:

db0.userInfo_0, db0.userInfo_1, db1.userInfo_3, db1.userInfo_4
数据源分片策略

对应于DatabaseShardingStrategy。用于配置数据被分配的目标数据源。

表分片策略

对应于TableShardingStrategy。用于配置数据被分配的目标表,该目标表存在于该数据的目标数据源内。故表分片策略是依赖于数据源分片策略的结果的。

两种策略的 API 完全相同。

自增主键生成策略

通过在客户端生成自增主键替换以数据库原生自增主键的方式,做到分布式主键无重复。

分片计算表达式

实现动机

配置的简化与一体化是行表达式所希望解决的两个主要问题。

  • 在繁琐的数据分片规则配置中,随着数据节点的增多,大量的重复配置使得配置本身不易被维护。通过行表达式可以有效地简化数据节点配置工作量。

  • 对于常见的分片算法,使用 Java 代码实现并不有助于配置的统一管理。通过行表达式书写分片算法,可以有效地将规则配置一同存放,更加易于浏览与存储。

语法说明

目前支持数据节点和分片算法这两个部分的配置。

行表达式的内容使用的是 Groovy 的语法,Groovy 能够支持的所有操作,行表达式均能够支持。只需要在配置中使用 { expression } 或->{ expression } 标识行表达式即可。例如:

${begin..end} 表示范围区间

${[unit1, unit2, unit_x]} 表示枚举值

行表达式中如果出现连续多个{ expression } 或->{ expression } 表达式,整个表达式最终的结果将会根据每个子表达式的结果进行笛卡尔组合。

行表达式案例
${['a', 'b']}_table${1..3}

最终会解析为:

a_table1, a_table2, a_table3, b_table1, b_table2, b_table3
配置数据节点

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

db0
  ├── userInfo_0 
  └── userInfo_1 
db1
  ├── userInfo_3
  └── userInfo_4
db0.userinfo_${0..1},db1.userinfo_${0..1}

用行表达式可以简化为:

db${0..1}.userinfo_${0..1}
  • 或者
db$->{0..1}.userinfo_$->{0..1}

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

db0
  ├── userInfo_0 
  └── userInfo_1 
db1
  ├── userInfo_0
  └── userInfo_1

可以使用分开配置的方式,先配置包含前缀的数据节点,再配置不含前缀的数据节点,再利用行表达式笛卡尔积的特性,自动组合即可。 上面的示例,用行表达式可以简化为:

db${0..1}.t_order_0${0..9}, db${0..1}.t_order_${10..20}
或者
db$->{0..1}.t_order_0$->{0..9}, db$->{0..1}.t_order_$->{10..20}

配置分片算法

  • 对于只有一个分片键的使用 = 和 IN 进行分片的 SQL,可以使用行表达式代替编码方式配置。

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

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

ds${id % 10}

或者

ds$->{id % 10}
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 205,236评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 87,867评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 151,715评论 0 340
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,899评论 1 278
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,895评论 5 368
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,733评论 1 283
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,085评论 3 399
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,722评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 43,025评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,696评论 2 323
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,816评论 1 333
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,447评论 4 322
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,057评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,009评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,254评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,204评论 2 352
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,561评论 2 343

推荐阅读更多精彩内容