ShardingJDBC

ShardingJDBC是用来做客户端分库分表的产品,而ShardingProxy是用来做服务端分库分表的产品。
shardingjdbc的核心功能是数据分片和读写分离,通过ShardingJDBC,应用可以透明的使用JDBC访问已经分库分表、读写分离的多个数据源,而不用关心数据源的数量以及数据如何分布。

核心概念

  • 逻辑表:水平拆分的数据库的相同逻辑和数据结构表的总称
  • 真实表:在分片的数据库中真实存在的物理表。
  • 数据节点:数据分片的最小单元。由数据源名称和数据表组成
  • 绑定表:分片规则一致的主表和子表。
  • 广播表:也叫公共表,指素有的分片数据源中都存在的表,表结构和表中的数据在每个数据库中都完全一致。例如字典表。
  • 分片键:用于分片的数据库字段,是将数据库(表)进行水平拆分的关键字段。SQL中若没有分片字段,将会执行全路由,性能会很差。
  • 分片算法:通过分片算法将数据进行分片,支持通过=、BETWEEN和IN分片。分片算法需要由应用开发者自行实现,可实现的灵活度非常高。
  • 分片策略:真正用于进行分片操作的是分片键+分片算法,也就是分片策略。在ShardingJDBC中一般采用基于Groovy表达式的inline分片策略,通过一个包含分片键的算法表达式来制定分片策略,如t_user_$->{u_id%8}标识根据u_id模8,分成8张表,表名称为t_user_0到t_user_7。

ShardingJDBC的分片算法


ShardingJDBC的整个实战完成后,可以看到,整个分库分表的核心就是在于配置的分片算法。我们的这些实战都是使用的inline分片算法,即提供一个分片键和一个分片表达式来制定分片算法。这种方式配置简单,功能灵活,是分库分表最佳的配置方式,并且对于绝大多数的分库分片场景来说,都已经非常好用了。但是,如果针对一些更为复杂的分片策略,例如多分片键、按范围分片等场景,inline分片算法就有点力不从心了。所以,我们还需要学习下ShardingSphere提供的其他几种分片策略。


ShardingSphere目前提供了一共五种分片策略:

  • NoneShardingStrategy
    不分片。这种严格来说不算是一种分片策略了。只是ShardingSphere也提供了这么一个配置。
  • InlineShardingStrategy

最常用的分片方式

  • 配置参数: inline.shardingColumn 分片键;inline.algorithmExpression 分片表达式
  • 实现方式: 按照分片表达式来进行分片。
  • StandardShardingStrategy

只支持单分片键的标准分片策略

  • 配置参数:standard.sharding-column 分片键;standard.precise-algorithm-class-name 精确分片算法类名;standard.range-algorithm-class-name 范围分片算法类名
  • 实现方式:

shardingColumn指定分片算法。

  • preciseAlgorithmClassName 指向一个实现了io.shardingsphere.api.algorithm.sharding.standard.PreciseShardingAlgorithm接口的java类名,提供按照 = 或者 IN 逻辑的精确分片 示例:com.roy.shardingDemo.algorithm.MyPreciseShardingAlgorithm
  • rangeAlgorithmClassName 指向一个实现了 io.shardingsphere.api.algorithm.sharding.standard.RangeShardingAlgorithm接口的java类名,提供按照Between 条件进行的范围分片。示例:com.roy.shardingDemo.algorithm.MyRangeShardingAlgorithm
  • 说明:其中精确分片算法是必须提供的,而范围分片算法则是可选的。
  • ComplexShardingStrategy

支持多分片键的复杂分片策略。

  • 配置参数:complex.sharding-columns 分片键(多个); complex.algorithm-class-name 分片算法实现类。
  • 实现方式:

shardingColumn指定多个分片列

  • algorithmClassName指向一个实现了org.apache.shardingsphere.api.sharding.complex.ComplexKeysShardingAlgorithm接口的java类名。提供按照多个分片列进行综合分片的算法。示例:com.roy.shardingDemo.algorithm.MyComplexKeysShardingAlgorithm
  • HintShardingStrategy
    不需要分片键的强制分片策略。这个分片策略,简单来理解就是说,他的分片键不再跟SQL语句相关联,而是用程序另行指定。对于一些复杂的情况,例如select count(*) from (select userid from t_user where userid in (1,3,5,7,9)) 这样的SQL语句,就没法通过SQL语句来指定一个分片键。这个时候就可以通过程序,给他另行执行一个分片键,例如在按userid奇偶分片的策略下,可以指定1作为分片键,然后自行指定他的分片策略。
  • 配置参数:hint.algorithm-class-name 分片算法实现类。
  • 实现方式:

algorithmClassName指向一个实现了org.apache.shardingsphere.api.sharding.hint.HintShardingAlgorithm接口的java类名。 示例:com.roy.shardingDemo.algorithm.MyHintShardingAlgorithm。 在这个算法类中,同样是需要分片键的。而分片键的指定是通过HintManager.addDatabaseShardingValue方法(分库)和HintManager.addTableShardingValue(分表)来指定。 使用时要注意,这个分片键是线程隔离的,只在当前线程有效,所以通常建议使用之后立即关闭,或者用try资源方式打开。


而Hint分片策略并没有完全按照SQL解析树来构建分片策略,是绕开了SQL解析的,所有对某些比较复杂的语句,Hint分片策略性能有可能会比较好(情况太多了,无法一一分析)。
但是要注意,Hint强制路由在使用时有非常多的限制:


-- 不支持UNION
    SELECT * FROM t_order1 UNION SELECT * FROM t_order2 INSERT INTO tbl_name (col1, col2, …) SELECT col1, col2, … FROM tbl_name WHERE col3 = ?

    -- 不支持多层子查询
    SELECT COUNT(*) FROM (SELECT * FROM t_order o WHERE o.id IN (SELECT id FROM t_order WHERE status = ?))

    -- 不支持函数计算。ShardingSphere只能通过SQL字面提取用于分片的值
    SELECT * FROM t_order WHERE to_date(create_time, 'yyyy-mm-dd') = '2019-01-01';


从这里也能看出,即便有了ShardingSphere框架,分库分表后对于SQL语句的支持依然是非常脆弱的。