微速讯:看完这一篇,ShardingSphere-jdbc 实战再也不怕了
谈到分库分表中间件时,我们自然而然的会想到 ShardingSphere-JDBC 。
【资料图】
这篇文章,我们聊聊 ShardingSphere-JDBC 相关知识点,并实战演示一番。
1 ShardingSphere 生态
Apache ShardingSphere 是一款分布式的数据库生态系统,它包含两大产品:
ShardingSphere-Proxy ShardingSphere-JDBC▍一、ShardingSphere-Proxy
ShardingSphere-Proxy 被定位为透明化的数据库代理端,提供封装了数据库二进制协议的服务端版本,用于完成对异构语言的支持。
代理层介于应用程序与数据库间,每次请求都需要做一次转发,请求会存在额外的时延。
这种方式对于应用非常友好,应用基本零改动,和语言无关,可以通过连接共享减少连接数消耗。
▍二、ShardingSphere-JDBC
ShardingSphere-JDBC 是 ShardingSphere 的第一个产品,也是 ShardingSphere 的前身, 我们经常简称之为:sharding-jdbc 。
它定位为轻量级 Java 框架,在 Java 的 JDBC 层提供的额外服务。它使用客户端直连数据库,以 jar 包形式提供服务,无需额外部署和依赖,可理解为增强版的 JDBC 驱动,完全兼容 JDBC 和各种 ORM 框架。
当我们在 Proxy 和 JDBC 两种模式选择时,可以参考下表对照:
JDBC | Proxy | |
---|---|---|
数据库 |
| MySQL/PostgreSQL |
连接消耗数 |
| 低 |
异构语言 |
| 任意 |
性能 |
| 损耗略高 |
无中心化 |
| 否 |
静态入口 |
| 有 |
越来越多的公司都在生产环境使用了 sharding-jdbc ,最核心的原因就是:简单(原理简单,易于实现,方便运维)。
2 基本原理
在后端开发中,JDBC 编程是最基本的操作。不管 ORM 框架是 Mybatis 还是 Hibernate ,亦或是 spring-jpa ,他们的底层实现是 JDBC 的模型。
sharding-jdbc 的本质上就是实现 JDBC 的核心接口。
接口 | 实现类 |
---|---|
DataSource | ShardingDataSource |
Connection | ShardingConnection |
Statement | ShardingStatement |
PreparedStatement | ShardingPreparedStatement |
ResultSet | ShardingResultSet |
虽然我们理解了 sharding-jdbc 的本质,但是真正实现起来还有非常多的细节,下图展示了 Prxoy 和 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 。
这四个分库,每个分库都包含 订单基础表 , 订单详情表 ,订单明细表 。但是因为明细表需要分表,所以包含多张表。
然后 springboot 项目中配置依赖 :
org.apache.shardingsphere sharding-jdbc-spring-boot-starter 4.1.1
配置文件中配置如下:
配置数据源,上面配置数据源是: ds0、ds1、ds2、ds3 ;配置打印日志,也就是:sql.show ,在测试环境建议打开 ,便于调试;配置哪些表需要分库分表 ,在 shardingsphere.datasource.sharding.tables 节点下面配置:上图中我们看到配置分片规则包含如下两点:
1.真实节点
对于我们的应用来讲,我们查询的**逻辑表**是:t_ent_order_item 。
它们在数据库中的真实形态是:`t_ent_order_item_0` 到 `t_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落入哪个区段,便路由到哪个分库。
看起来分片算法很简单,但我们需要按照订单 ID 查询订单信息时依然需要路由四个分片,效率不高,那么如何优化呢 ?
答案是:基因法& 自定义复合分片算法。
基因法是指在订单 ID 中携带企业用户编号信息,我们可以在创建订单 order_id时使用雪花算法,然后将 slot的值保存在 10位工作机器 ID里。
通过订单 order_id 可以反查出 slot, 就可以定位该用户的订单数据存储在哪个分片里。
Integer getWorkerId(Long orderId) { Long workerId = (orderId >> 12) & 0x03ff; return workerId.intValue();}
下图展示了订单 ID 使用雪花算法的生成过程,生成的编号会携带企业用户 ID 信息。
解决了分布式 ID 问题,接下来的一个问题:sharding-jdbc 可否支持按照订单 ID ,企业用户 ID 两个字段来决定分片路由吗?
答案是:自定义复合分片算法。我们只需要实现 ComplexKeysShardingAlgorithm类即可。
复合分片的算法流程非常简单:
1.分片键中有主键值,则直接通过主键解析出路由分片;
2.分片键中不存在主键值 ,则按照其他分片字段值解析出路由分片。
5 扩容方案
既然做了分库分表,如何实现平滑扩容也是一个非常有趣的话题。
在数据同步之前,需要梳理迁移范围。
1.业务唯一主键;
在进行数据同步前,需要先梳理所有表的唯一业务 ID,只有确定了唯一业务 ID 才能实现数据的同步操作。
需要注意的是:业务中是否有使用数据库自增 ID 做为业务 ID 使用的,如果有需要业务先进行改造 。另外确保每个表是否都有唯一索引,一旦表中没有唯一索引,就会在数据同步过程中造成数据重复的风险,所以我们先将没有唯一索引的表根据业务场景增加唯一索引(有可能是联合唯一索引)。
2.迁移哪些表,迁移后的分库分表规则;
分表规则不同决定着 rehash 和数据校验的不同。需逐个表梳理是用户ID纬度分表还是非用户ID纬度分表、是否只分库不分表、是否不分库不分表等等。
接下来,进入数据同步环节。
整体方案见下图,数据同步基于 binlog ,独立的中间服务做同步,对业务代码无侵入。
首先需要做历史数据全量同步:也就是将旧库迁移到新库。
单独一个服务,使用游标的方式从旧库分片 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 的核心接口,架构相对简单。
实战过程中,需要配置数据源信息,逻辑表对应的真实节点和分库分表策略(分片字段和分片算法)
实现分布式主键直接路由到对应分片,则需要使用基因法 & 自定义复合分片算法。
平滑扩容的核心是全量同步和实时双向同步,工程上有不少细节。
实战代码地址:
https://github.com/makemyownlife/shardingsphere-jdbc-demo
参考资料:
256变4096:分库分表扩容如何实现平滑数据迁移?黄东旭:分布式数据库历史、发展趋势与 TiDB 架构如果我的文章对你有所帮助,还请帮忙点赞、在看、转发一下,你的支持会激励我输出更高质量的文章,非常感谢!
精心推荐
- 全国首批!广州市获批开展外籍“高精尖缺”人才认定标准试点工作
- 比利时市场调查显示超七成零售商对前景担忧
- 观察:12月29日基金净值:广发创新升级混合最新净值2.7602,跌0.21%
- 2023金华双龙旅游景区跨年敲钟祈福仪式_世界热文
- 一镜到底穿越2022
- 2023中国长春净月潭瓦萨国际滑雪节开始时间 世界观速讯
- 深圳坪山云巴 1 号线通车:最高时速 80km / h,采用无人驾驶技术 全球热讯
- 世界观点:量子思维(08050.HK)认购180万元理财产品
- 热点在线丨对友情绝望的句子精选316句
- 西安儿童医院发热门诊就诊须知
- 政府补贴助推上海快递业火爆:配送员找亲友帮忙送单,有外卖员日赚千元
- 机器学习数据不满足同分布,怎么整? 环球播报
- 保定市涞水县交通违章可以在网上办理吗
- 天天头条:中信证券: 中信证券股份有限公司第七届董事会第四十八次会议决议公告
-
新华网科伦坡12月27日电(记者车宏亮)马累消息:中马友谊赛跑近日在马尔代夫首都马累市中马友谊大桥上举行,中国驻马大使王立新、马青体部长
-
华东医药(000963)12月27日在投资者关系平台上答复了投资者关心的问题。
-
中新网西宁12月26日电(李隽)26日,记者从青海省人民政府获悉,该省将碳达峰碳中和纳入经济社会发展和生态文明建设整体布局,从供给、消费、固
-
华天酒店12月26日主力资金净流入9353 70万元,涨跌幅为7 76%,主力净量(dde大单净额 流通股)为1 54%,两市排名25 4897。投顾分析华天酒店今日
-
12月25日,国联证券发布一篇非银金融行业的研究报告,报告指出,建议低位布局非银板块,静候风险偏好回升。 报告具体内容如下: 投资要
X 关闭
X 关闭
产业
-
不用跑北京 在家门口也能挂上顶...
日前,我省首个神经疾病会诊中心——首都医科大学宣武医院河北医院...
-
“十四五”期间 河北省将优化快...
从省邮政管理局获悉,十四五期间,我省将优化快递空间布局,着力构...
-
张家口市宣化区:光伏发电站赋能...
3月19日拍摄的张家口市宣化区春光乡曹庄子村光伏发电站。张家口市宣...
-
“张同学”商标被多方抢注 涉及...
“张同学”商标被多方抢注,官方曾点名批评恶意抢注“丁真” ...
-
山东济南“防诈奶奶团”花式反诈...
中新网济南12月15日电 (李明芮)“老有所为 无私奉献 志愿服...
-
广州新增1例境外输入关联无症状...
广州卫健委今日通报,2021年12月15日,在对入境转运专班工作人...
-
西安报告初筛阳性病例转为确诊病例
12月15日10:20,经陕西西安市级专家组会诊,西安市报告新冠病毒...
-
广东东莞新增本土确诊病例2例 ...
(抗击新冠肺炎)广东东莞新增本土确诊病例2例 全市全员核酸检测...
-
中缅边境临沧:民警深夜出击捣毁...
中新网临沧12月15日电 (胡波 邱珺珲)记者15日从云南临沧边境...
-
“土家鼓王”彭承金:致力传承土...
中新网恩施12月15日电 题:“土家鼓王”彭承金:致力传承土家...