上一章已经讲述分库分表算法选型,本章主要讲述分库分表技术选型

文中关联上一章,若下文出现提及其时,可以点击 分库分表算法方案与技术选型(一)

主要讲述

  • 框架比较
  • sharding-jdbc、zdal 代码实现样例,如需源码可在后文中查看
  • 主键生成策略

可以按需阅读文章

点赞再看,关注公众号:【地藏思维】给大家分享互联网场景设计与架构设计方案
掘金:地藏Kelvin https://juejin.im/user/5d67da8d6fb9a06aff5e85f7

常见框架

除了原生JDBC,网上常见分库分表框架有:
当当网 sharding-jdbc
alibaba.cobar (是阿里巴巴(B2B)部门开发)
MyCAT(基于阿里开源的Cobar产品而研发)
蚂蚁金服 ZDAL (开源)
蘑菇街 TSharding

当然除了这些,还有很多各自公司提出的框架,但是根据用户量较高的为以上几种。
其中自从出现基于cobar的MyCAT,zdal,也很少人用cobar了。ZDAL虽然也是开源,但是很少文章和使用反馈,不支持MongoDb,交流活跃度也比较低。

所以本次文章来比较一下活跃度较高的sharding-jdbc和MyCAT

扩展阅读:当当网做的不错的,除了sharding-jdbc,还有elastic-job用于定时任务分片

对比概览

主要指标 Sharding-jdbc Mycat zdal
ORM支持 任意 任意 任意
事务 自带弱XA、最大努力送达型柔性事务BASE 自带弱XA 自带弱XA、最大努力送达型柔性事务BASE
分库 支持 支持 支持
分库 支持 不支持单库分表 支持
开发 开发成本高,代码入侵大 开发成本小,代码入侵小 开发成本不算高配置明确
所属公司 当当网 基于阿里Cobar二次开发,社区维护 蚂蚁金服
数据库支持 任意 Oracle、 SQL Server、 Mysql、DB2、mongodb 不支持mongodb
活跃度 也有不少的企业在最近几年新项目使用 社区活跃度很高,一些公司已在使用 活跃度低
监控
读写分离 支持 支持
资料 资料少、github、官网、网上讨论贴 资料多,github、官网、Q群、书籍
运维 维护成本低 维护成本高 维护成本低
限制 部分JDBC方法不支持、SQL语句限制 SQL语句限制
连接池 druid版本 无要求 无要求
配置难度 一般 复杂 比较简单,读写分离、分开分表规则设置量少

关键指标对比

1.开发与运维成本

sharding-jdbc

  • sharding-jdbc是一个轻量级框架,不是独立运行中间件,以工程的依赖jar的形式提供功能,无需额外部署,可以理解为增强版JDBC驱动。
  • 对运维、DBA人员无需感知代码与分片策略规则,运维只需要维护执行建立表和数据的迁移。
  • 相对Mycat这是sharding-jdbc的优势,减少了部署成本以及DBA学习成本。
  • 原理是通过规则改写原sql,如select from A 根据规则变成select from A_01,运行执行sql时就会向mysql服务器传select * from A_01指令。

MyCat

  1. 而MyCat并不是业务系统代码里面的配置,而是独立运行的中间件,所以配置都会交给DBA执行。
  2. 对于DBA来说,他是一个在mysql Server前,增加一层代理,mycat本身不存数据,数据是在后端的MySQL上存储的,因此数据可靠性以及事务等都是MySQL保证的。
  3. 为了减少迁移数据的风险,在 上一章推荐的增量迁移算法方案(推荐大家阅读)讲述如何分片达到降低风险。

若用MyCat,DBA需要配置多次的增量分片规则,每配置一次则要重启一次,才能达到一轮的数据迁移。实际上MyCat down掉的时系统都不能对数据库查询,实际依然对所有用户有影响。

  1. 然而sharding-jdbc都在代码实现路由规则,则可以减少DBA操作次数和系统重启次数,进而减少影响用户数。
推荐阅读第一章的第五节才比较好理解上述3~4点 分库分表算法方案与技术选型(一)
  1. proxy整合大数据思路,将 OLTP 和 OLAP 分离处理,可能会对大数据处理的系统比较适合,毕竟数据工作不一定有java后端系统。
该点总结:sharding-jdbc增量分片和增量迁移数据效果更佳,mycat比较适合大数据工作

备注:
sharding-jdbc增强了JDBC驱动部分功能,但同时也限制部分原生JDBC接口的使用。具体限制参考:
限制情况:http://dangdangdotcom.github.io/sharding-jdbc/01-start/limitations/ 这个文档现在好像访问不了
附:
官网文档
官网源码

MyCat配置样例
MyCat配置样例2

2.分库分表能力

  • sharding-jdbc另一个优势是他的分表能力,可以不需要分库的情况下单库分表。
  • MyCAT不能单库分多表,必须分库,这样就会造成让DBA增加机器节点,即使不增加机器节点,也会在同一个机器上增加mysql server实例,若使用sharding-jdbc单库分多表,则DBA只需要执行建立表语句即可。

3.事务

首先说说XA, XA 多阶段提交的方式,虽然对分布式数据的完整性有比较好的保障,但会极大的降影响应用性能。

  • sharding-jdbc和mycat支持弱XA,弱 XA 就是分库之后的数据库各自负责自己事务的提交和回滚,没有统一的调度器集中处理。这样做的好处是天然就支持,对性能也没有影响。但一旦出问题,比如两个库的数据都需要提交,一个提交成功,另一个提交时断网导致失败,则会发生数据不一致的问题,而且这种数据不一致是永久存在的。
  • 柔性事务是对弱 XA 的有效补充。柔性事务类型很多。

Sharding-JDBC 主要实现的是最大努力送达型。即认为事务经过反复尝试一定能够成功。如果每次事务执行失败,则记录至事务库,并通过异步的手段不断的尝试,直至事务成功(可以设置尝试次数,如果尝试太多仍然失败则入库并需要人工干预)。在尝试的途中,数据会有一定时间的不一致,但最终是一致的。通过这种手段可以在性能不受影响的情况下牺牲强一致性,达到数据的最终一致性。最大努力送达型事务的缺点是假定事务一定是成功的,无法回滚,因此不够灵活。

备注:
还有一种柔性事务类型是 TCC,即 Try Confirm Cancel。可以通过事务管理器控制事务的提交或回滚,更加接近原生事务,但仍然是最终一致性。其缺点是需要业务代码自行实现 Try Confirm Cancel 的接口,对现有业务带来一定冲击。Sharding-JDBC 未对 TCC 的支持。

4.监控

为什么要监控,因为上述事务的弱XA、最大努力送达型,其实还是有概率失败。

  • MyCat就要监控页面,监控MyCat与Mysql server的心跳,运维人员可以看到
  • 而sharding-jdbc没有监控事务是不是最终执行了,可能需要改写源码,如果有个分片没执行成功就发一下短信、钉钉之类的。

MyCat监控配置样例

5.语句限制

  • sharding-jdbc分库分表使用 like 查询是有限制的。目前 Shariding-JDBC 不支持 like 语句中包含分片键,但不包含分片键的 like 语句可以正确执行。

至于 like 性能问题,是与数据库相关的,Shariding-JDBC 仅仅是解析 SQL 以及路由至正确的数据源而已。
是否会查询所有的库和表是根据分片键决定的,如果 SQL 中不包括分片键,就会查询所有库和表,这个和是否有 like 没有关系。

  • MyCat没有限制

6.比较蚂蚁金服的zdal

相对zdal来说,sharding-jdbc的配置量差不多,但是sharding-jdbc提供了java、springboot、yml、spring命名空间方式,而且有官方网站和gitee网站维护。相对zdal用户更加活跃。


Sharding-jdbc分库分表整合mybatis-plus 开发样例

代码样例具体描述,下述关键的开发点。
具体源码请到我的gitee地址sharding-jdbc-example

sharding-jdbc分片的开发主要几个关键点:

  1. 引入关键依赖 2019.10最新版4.0.0-RC2
         <dependency>
            <groupId>org.apache.shardingsphere</groupId>
            <artifactId>sharding-jdbc-spring-namespace</artifactId>
            <version>4.0.0-RC2</version>
        </dependency>
  1. 在xml中配置基础数据源、分库分表的策略,其中DbShardingAlgorithm,TbShardingAlgorithm需要在java代码里面实现。
<--分库的规则对象类->
    <bean id="preciseModuloDatabaseShardingAlgorithm" class="com.dizang.sharding.config.algorithm.DbShardingAlgorithm" />
    <--分表规则对象类->
    <bean id="preciseModuloTableShardingAlgorithm" class="com.dizang.sharding.config.algorithm.TbShardingAlgorithm" />
    <--分库根据的key->
    <sharding:standard-strategy id="databaseStrategy" sharding-column="user_id" precise-algorithm-ref="preciseModuloDatabaseShardingAlgorithm" />
    <--分库根据的key->
    <sharding:standard-strategy id="tableShardingStrategy" sharding-column="user_id" precise-algorithm-ref="preciseModuloTableShardingAlgorithm" />
    
    <sharding:key-generator id="orderKeyGenerator" type="SNOWFLAKE" column="id" />
    
    <sharding:data-source id="shardingDataSource">
    <--分表数据源->
        <sharding:sharding-rule data-source-names="ds0, ds1">
            <sharding:table-rules>
            <--逻辑表名->
                <sharding:table-rule logic-table="t_user" 
                actual-data-nodes="ds$->{0..1}.t_user_$->{0..2}" 
                <--分库分表逻辑bean->
                database-strategy-ref="databaseStrategy" 
                table-strategy-ref="tableShardingStrategy" 
                key-generator-ref="orderKeyGenerator" />
            </sharding:table-rules>
            <--配置能适用规则的表->
            <sharding:binding-table-rules>
                <sharding:binding-table-rule logic-tables="t_user" />
            </sharding:binding-table-rules>
            <--配置不需要分库分表的表->
            <sharding:broadcast-table-rules>
                <sharding:broadcast-table-rule table="t_order" />
            </sharding:broadcast-table-rules>
        </sharding:sharding-rule>
    </sharding:data-source>

<--sqlSessionFactory配置shardingDataSource数据源->
    <bean id="sqlSessionFactory"
    class="com.baomidou.mybatisplus.extension.spring.MybatisSqlSessionFactoryBean"> 
        <property name="dataSource" ref="shardingDataSource"/>
        <property name="mapperLocations" value="classpath*:mapper/*.xml"/>
    </bean>
  1. java代码编写分库策略

需要继承SingleKeyDatabaseShardingAlgorithm分开规则类,重写equal等于、大于、小于时的路由规则

public class DbShardingAlgorithm implements PreciseShardingAlgorithm<Long>{  

    @Override
    public String doSharding(Collection<String> databaseNames, PreciseShardingValue<Long> shardingValue) {
        for (String each : databaseNames) {
            if (each.endsWith(shardingValue.getValue() % 2 + "")) {
                return each;
            }
        }
        return null;
    }  

}  
  1. java代码编写分表策略

需要继承SingleKeyTableShardingAlgorithm分开规则类,重写equal等于、大于、小于时的路由规则

public class TbShardingAlgorithm implements PreciseShardingAlgorithm<Long>{  

    @Override
    public String doSharding(Collection<String> tableNames, PreciseShardingValue<Long> shardingValue) {
        for (String each : tableNames) {
            if (each.endsWith(shardingValue.getValue() % 2 + "")) {
                return each;
            }
        }
//        return shardingValue.getLogicTableName()+(shardingValue.getValue() % 2);
        throw new UnsupportedOperationException();
    }  

}  

zdal具体代码实现推荐阅读

Zdal分库分表介绍、超详细一步一步搭建简单的zdal框架


欢迎关注

我的公众号 :地藏思维

我的Gitee: 地藏Kelvin https://gitee.com/dizang-kelvin

推荐阅读sharding-jdbc源码:

Sharding-JDBC 源码解析合集

Sharding-JDBC 源码分析 —— SQL 改写

原生jdbc读写分离


地藏Kelvin
49 声望9 粉丝