sharding-method分表分库的新思路——服务层Sharding框架,全SQL、全数据库兼容,ACID特性与原生数据库一致,能实现RR级别读写分离,无SQL解析性能更高
目前国内主流的Sharding框架都是基于SQL来完成,其主要流程:
1)是解析上层传入的SQL
2)结合对应的分表分库配置,对传入的SQL进行改写并分发到对应的单机数据库上
3)获得各个单机数据库的返回结果后,根据原SQL归并结果,返回用户期待的结果
这种实现希望提供一个屏蔽底层Sharding逻辑的解决方案,对上层应用来说,只有一个RDB,这样应用可以透明访问多个数据库。
然而,这仅仅只是一个美丽的目标。因种种原因,这些层次的Sharding方案都无法提供跟原生数据库一样的功能:
1)ACID里的A无法保证
2)ACID里的C可能被打破
3)ACID里的I与原生不一致
4)由于SQL解析复杂,性能等考虑,很多数据库SQL不支持
正因为存在这些差异,本质上,上层应用必须明确的知道经过此类Sharding方案后得到的查询结果、事务结果与原生的有啥不一致才能写出正确可靠的程序。
因此,基于SQL的Sharding方案对应用层并不透明。
如果要基于SQL层的框架写出正确可靠的代码的话,我们需要遵循一些范式:
1)所有事务(包括读、写)都不能跨库
2)跨分片的查询提供的隔离级别与原生不一致
3)某些聚合查询的性能消耗很大,要慎用
这些范式对于实际上就是使用Sharding数据库框架时,不透明的表现。而这些表现都是隐式的隐藏于SQL中,难以REVIEW。
而且这些范式对于很多人来说不一定能够充分理解执行的含义,以至于忽略了。
由上面最重要的一点“所有事务(包括读、写)都不能跨库”决定,一个合理设计的代码里绝大多数的业务代码中数据库访问都不会跨分区,核心业务代码都在同一分区内进行。 因此,我们大多数情况下,需要的只是一个协助我们便捷选择对应分片的一个框架。
基本注解使用方法
@ShardingContext表示当前的Service的Sharding上下文,就是说,如果有 选择数据源、Map到各数据库Reduce出结果、生成ID等操作时,如果某些参数没有指定,都从这个ShardingContext里面的配置取
@SelectDataSource表示为该方法内执行的SQL根据Sharding策略选择一个Sharding数据源,在方法结束返回前,不能更改Sharding数据源
@GenerateId表示生成ID,并将其赋值到参数的指定位置
@GenerateId对应的逻辑会先执行,然后到@SelectDataSource然后到@Transaction
@Transactional(readOnly=true)标签指定了事务时只读的,因此框架会根据readOnly标志自动选择读库(如果有的话)
从方法calcUserAvgAge可以看到在JDK8的LAMBADA表达式及Stream功能下,JAVA分析处理集合数据变得极为简单,这会大大减少我们自行加工Sharding分片数据的复杂度。
@MapReduce表示该方法将会在每个数据分片都执行一遍,然后进行数据聚合后返回。 对于聚合前后返回的数据类型一致的方法,调用时可以直接从返回值取得聚合结果。 对于聚合前后返回的数据类型不一致的方法,需要传入一个对象ReduceResultHolder,调用完成后,通过该对象获得聚合结果
默认情况下,框架会提供一个通用Reduce策略,如果是数字则累加返回,如果是Collection及其子类则合并后返回,如果是MAP则也是合并后返回。 如果该策略不适合,那么用户可自行设计指定Reduce策略。
@Transaction表示每一个Sharding执行的SQL都处于一个事务中,并不是表示整个聚合操作是一个整体的事务。所以,MapReduce最好不要进行更新操作(考虑框架层次限制MapReduce只允许ReadOnly事务)。
@MapReduce执行的操作会在@Transaction之前。
优点缺点对比
以上是框架的主要使用形式,我们可以从这种实现中发现服务层的Sharding有以下好处
全数据库、全SQL兼容
SQL层Sharding无法做到
能完美实现读写分离
基于SQL层实现的Sharding引入读写分离后,在上层Service感知的事务里,存在混乱的隔离级别的问题,其最多实现RC级别读写分离(若不在Service层介入相关辅助代码的话),而Service层Sharding在Service开始前就能确定该事务是读事务,整个读事务都在一个读库中完成,隔离级别与数据库一致
无额外维护DBProxy可用性的负担
相对于复杂的SQL解析,实现简单,相信花个一天就能看完所有代码,整个框架了如指掌
无SQL解析成本,性能更高
隔离级别及事务原子性等特征与使用的数据库一致,无额外学习负担,易于写出正确的程序
框架限制了所有事务都在单库进行
基于Sql的Sharding即使在非读写分离情况下,因其需要归并多个数据库的结果,其提供的隔离级别也是混乱的,但这个区别并没有显式的提示到程序员。
当然也存在缺点
劣势:
跨库查询需要自行进行结果聚合
是劣势也是优势
劣势:需要完成额外的聚合代码
优势:但其能能更好的调优,使用JDK8的Stream及Lambada表达式,能像写SQL一样简单的完成相关集合处理
跨库事务需要自行保证
是劣势也是优势
劣势:需要额外自行实现跨库事务
优势:目前所有的Sharding框架实现的跨库事务都有缺陷或者说限制,如Sharding-JDBC,Mycat等提供的跨库事务都并非严格意义的ACID,A可能被打破,I也与原生定义的不一样,程序员不熟悉时就很容易写出不可靠的代码。因此自行控制分布式事务,采用显式的事务控制或许是更好的选择。可参考使用本人写的另外一个框架EasyTransaction
无法实现单库分表
其实,单库分表并不是必须的,这可以用数据原生的表分区来实现,性能一样,使用更便捷
相关推荐
使用mysql5.7+sharding-proxy实现分表,策略为每半年时间分一次表
ShardingSphere是一套开源的分布式数据库中间件解决方案组成的生态圈,它由Sharding-JDBC、Sharding-Proxy和Sharding-Sidecar(计划中)这3款相互独立的产品组成。 他们均提供标准化的数据分片、分布式事务和数据库...
sharding-sphere4.1.1
该项目主要采用springboot2.x+sharding -spring-boot-sharding-jdbc
利用ShardingSphere(sharding-proxy)实现分库分表,通过整合ZooKeeper,进行简单配置文件修改轻松实现跨库跨表相关操作,轻量级零侵入整合项目开发。
sharding-jdbc 3.1.0 不分片表,分页bug,第二页查出的数据会显示前面的数据 https://github.com/apache/incubator-shardingsphere/issues/1722 sharding-core-3.1.0.jar
SpringBoot+Mybatis-Plus整合Sharding-JDBC5.1.1实现单库分表【全网最新】.doc
sharding-jdbc 目录结构 sjdbc-read-write-springboot:Spring Boot版 Sharding JDBC 读写分离示列 sjdbc-db-sharding-springboot:Spring Boot版 Sharding JDBC 垂直拆分(不同的表在不同的库中) sjdbc-db-read-...
apache-shardingsphere-sharding-proxy4.1.1修改后的zip包,对apache官网直接下载的包进行了优化,下载即可使用,不用修改其他东西。
1、基于yml 配置方式 ,实现springBoot+sharding-jdbc+mybatis-plus 实现分库分表,读写分离,以及全局表,子表的配置。 2、实现mybatis-plus 整合到springboot 详细使用请看 测试用例
sharding-jdbc整合boot
Sharding-JDBC教程:Spring Boot2.0以上整合Sharding-JDBC实现分库分表+读写分离,Mysql数据库主从搭建:https://blog.csdn.net/forezp/article/details/94173427
Springboot集成最新版本的sharding-jdbc做分库分表、读写分离,自定义分片策略,纯yml版本,集成mybatis和durid
sharding-proxy和sharding-ui 简介与v5.0.0-beat版本搭建配置,相关建库建表sql
使用sharding-jdbc快速实现自动读写分离-demo源码!
mysql分库分表sharding-jdbc-sharding-jdbc-demo
sharind-jdbc样例,当中包含了按月动态分表,一个比较简单的demo,仅供参考!……………………
集成sharding-jdbc实现分库分表.zip
sharding-jdbc 分库分表
Sharding-JDBC实现读写分离demo