sharding-jdbc常用的分片场景策略:
取余/取模分片:优点-均匀存放数据,缺点-扩容非常困难
按照范围分片:比较好扩容,数据分布不均匀,可能造成资源浪费
按照时间分片:比较容易将热点数据区分出来
按照枚举值分片:例如按照地区分片
按照目标字段前缀指定进行分区:自定义规则
sharding-jdbc核心概念:
sql
逻辑表:水平拆分的数据库(表)的相同逻辑和数据结构表的总称。例:订单数据根据主键尾数拆分为 10 张表,分别是
t_order_0
到t_order_9
,他们的逻辑表名为t_order
。真实表:在分片的数据库中真实存在的物理表。即上个逻辑表的例子中的
t_order_0
到t_order_9
。数据节点:数据分片的最小单元。由数据源名称和数据表组成,例:
ds_0.t_order_0
。绑定表:指分片规则一致的主表和子表。例如:
t_order
表和t_order_item
表,均按照order_id
分片,则此两张表互为绑定表关系。绑定表之间的多表关联查询不会出现笛卡尔积关联,关联查询效率将大大提升。举例说明,如果 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_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
的条件。故绑定表之间的分区键要完全相同。广播表:指所有的分片数据源中都存在的表,表结构和表中的数据在每个数据库中均完全一致。适用于数据量不大且需要与海量数据的表进行关联查询的场景,例如:字典表。
分片
分⽚键 : ⽤于分⽚的数据库字段,是将数据库(表)⽔平拆分的关键字段。例:将订单表中的订单主键的尾数取模分⽚,则订单主键为分⽚字段。SQL 中如果⽆分⽚字段,将执⾏全路由,性能较差。除了对单分⽚字段的⽀持, Apache ShardingSphere 也⽀持根据多个字段进⾏分⽚。分⽚算法 : 通过分⽚算法将数据分⽚,⽀持通过 = 、 >= 、 <= 、 > 、 < 、 BETWEEN 和 IN 分⽚。分⽚算法需要应⽤⽅开发者⾃⾏实现,可实现的灵活度⾮常⾼。⽬前提供 4 种分⽚算法。由于分⽚算法和业务实现紧密相关,因此并未提供内置分⽚算法,而是通过分⽚策略将各种场景提炼出来,提供更⾼层级的抽象,并提供接口让应⽤开发者⾃⾏实现分⽚算法。• 标准分⽚算法 :对应 StandardShardingAlgorithm,⽤于处理使⽤单⼀键作为分⽚键的 =、IN、BETWEEN AND、>、<、>=、 <= 进⾏分⽚的场景。需要配合 StandardShardingStrategy 使⽤。
• 复合分⽚算法 :对应 ComplexKeysShardingAlgorithm,⽤于处理使⽤多键作为分⽚键进⾏分⽚的场景,包含多个分⽚键的逻辑较复杂,需要应⽤开发者⾃⾏处理其中的复杂度。需要配合 ComplexShardingStrategy 使⽤。
• Hint 分⽚算法 :对应 HintShardingAlgorithm,⽤于处理使⽤ Hint ⾏分⽚的场景。需要配合 HintShardingStrategy 使⽤。
分⽚策略: 包含分⽚键和分⽚算法,由于分⽚算法的独⽴性,将其独⽴抽离。真正可⽤于分⽚操作的是分⽚键 + 分 ⽚算法,也就是分⽚策略。⽬前提供 5 种分⽚策略。• 标准分⽚策略 :对应 StandardShardingStrategy。提供对 SQ L 语句中的 =, >, <, >=, <=, 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。不分⽚的策略。
配置
分⽚规则 :分⽚规则配置的总⼊口。包含数据源配置、表配置、绑定表配置以及读写分离配置等。
数据源配置 :真实数据源列表。
表配置 : 逻辑表名称、数据节点与分表规则的配置。数据节点配置:⽤于配置逻辑表与真实表的映射关系。可分为均匀分布和⾃定义分布两种形式。
- 均匀分布
指数据表在每个数据源内呈现均匀分布的态势,例如:db0├── t_order0└── t_order1db1├── t_order0└── t_order1那么数据节点的配置如下: db0.t_order0, db0.t_order1, db1.t_order0, db1.t_order1
- ⾃定义分布
指数据表呈现有特定规则的分布,例如:db0├── t_order0└── t_order1db1└── t_order2那么数据节点的配置如下:db0.t_order0, db0.t_order1, db1.t_order2分⽚策略配置:对于分⽚策略存有数据源分⽚策略和表分⽚策略两种维度。两种策略的 API 完全相同。
- 数据源分片策略:对应于 DatabaseShardingStrategy。⽤于配置数据被分配的⽬标数据源。
- 表分片策略:对应于 TableShardingStrategy。⽤于配置数据被分配的⽬标表,该⽬标表存在于该数据的⽬标数据源内。 故表分⽚策略是依赖于数据源分⽚策略的结果的。
⾃增主键⽣成策略:通过在客⼾端⽣成⾃增主键替换以数据库原⽣⾃增主键的⽅式,做到分布式主键⽆重复
行表达式
实现动机:
配置的简化与⼀体化是⾏表达式所希望解决的两个主要问题。在繁琐的数据分⽚规则配置中,随着数据节点的增多,⼤量的重复配置使得配置本⾝不易被维护。通过⾏表达式可以有效地简化数据节点配置⼯作量。对于常⻅的分⽚算法,使⽤ Java 代码实现并不有助于配置的统⼀管理。通过⾏表达式书写分⽚算法,可以有效地将规则配置⼀同存放,更加易于浏览与存储。语法说明⾏表达式的使⽤⾮常直观,只需要在配置中使⽤ ${ expression } 或 $->{ expression } 标识⾏表达式即可。⽬前⽀持数据节点和分⽚算法这两个部分的配置。⾏表达式的内容使⽤的是 Groovy 的语法,Groovy 能够⽀持的所有操作,⾏表达式均能够⽀持。例如:${begin..end} 表⽰范围区间${[unit1, unit2, unit_x]} 表⽰枚举值⾏表达式中如果出现连续多个 ${ expression } 或 $->{ expression } 表达式,整个表达式最终的结果将会根据每个⼦表达式的结果进⾏笛卡尔组合。例如,以下⾏表达式:${['online','offline']}_table${1..3}最终会解析为:online_table1,online_table2,online_table3,offline_table1,offline_table2,offline_table3配置数据节点对于均匀分布的数据节点,如果数据结构如下:
对于⾃定义的数据节点,如果数据结构如下:
配置分⽚算法对于只有⼀个分⽚键的使⽤=和IN进⾏分⽚的SQL,可以使⽤⾏表达式代替编码⽅式配置。
⾏表达式内部的表达式本质上是⼀段Groovy代码,可以根据分⽚键进⾏计算的⽅式,返回相应的真实数据源或真实表名称。
例如:分为10个库,尾数为0的路由到后缀为0的数据源,尾数为1的路由到后缀为1的数据源,以此类推。⽤于表⽰分⽚算法的⾏表达式为:
分布式主键
实现动机
传统数据库软件开发中,主键⾃动⽣成技术是基本需求。而各个数据库对于该需求也提供了相应的⽀持,
⽐如 MySQL 的⾃增键, Oracle 的⾃增序列等。数据分⽚后,不同数据节点⽣成全局唯⼀主键是⾮常棘⼿的问题。同⼀个逻辑表内的不同实际表之间的⾃增键由于⽆法互相感知而产⽣重复主键。虽然可通过约束⾃增主键初始值和步⻓的⽅式避免碰撞,但需引⼊额外的运维规则,使解决⽅案缺乏完整性和可扩展性。⽬前有许多第三⽅解决⽅案可以完美解决这个问题,如 UUID 等依靠特定算法⾃⽣成不重复键,或者通过引⼊主键⽣成服务等。为了⽅便⽤⼾使⽤、满⾜不同⽤⼾不同使⽤场景的需求, Apache ShardingSphere不仅提供了内置的分布式主键⽣成器,例如 UUID 、 SNOWFLAKE ,还抽离出分布式主键⽣成器的接口,⽅便⽤⼾⾃⾏实现⾃定义的⾃增主键⽣成器。内置的主键⽣成器
UUID采⽤UUID.randomUUID()的⽅式产⽣分布式主键。SNOWFLAKE在分⽚规则配置模块可配置每个表的主键⽣成策略,默认使⽤雪花算法(snowfake)⽣成64bit的⻓整型数据。
雪花算法是由Twitter公布的分布式主键⽣成算法,它能够保证不同进程主键的不重复性,以及相同进程主键的有序性。
强制分片路由
实现动机
通过解析SQL语句提取分⽚键列与值并进⾏分⽚是ApacheShardingSphere对SQL零侵⼊的实现⽅式。若SQL语句中没有分⽚条件,则⽆法进⾏分⽚,需要全路由。
在⼀些应⽤场景中,分⽚条件并不存在于SQL,而存在于外部业务逻辑。因此需要提供⼀种通过外部指定分⽚结果的⽅式,在ApacheShardingSphere中叫做Hint。实现机制
ApacheShardingSphere使⽤ThreadLocal管理分⽚键值。可以通过编程的⽅式向HintManager中添加分⽚条件,该分⽚条件仅在当前线程内⽣效。
除了通过编程的⽅式使⽤强制分⽚路由,ApacheShardingSphere还计划通过SQL中的特殊注释的⽅式引⽤Hint,使开发者可以采⽤更加透明的⽅式使⽤该功能。
指定了强制分⽚路由的SQL将会⽆视原有的分⽚逻辑,直接路由⾄指定的真实数据节点。