谈到分库分表中间件时,咱们自然而然的会想到 ShardingSphere-JDBC 。

这篇文章,咱们聊聊 ShardingSphere-JDBC 相关知识点,并实战演示一番。

看完这一篇,ShardingSphere-jdbc 实战再也不怕了

1 ShardingSphere 生态

Apache ShardingSphere 是一款分布式的数据库生态系统,它包括两大产品:

  • ShardingSphere-Proxy
  • ShardingSphere-JDBC

▍一、ShardingSphere-Proxy

ShardingSphere-Proxy 被定位为透明化的数据库署理端,供给封装了数据库二进制协议的服务端版别,用于完成对异构言语的支撑。

看完这一篇,ShardingSphere-jdbc 实战再也不怕了

署理层介于运用程序与数据库间,每次恳求都需求做一次转发,恳求会存在额定的时延。

这种方法关于运用十分友好,运用基本零改动,和言语无关,能够经过衔接同享削减衔接数耗费。

▍二、ShardingSphere-JDBC

ShardingSphere-JDBC 是 ShardingSphere 的第一个产品,也是 ShardingSphere 的前身, 咱们常常简称之为:sharding-jdbc 。

它定位为轻量级 Java 结构,在 Java 的 JDBC 层供给的额定服务。它运用客户端直连数据库,以 jar 包形式供给服务,无需额定布置和依靠,可了解为增强版的 JDBC 驱动,完全兼容 JDBC 和各种 ORM 结构。

看完这一篇,ShardingSphere-jdbc 实战再也不怕了


当咱们在 Proxy 和 JDBC 两种形式挑选时,能够参阅下表对照:

JDBC Proxy
数据库 恣意 MySQL/PostgreSQL
衔接耗费数
异构言语 仅Java 恣意
性能 损耗低 损耗略高
无中心化
静态进口

越来越多的公司都在出产环境运用了 sharding-jdbc ,最中心的原因便是:简略(原理简略,易于完成,便利运维)。

2 基本原理

在后端开发中,JDBC 编程是最基本的操作。不论 ORM 结构是 Mybatis 仍是 Hibernate ,亦或是 spring-jpa ,他们的底层完成是 JDBC 的模型。

看完这一篇,ShardingSphere-jdbc 实战再也不怕了

sharding-jdbc 的实质上便是完成 JDBC 的中心接口。

看完这一篇,ShardingSphere-jdbc 实战再也不怕了

接口 完成类
DataSource ShardingDataSource
Connection ShardingConnection
Statement ShardingStatement
PreparedStatement ShardingPreparedStatement
ResultSet ShardingResultSet

虽然咱们了解了 sharding-jdbc 的实质,可是真正完成起来还有十分多的细节,下图展现了 Prxoy 和 JDBC 两种形式的中心流程。

看完这一篇,ShardingSphere-jdbc 实战再也不怕了

1.SQL 解析

分为词法解析和语法解析。 先经过词法解析器将 SQL 拆分为一个个不可再分的单词。再运用语法解析器对 SQL 进行了解,并终究提炼出解析上下文。

解析上下文包括表、挑选项、排序项、分组项、聚合函数、分页信息、查询条件以及或许需求修正的占位符的标记。

2.履行器优化

兼并和优化分片条件,如 OR 等。

3.SQL 路由

依据解析上下文匹配用户装备的分片战略,并生成路由路径。目前支撑分片路由和广播路由。

4.SQL 改写

将 SQL 改写为在实在数据库中能够正确履行的句子。SQL 改写分为正确性改写和优化改写。

5.SQL 履行

经过多线程履行器异步履行。

6.成果归并

将多个履行成果集归并以便于经过统一的 JDBC 接口输出。成果归并包括流式归并内存归并和运用装饰者形式的追加归并这几种方法。

本文的重点在于实战层面, sharding-jdbc 的完成原理细节咱们会在后续的文章逐个给咱们出现 。

3 实战案例

笔者从前为武汉一家 O2O 公司订单服务做过分库分表架构设计 ,当企业用户创建一条采购订单 , 会生成如下记载:

  • 订单根底表t_ent_order :单条记载
  • 订单概况表t_ent_order_detail :单条记载
  • 订单明细表t_ent_order_item:N 条记载

订单数据选用了如下的分库分表战略:

  • 订单根底表依照 ent_id (企业用户编号) 分库 ,订单概况表保持共同;
  • 订单明细表依照 ent_id (企业用户编号) 分库,同时也要依照 ent_id (企业编号) 分表。

首要创建 4 个库,分别是:ds_0、ds_1、ds_2、ds_3 。

这四个分库,每个分库都包括 订单根底表 , 订单概况表 ,订单明细表 。可是由于明细表需求分表,所以包括多张表。

看完这一篇,ShardingSphere-jdbc 实战再也不怕了

然后 springboot 项目中装备依靠 :

1
<dependency>
2
  <groupId>org.apache.shardingsphere</groupId>
3
  <artifactId>sharding-jdbc-spring-boot-starter</artifactId>
4
  <version>4.1.1</version>
5
</dependency>

装备文件中装备如下:

看完这一篇,ShardingSphere-jdbc 实战再也不怕了

  • 装备数据源,上面装备数据源是: ds0、ds1、ds2、ds3 ;
  • 装备打印日志,也便是:sql.show ,在测试环境建议打开 ,便于调试;
  • 装备哪些表需求分库分表 ,在 shardingsphere.datasource.sharding.tables 节点下面装备:

看完这一篇,ShardingSphere-jdbc 实战再也不怕了

上图中咱们看到装备分片规矩包括如下两点:

1.实在节点

关于咱们的运用来讲,咱们查询的逻辑表是:t_ent_order_item 。

它们在数据库中的实在形状是:t_ent_order_item_0t_ent_order_item_7

实在数据节点是指数据分片的最小单元,由数据源称号和数据表组成。

订单明细表的实在节点是:ds$->{0..3}.t_ent_order_item_$->{0..7}

2.分库分表算法

装备分库战略和分表战略 , 每种战略都需求装备分片字段( sharding-columns )和分片算法

4 基因法 & 自定义复合分片算法

分片算法和阿里开源的数据库中间件 cobar 路由算法十分相似的。

假定现在需求将订单表均匀拆分到4个分库 shard0 ,shard1 ,shard2 ,shard3 。

首要将 [0-1023] 均匀分为4个区段:[0-255],[256-511],[512-767],[768-1023],然后对字符串(或子串,由用户自定义)做 hash, hash 成果对 1024 取模,终究得出的成果 slot 落入哪个区段,便路由到哪个分库。

看完这一篇,ShardingSphere-jdbc 实战再也不怕了

看起来分片算法很简略,但咱们需求依照订单 ID 查询订单信息时依然需求路由四个分片,功率不高,那么怎么优化呢 ?

答案是:基因法 & 自定义复合分片算法

基因法是指在订单 ID 中带着企业用户编号信息,咱们能够在创建订单 order_id时运用雪花算法,然后将 slot 的值保存在 10位作业机器 ID 里。

看完这一篇,ShardingSphere-jdbc 实战再也不怕了

经过订单 order_id 能够反查出 slot , 就能够定位该用户的订单数据存储在哪个分片里。

1
Integer getWorkerId(Long orderId) {
2
 Long workerId = (orderId >> 12) & 0x03ff;
3
 return workerId.intValue();
4
}

下图展现了订单 ID 运用雪花算法的生成过程,生成的编号会带着企业用户 ID 信息。

看完这一篇,ShardingSphere-jdbc 实战再也不怕了

解决了分布式 ID 问题,接下来的一个问题:sharding-jdbc 可否支撑依照订单 ID ,企业用户 ID 两个字段来决定分片路由吗?

答案是:自定义复合分片算法。咱们只需求完成 ComplexKeysShardingAlgorithm 类即可。

看完这一篇,ShardingSphere-jdbc 实战再也不怕了

复合分片的算法流程十分简略:

1.分片键中有主键值,则直接经过主键解析出路由分片;

2.分片键中不存在主键值 ,则依照其他分片字段值解析出路由分片。

5 扩容计划

已然做了分库分表,怎么完成滑润扩容也是一个十分风趣的论题。

在数据同步之前,需求整理搬迁规模。

1.事务仅有主键

在进行数据同步前,需求先整理所有表的仅有事务 ID,只有确认了仅有事务 ID 才干完成数据的同步操作。

需求注意的是:事务中是否有运用数据库自增 ID 做为事务 ID 运用的,假如有需求事务先进行改造 。别的保证每个表是否都有仅有索引,一旦表中没有仅有索引,就会在数据同步过程中形成数据重复的风险,所以咱们先将没有仅有索引的表依据事务场景增加仅有索引(有或许是联合仅有索引)。

2.搬迁哪些表,搬迁后的分库分表规矩

分表规矩不同决定着 rehash 和数据校验的不同。需逐个表整理是用户ID纬度分表仍是非用户ID纬度分表、是否只分库不分表、是否不分库不分表等等。

接下来,进入数据同步环节

整体计划见下图,数据同步基于 binlog ,独立的中间服务做同步,对事务代码无侵入。

看完这一篇,ShardingSphere-jdbc 实战再也不怕了

首要需求做前史数据全量同步:也便是将旧库搬迁到新库。

独自一个服务,运用游标的方法从旧库分片 select 句子,经过 rehash 后批量刺进 (batch insert)到新库,需求装备jdbc 衔接串参数 rewriteBatchedStatements=true 才干使批处理操作收效。

由于前史数据也会存在不断的更新,假如先敞开前史数据全量同步,则刚同步完成的数据有或许不是最新的。

所以咱们会先敞开增量数据单向同步(从旧库到新库),此时只是敞开积压 kafka 音讯并不会真正消费;然后在开始前史数据全量同步,当前史全量数据同步完成后,在敞开消费 kafka 音讯进行增量数据同步(进步全量同步功率削减积压也是关键的一环),这样来保证搬迁数据过程中的数据共同。

增量数据同步考虑到灰度切流安稳性、容灾 和可回滚才能 ,选用实时双向同步计划,切流过程中一旦新库出现安稳性问题或者新库出现数据共同问题,可快速回滚切回旧库,保证数据库的安稳和数据牢靠。

增量数据实时同步的大体思路 :

1.过滤循环音讯

需求过滤掉循环同步的 binlog 音讯 ;

2.数据兼并

同一条记载的多条操作只保存终究一条。为了进步性能,数据同步组件接到 kafka 音讯后不会立刻进行数据流转,而是先存到本地堵塞行列,然后由本地定时任务每X秒将本地行列中的N条数据进行数据流转操作。此时N条数据有或许是对同一张表同一条记载的操作,所以此处只需求保存终究一条(相似于 redis aof 重写);

3.update 转 insert

数据兼并时,假如数据中有 insert + update 只保存终究一条 update ,会履行失利,所以此处需求将 update 转为 insert 句子 ;

4.按新表兼并

将终究要提交的 N 条数据,依照新表进行拆分兼并,这样能够直接依照新表纬度进行数据库批量操作,进步刺进功率。

扩容计划文字来自 《256变4096:分库分表扩容怎么完成滑润数据搬迁》,笔者做了少许调整。

6 总结

sharding-jdbc 的实质是完成 JDBC 的中心接口,架构相对简略。

实战过程中,需求装备数据源信息,逻辑表对应的实在节点和分库分表战略(分片字段分片算法

完成分布式主键直接路由到对应分片,则需求运用基因法 & 自定义复合分片算法

滑润扩容的中心是全量同步实时双向同步,工程上有不少细节。


实战代码地址:

github.com/makemyownli…

看完这一篇,ShardingSphere-jdbc 实战再也不怕了

参阅资料:

  • 256变4096:分库分表扩容怎么完成滑润数据搬迁?
  • 黄东旭:分布式数据库前史、发展趋势与 TiDB 架构

假如我的文章对你有所协助,还请帮助点赞、在看、转发一下,你的支撑会激励我输出更高质量的文章,十分感谢!