MySQL 分库分表必修课:ShardingSphere 基础

316 阅读8分钟

引言

在 MySQL 分库分表理论基础中,分库分表的不同粒度充分还原了不同的应用场景,并预演了不同粒度下所带来的问题的解决方案。接着引出了分库后如何访问数据库的问题,在代理层,所有使用数据库的业务服务都连接代理中间件,由中间件来决定落库位置,如 MyCat、Sharding-Sphere 实现;而在驱动层,在 JDBC 驱动层拦截 SQL 语句,然后改写 SQL 实现,如 Sharding-JDBC 框架的原理就是如此。

ShardingSphere 介绍

Apache ShardingSphere 是一款分布式 SQL 事务和查询引擎,可通过数据分片、弹性伸缩、加密等能力对任意数据库进行增强。

ShardingSphere 目前包括两大产品:ShardingSphere-JDBC 和 ShardingSphere-Proxy。

ShardingSphere-JDBC

ShardingSphere-JDBC 定位为轻量级 Java 框架,在 Java 的 JDBC 层提供的额外服务。

它会以POM依赖的形式嵌入程序,运行期间会和 Java 应用共享资源,这款框架的本质可以理解成是JDBC的增强版,只不过 Java 原生的 JDBC 仅支持单数据源的连接。

ORM框架在执行 SQL 语句时,Sharding-JDBC 会以切面的形式拦截发往数据库的语句,接着根据配置好的数据源、分片规则和路由键,为 SQL 选择一个目标数据源,然后再发往对应的数据库节点处理。

ShardingSphere-Proxy

ShardingSphere-Proxy 定位为透明化的数据库代理端,通过实现数据库二进制协议,对异构语言提供支持。

Sharding-JDBC 在整个业务系统中对性能损耗极低,但由于 Sharding-JDBC 配置较为麻烦,比如在分布式系统中,任何使用分库分表的服务都需要单独配置多数据源地址、路由键、分片策略等等信息,同时它也仅支持 Java 语言,当一个系统是用多语言异构的,此时其他语言开发的子服务,则无法使用分库分表策略。

Sharding-Proxy 可以将其理解成一个伪数据库,对于应用程序而言是完全透明的,它会以中间件的形式独立部署在系统中。

使用 Sharding-Proxy 的子服务都会以连接数据库的形式,与其先建立数据库连接,然后将 SQL 发给它执行,Sharding-Proxy 会根据分片规则和路由键,将 SQL 语句发给具体的数据库节点处理,数据库节点处理完成后,又会将结果集返回给 Sharding-Proxy,最终再由它将结果集返回给具体的子服务。因此相较于原本的 Sharding-JDBC 来说,Sharding-Proxy 性能、资源开销更大,响应速度也会变慢。

ShardingSphere 核心概念

分片

  • 分片键:用于将数据库(表)水平拆分的数据库字段。 例:将订单表中的订单主键的尾数取模分片,则订单主键为分片字段。 SQL 中如果无分片字段,将执行全路由,性能较差。 除了对单分片字段的支持,Apache ShardingSphere 也支持根据多个字段进行分片。
  • 分片算法:用于将数据分片的算法,支持 =>=<=><BETWEENIN 进行分片。 分片算法可由开发者自行实现,也可使用 Apache ShardingSphere 内置的分片算法语法糖,灵活度非常高。
  • 自动化分片算法:分片算法语法糖,用于便捷的托管所有数据节点,使用者无需关注真实表的物理分布。 包括取模、哈希、范围、时间等常用分片算法的实现。
  • 自定义分片算法:提供接口让应用开发者自行实现与业务实现紧密相关的分片算法,并允许使用者自行管理真实表的物理分布。 自定义分片算法又分为:
    • 标准分片算法:用于处理使用单一键作为分片键的=INBETWEEN AND><>=<=进行分片的场景。
    • 复合分片算法:用于处理使用多键作为分片键进行分片的场景,包含多个分片键的逻辑较复杂,需要应用开发者自行处理其中的复杂度。
    • Hint 分片算法:用于处理使用 Hint 行分片的场景。对于分片字段并非由 SQL 而是其他外置条件决定的场景,可使用 SQL Hint 注入分片值。 例:按照员工登录主键分库,而数据库中并无此字段。 SQL Hint 支持通过 Java API 和 SQL 注释两种方式使用。 详情请参见强制分片路由。

逻辑表&真实表

  • 逻辑表:相同结构的水平拆分数据库(表)的逻辑名称,是 SQL 中表的逻辑标识。 例:订单数据根据主键尾数拆分为 10 张表,分别是 t_order_0t_order_9,他们的逻辑表名为 t_order
  • 真实表:在水平拆分的数据库中真实存在的物理表。 即上个示例中的 t_order_0t_order_9

数据节点

数据分片的最小单元,由数据源名称和真实表组成。 例:ds_0.t_order_0。 逻辑表与真实表的映射关系,可分为均匀分布和自定义分布两种形式。

  • 均匀分布:指数据表在每个数据源内呈现均匀分布的态势, 例如:
数据节点的配置为:db0.t_order0, db0.t_order1, db1.t_order0, db1.t_order1

db0
  ├── t_order0
  └── t_order1
db1
  ├── t_order0
  └── t_order1
  • 自定义分布:指数据表呈现有特定规则的分布, 例如:
数据节点的配置为:db0.t_order0, db0.t_order1, db1.t_order2, db1.t_order3, db1.t_order4

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

分库分表工作流程

以一个分库分表的工作流程示例图了解上述概念是如何应用的。

假定有一张逻辑表t_order,以order_id作为分片键,并以Key % DBCount分片算法将数据分发到三个数据库db_0db_1db_2,并自定义数据节点分布为db_0.order_01db_1.order_01db_1.order_02db_2.order_01

画板

绑定表&广播表&单表&动态表

  • 绑定表:指分片规则一致的一组分片表。 使用绑定表进行多表关联查询时,必须使用分片键进行关联,否则会出现笛卡尔积关联或跨库关联,从而影响查询效率。假定有 t_order 表和 t_order_item 表,它们之间以 t_order.idt_order_item.order_id 作为逻辑上的主外键关系。其中 t_order 表由于指定了分片条件,ShardingSphere 将会以它作为整个绑定表的主表。 所有路由计算将会只使用主表的策略,那么 t_order_item 表的分片计算将会使用 t_order 的条件。其配置如下:
rules:
- !SHARDING
  tables:
    t_order:
      actualDataNodes: ds_${0..1}.t_order_${0..1}
    t_order_item:
      actualDataNodes: ds_${0..1}.t_order_item_${0..1}
  • 广播表:指所有的数据源中都存在的表,表结构及其数据在每个数据库中均完全一致。 适用于数据量不大且需要与海量数据的表进行关联查询的场景,例如:字典表。
  • 单表:指所有的分片数据源中仅唯一存在的表。 适用于数据量不大且无需分片的表。也就是说不需要分库分表的数据表无需分片,这样所有的读写操作最终都会落入这一张单表中处理。
  • 动态表:动态表的概念在 ShardingSphere 最新的 5.x 文档中已经移除了,但也可以基于分片算法去实现,所以虽然移除了动态表的概念,但也可以实现相同的效果,动态表的概念是指表会随着数据增长、或随着时间推移,不断的去创建新表,如下:
数据节点的配置为:db0.t_order202301, db0.t_order202302, db1.t_order202303...

db0
  └── t_order202301
db1
  └── t_order202302
db2
  └── t_order202303

行表达式

行表达式是为了解决配置的简化与一体化这两个主要问题。在繁琐的数据分片规则配置中,随着数据节点的增多,大量的重复配置使得配置本身不易被维护。 通过行表达式可以有效地简化数据节点配置工作量。

行表达式的使用非常直观,只需要在配置中使用${ expression }$->{ expression }标识行表达式即可。 目前支持数据节点和分片算法这两个部分的配置。行表达式的内容使用的是Groovy的语法,Groovy能够支持的所有操作,行表达式均能够支持。 例如:${begin..end}表示范围区间,${[unit1, unit2, unit_x]}表示枚举值。在Spring Boot中因为属性配置会使用${},为与之区分建议使用$->{ expression }

例如,以下行表达式:

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

最终解析为:

online_table1, online_table2, online_table3, offline_table1, offline_table2, offline_table3

总结

ShardingSphere 作为 MySQL 分库分表的解决方案,是目前主流的方式之一。学习 ShardingSphere 的原理及核心概念有助于理解实际开发的业务编码,这是前往实战的必修课之一。之后我们将基于 Spring Boot 应用 ShardingSphere,完成实际开发中的分库分表。