likes
comments
collection
share

sharding-jdbc 分享

作者站长头像
站长
· 阅读数 12

sharding-jdbc 分享

sharding-jdbc 分享

1.简介

Sharding-JDBC 历史

Sharding-JDBC 是当当应用框架 ddframe 中,从关系型数据库模块 dd-rdb 中分离出来的数据库水平分片框架,实现透明化数据库分库分表访问。 Sharding-JDBC 是继 dubbox 和 elastic-job 之后, ddframe 系列开源的第 3 个项目。 3.X 之后已经改变了名字,叫 ShardingSphere ,已交由 apache 进行孵化。

sharding-jdbc 分享ShardingSphere 简介

ShardingSphere 是一套开源的分布式数据库中间件解决方案组成的生态圈,它由 Sharding-JDBC 、 Sharding-Proxy 和 Sharding-Sidecar (计划中)这 3 款相互独立的产品组成。他们均提供标准化的数据分片、分布式事务和数据库治理功能,可适用于如 Java 同构、异构语言、容器、云原生等各种多样化的应用场景。

如果我们不需要向 mycat 一样,部署独立服务代理,那么其实我们只要关注 Sharding-JDBC 即可,目前最新的是 4.0.0-RC1 的版本。

Sharding-JDBC 简介

定位为轻量级 Java 框架,在 Java 的 JDBC 层提供的额外服务。 它使用客户端直连数据库,以 jar 包形式提供服务,无需额外部署和依赖,可理解为增强版的 JDBC 驱动,完全兼容 JDBC 和各种 ORM 框架。

  • 适用于任何基于 Java 的 ORM 框架,如: JPA , Hibernate , Mybatis , Spring JDBC Template 或直接使用 JDBC 。
  • 基于任何第三方的数据库连接池,如: DBCP , C3P0 , BoneCP , Druid , HikariCP 等。
  • 支持任意实现 JDBC 规范的数据库。目前支持 MySQL , Oracle , SQLServer 和 PostgreSQL 。

sharding-jdbc 分享

2.分库分表

分库分表用于应对当前互联网常见的两个场景——大数据量和高并发

分库分表-垂直拆分

当一个数据库中存在着多种不同业务中的表时,各种业务需要同时操作这个 DB ,数据库过大过多会引起 IO 读写瓶颈,这个时候就需要垂直拆分,将一个库(表)拆分为多个库(表)。

sharding-jdbc 分享

优点:

  • 拆分后业务清晰
  • 子系统之间的整合与扩展相对容易
  • 数据便于管理

缺点:

  • 提高系统复杂度
  • 单业务量过大还是不能解决该问题
  • 存在跨库事务的一致性问题

分库分表-水平拆分

单业务量过大的情况下,比如订单交易量过大,会导致单 db 的 io 被打满, cpu 飙升,那么这个时候就需要对订单进行水平拆分,根据分片算法将一个库(表)拆分为多个库(表)

sharding-jdbc 分享

优点:

  • 单库单表的数据容量可以维持在一个量级,有助于提高业务 SQL 的执行效率和系统性能
  • 可以提高业务系统的稳定性和负载能力

缺点:

  • 数据水平切分后,分布在多库多表中,跨库 Join 查询比较复杂
  • 分片数据的一致性较为难保证
  • 对于历史数据的迁移和数据库的扩容需要较大的维护工作量

3.原理解析

真实库:表示在真实存在数据库中的物理库。比如 ordercenter_0 到 ordercenter_7

真实表:表示在真实存在数据库中的物理表。比如 orders_0 到 orders_1023

数据节点: ordercenter_0.orders_0

逻辑表:水平拆分数据库中表的总称。比如 orders

Sharding-JDBC 的整体架构图:

sharding-jdbc 分享

分片规则配置

支持分片策略自定义、复数分片键、多运算符分片等功能。如:根据用户 ID 分库分表;也可以根据年来分库,根据月份分表这种分库分表结合的分片策略。 Sharding-JDBC 除了支持等号运算符进行分片,还支持 in/between 运算符分片,提供了更加强大的分片功能。

JDBC 规范重写

Sharding-JDBC 对 JDBC 规范的重写思路是针对 DataSource 、 Connection 、 Statement 、 PreparedStatement 和 ResultSet 五个核心接口封装,将多个真实 JDBC 实现类集合(如: MySQLJDBC 实现 /DBCPJDBC 实现等)纳入 Sharding-JDBC 实现类管理。

SQL 解析

SQL 解析作为分库分表类产品的核心,性能和兼容性是最重要的衡量指标目前常见的 SQL 解析器主要有 fdb/jsqlparser 和 Druid 。 Sharding-JDBC 使用 Druid 作为 SQL 解析器,经实际测试, Druid 解析速度是另外两个解析器的几十倍。

如:

select id , name from t_user where status = 'active' and age > 18;

sharding-jdbc 分享

SQL 改写

SQL 改写分为两部分:

  • 将分表的逻辑表名称替换为真实表名称。
  • 根据 SQL 解析结果替换一些在分片环境中不正确的功能。

第 1 个例子是 avg 计算。例如在分片的环境中,以 avg1 + avg2 + avg3 / 3 计算平均值并不正确,需要改写为( sum1 + sum2 + sum3 )/( count1 + count2 + count3 )

第 2 个例子是分页。假设每 10 条数据为一页,取第 2 页数据。在分片环境下获取 limit 10 , 10 ,归并之后再根据排序条件取出前 10 条数据是不正确的结果。正确的做法是将分条件改写为 limit 0 , 20 ,取出所有前 2 页数据,再结合排序条件算出正确的数据

select score from t_score order by score desc limit 1 , 2;

sharding-jdbc 分享

sharding-jdbc 分享

SQL 路由

SQL 路由分为:标准路由,直接路由和笛卡尔积路由

例如:

select o.* FROM orders o left join order_goods g ono.id = g.order_id where o.user_id in ( 1 , 2 );

如果两个有绑定关系(用同种规则进行分库分表)

则会解析成以下 2 条 SQL (标准路由)

select o.* from orders_1 o left join order_goods_1g on o.id = g.order_id where o.user_id in ( 1 , 2 );
​
select o.* from orders_2oleft join order_goods_2g on o.id = g.order_id where o.user_id in ( 1 ,  2 );

如果两个有没有绑定关系

则会解析成以下 1024 * 1024 条 SQL (笛卡尔积路由)

select o.* from orders_0oleft join order_goods_1 g on o.id = g.order_id where o.user_id in ( 1 , 2 );
​
select o.* from orders_0oleft join order_goods_2 g on o.id = g.order_id where o.user_id in ( 1 , 2 );
​
……
​
select o.* from orders_1023 oleft join order_goods_1023g on o.id = g.order_id where o.user_id in ( 1, 2 );

结果归并

结果归并包括 4 类:普通遍历类、排序类、聚合类和分组类

普通遍历类最为简单,只需按顺序遍历 ResultSet 的集合即可

排序类结果将结果先排序再输出,因为各分片结果均按照各自条件完成排序,所以采用归并排序算法整合最终结果

聚合类分为 3 种类型,比较型、累加型和平均值型。比较型包括 max 和 min ,只返回最大(小)结果。累加型包括 sum 和 count ,需要将结果累加后返回。平均值则是通过 SQL 改写的 sum 和 count 计算

分组类最为复杂,需要将所有的 ResultSet 结果放入内存,使用 map-reduce 算法分组,最后根据排序和聚合条件做相关处理。最消耗内存,最损失性能的部分即是此,可以考虑使用 limit 合理的限制分组数据大小。

标准分库算法

sharding-jdbc 分享

标准分表算法

sharding-jdbc 分享

快速接入实战

引入 jar 包:

<dependency>
    <groupId>org.apache.shardingsphere</groupId>
    <artifactId>sharding-jdbc-spring-boot-starter</artifactId>
    <version>4.1.1</version>
</dependency><dependency>
    <groupId>org.apache.shardingsphere</groupId>
    <artifactId>sharding-jdbc-spring-namespace</artifactId>
    <version>4.1.1</version>
</dependency>

添加配置:

#数据库分表规则
#数据源配置
spring.shardingsphere.datasource.names = master0
#库master0 的连接配置
spring.shardingsphere.datasource.master0.type = com.alibaba.druid.pool.DruidDataSource
spring.shardingsphere.datasource.master0.driver-class-name = com.mysql.jdbc.Driver
spring.shardingsphere.datasource.master0.url = 数据库地址
spring.shardingsphere.datasource.master0.username = 账号
spring.shardingsphere.datasource.master0.password = 密码
spring.shardingsphere.datasource.master0.initial-size = 10
spring.shardingsphere.datasource.master0.min-idle = 5
spring.shardingsphere.datasource.master0.maxActive = 200
spring.shardingsphere.datasource.master0.maxWait = 60000
spring.shardingsphere.datasource.master0.timeBetweenEvictionRunsMillis = 60000
spring.shardingsphere.datasource.master0.minEvictableIdleTimeMillis = 300000
spring.shardingsphere.datasource.master0.validationQuery = SELECT 1
spring.shardingsphere.datasource.master0.testWhileIdle = true
spring.shardingsphere.datasource.master0.testOnBorrow = false
spring.shardingsphere.datasource.master0.testOnReturn = false
spring.shardingsphere.datasource.master0.poolPreparedStatements = true
spring.shardingsphere.datasource.master0.maxPoolPreparedStatementPerConnectionSize = 20
spring.shardingsphere.datasource.master0.filters = stat,wall,log4j2
spring.shardingsphere.datasource.master0.connectionProperties = druid.stat.mergeSql=true;druid.stat.slowSqlMillis=5000
​
​
# 需要分表的表声明 
spring.shardingsphere.sharding.tables.表名.actual-data-nodes =  master0.表名$->{0..N}
#分表字段
spring.shardingsphere.sharding.tables.表名.table-strategy.inline.sharding-column = 分表字段X
#分片算法表达式,简单的取模为例
spring.shardingsphere.sharding.tables.表名.table-strategy.inline.algorithm-expression = 分表的表名$->{分表字段X % N}
​
#打印sql
spring.shardingsphere.props.sql.show = false
#校验表是否存在
backlogSyncConfig.checkTableExist = false

数据库表初始化后,就可以启动项目开始探索了~~

官方文档地址

shardingsphere.apache.org/index_zh.ht…

推荐阅读

用户路径分析

浅析 MySQL 中 join 查询

为什么 Redis 这么快之数据结构

从源码看 Lucene 的文档写入流程

浅谈WebAssembly

招贤纳士

政采云技术团队(Zero),一个富有激情、创造力和执行力的团队,Base 在风景如画的杭州。团队现有 500 多名研发小伙伴,既有来自阿里、华为、网易的“老”兵,也有来自浙大、中科大、杭电等校的新人。团队在日常业务开发之外,还分别在云原生、区块链、人工智能、低代码平台、中间件、大数据、物料体系、工程平台、性能体验、可视化等领域进行技术探索和实践,推动并落地了一系列的内部技术产品,持续探索技术的新边界。此外,团队还纷纷投身社区建设,目前已经是 google flutter、scikit-learn、Apache Dubbo、Apache Rocketmq、Apache Pulsar、CNCF Dapr、Apache DolphinScheduler、alibaba Seata 等众多优秀开源社区的贡献者。如果你想改变一直被事折腾,希望开始折腾事;如果你想改变一直被告诫需要多些想法,却无从破局;如果你想改变你有能力去做成那个结果,却不需要你;如果你想改变你想做成的事需要一个团队去支撑,但没你带人的位置;如果你想改变本来悟性不错,但总是有那一层窗户纸的模糊……如果你相信相信的力量,相信平凡人能成就非凡事,相信能遇到更好的自己。如果你希望参与到随着业务腾飞的过程,亲手推动一个有着深入的业务理解、完善的技术体系、技术创造价值、影响力外溢的技术团队的成长过程,我觉得我们该聊聊。任何时间,等着你写点什么,发给 zcy-tc@cai-inc.com

微信公众号

文章同步发布,政采云技术团队公众号,欢迎关注

sharding-jdbc 分享