ShardingJDBC
1.简介
Sharding-JDBC 历史
Sharding-JDBC 是当当应用框架 ddframe 中,从关系型数据库模块 dd-rdb 中分离出来的数据库水平分片框架,实现透明化数据库分库分表访问。 Sharding-JDBC 是继 dubbox 和 elastic-job 之后, ddframe 系列开源的第 3 个项目。 3.X 之后已经改变了名字,叫 ShardingSphere ,已交由 apache 进行孵化。
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 。
2.分库分表
分库分表用于应对当前互联网常见的两个场景——大数据量和高并发
分库分表-垂直拆分
当一个数据库中存在着多种不同业务中的表时,各种业务需要同时操作这个 DB ,数据库过大过多会引起 IO 读写瓶颈,这个时候就需要垂直拆分,将一个库(表)拆分为多个库(表)。
优点:
- 拆分后业务清晰
- 子系统之间的整合与扩展相对容易
- 数据便于管理
缺点:
- 提高系统复杂度
- 单业务量过大还是不能解决该问题
- 存在跨库事务的一致性问题
分库分表-水平拆分
单业务量过大的情况下,比如订单交易量过大,会导致单 db 的 io 被打满, cpu 飙升,那么这个时候就需要对订单进行水平拆分,根据分片算法将一个库(表)拆分为多个库(表)
优点:
- 单库单表的数据容量可以维持在一个量级,有助于提高业务 SQL 的执行效率和系统性能
- 可以提高业务系统的稳定性和负载能力
缺点:
- 数据水平切分后,分布在多库多表中,跨库 Join 查询比较复杂
- 分片数据的一致性较为难保证
- 对于历史数据的迁移和数据库的扩容需要较大的维护工作量
3.原理解析
真实库:表示在真实存在数据库中的物理库。比如 ordercenter_0 到 ordercenter_7
真实表:表示在真实存在数据库中的物理表。比如 orders_0 到 orders_1023
数据节点: ordercenter_0.orders_0
逻辑表:水平拆分数据库中表的总称。比如 orders
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 解析速度是另外两个解析器的几十倍。
如:
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 页数据,再结合排序条件算出正确的数据
SQL 路由
SQL 路由分为:标准路由,直接路由和笛卡尔积路由
例如
select o.*FROM orders oleftjoin order_goods g ono.id = g.order_idwhere o.user_idin ( 1 , 2 );
如果两个有绑定关系(用同种规则进行分库分表)
则会解析成以下 2 条 SQL (标准路由)
如果两个有没有绑定关系
则会解析成以下 1024 * 1024 条 SQL (笛卡尔积路由)
结果归并
结果归并包括 4 类:普通遍历类、排序类、聚合类和分组类
普通遍历类最为简单,只需按顺序遍历 ResultSet 的集合即可
排序类结果将结果先排序再输出,因为各分片结果均按照各自条件完成排序,所以采用归并排序算法整合最终结果
聚合类分为 3 种类型,比较型、累加型和平均值型。比较型包括 max 和 min ,只返回最大(小)结果。累加型包括 sum 和 count ,需要将结果累加后返回。平均值则是通过 SQL 改写的 sum 和 count 计算
分组类最为复杂,需要将所有的 ResultSet 结果放入内存,使用 map-reduce 算法分组,最后根据排序和聚合条件做相关处理。最消耗内存,最损失性能的部分即是此,可以考虑使用 limit 合理的限制分组数据大小。
标准分库算法
标准分表算法
快速接入实战
引入 jar 包:
添加配置:
数据库表初始化后,就可以启动项目开始探索了~~
官方文档地址
Loading...