Mysql数据分片技术(二)——轻量分库分表框架Sharding-jdbc实例


作者:空白

1. 初识shardingJdbc

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

sharding-jdbc兼容的ORM框架有JPA, Hibernate, Mybatis, Spring JDBC Template,本文的实例项目就是基于mybatis框架的springboot项目。

sharding-jdbc是个轻量的数据库分片框架,分片模块是嵌入在每个应用程序中,属于应用程序的一部分。这种模式适合服务数量小的场景,如果服务数量是万级的集群,那么这种客户端模式的数据分片技术就不适用,而数据库分片代理模式就有明显的优势了。客户端模式如下图:

alt

2. sharding-jdbc四种配置方式

官方介绍了sharding-jdbc的四种配置方式:Java,YAML,Spring命名空间和Spring Boot Starter等。

我们一般把Java配置方式成为动态配置的方式,这种方式空白会在mysql分片技术系列的sharding-jdbc的java方式中详细讲解。

其实springboot的静态配置方式有3种,分别是yaml,springboot starter以及spring命名空间。本文介绍的是我的一个yaml方式创建的分库分表springboot实例。

静态配置方式的缺点。
静态配置的方式最大的不足就是不能动态的修改数据源的配置信息。当我们需要对数据库进行扩容和缩容的时候,我们必须把服务节点宕机停服来修改配置文件信息。即无法支持动态扩容。

3. YAML配置方式及mysql环境准备

我的实例项目准备了两个mysql的数据库,每个数据库中有两个订单表TransInfo(TransInfo0和TransInfo1),两个数据库是myutilproject0和myutilproject1。

数据库创建脚本

create database myutilproject0
create database myutilproject1
use myutilproject0
create table TransInfo0( id bigint primary key auto_increment, userid varchar(20) not null, orderid bigint(20)   unsigned NOT NULL );
create table TransInfo1( id bigint primary key auto_increment, userid varchar(20) not null, orderid bigint(20)   unsigned NOT NULL );
use myutilproject1
create table TransInfo0( id bigint primary key auto_increment, userid varchar(20) not null, orderid bigint(20)   unsigned NOT NULL );
create table TransInfo1( id bigint primary key auto_increment, userid varchar(20) not null, orderid bigint(20)   unsigned NOT NULL );

yaml配置方式

#设置内置tomcat的启动端口号
server:
  port: 8080
mybatis:
  mapper-locations: classpath:mapper/*.xml
  type-aliases-package: com.kingspringboot.springboot.myProject.com.bean
#分库分表配置信息
spring:
  profiles:
    active: test-ev,jackdking,testbeanone
  main:
# sharding-jdbc定义了重复的dataSource数据源bean,启动时必须添加以下值
    allow-bean-definition-overriding: true
# sharding-jdbc 分库、分表配置
  shardingsphere:
    datasource:
      names: ds0,ds1
      ds0:
        type: com.alibaba.druid.pool.DruidDataSource

        url: jdbc:mysql://192.168.3.9:3306/myutilproject0?characterEncoding=GBK&useSSL=false
        username: jackdking
        password: ncl@1234
        driver-class-name: com.mysql.jdbc.Driver
      ds1:
        type: com.alibaba.druid.pool.DruidDataSource
        url: jdbc:mysql://192.168.3.9:3306/myutilproject1?characterEncoding=GBK&useSSL=false
        username: jackdking
        password: ncl@1234
        driver-class-name: com.mysql.jdbc.Driver
    sharding:
      tables:
        TransInfo:
          actual-data-nodes: ds$->{0..1}.TransInfo$->{0..1}
          table-strategy:
            inline:
              #分片规则对应列,即以user_id值作为分片规则的列
              sharding-column: orderid
              #分片按user_id列和10取模运算,路由到对应的order0...9的表
              algorithm-expression: TransInfo$->{orderid % 2}
          key-generator:
            column: id
            type: SNOWFLAKE
      default-database-strategy:
        inline:
          sharding-column: id
          algorithm-expression: ds$->{id % 2}
    props:
      sql.show: true      

1.首先设置mysql数据源,本项目有两个数据源,分别是ds0和ds1
2.设置分库策略,sharding-column: id 根据id来进行分库,algorithm-expression: ds$->{id % 2} 每条数据额id字段对2取模,取模后的数字与ds拼接在一起得到最终的数据源名称。
3.分表策略: 1) actual-data-nodes: ds$->{0..1}.TransInfo$->{0..1} 最终计算得到的最终物理表是 ds[0,1].TransInfo[0,1]
2) sharding-column: orderid 根据记录的orderid字段来进行分表
3) algorithm-expression: TransInfo$->{orderid % 2} 分表规则是orderid字段对2取模计算得到的余数拼接到TransInfo的后面即为最终的表名。

4. sharding-jdbc分库分表实例测试

除了mysql两个数据库和表的准备以及yaml的方式配置sharding-jdbc模块外,我的实例项目还提供了完整的测试代码,包括controller层,service层以及dao层。

controller层代码

alt

service层代码

alt

最重要的是DAO层的配置

alt

1.表名称不是物理表名称TransInfo0和TransInfo1,而是TransInfo。物理名称都会经过分库分表逻辑计算到。

2.插入语句的字段必须要有分库分表逻辑字段,一般这种分段逻辑字段都是不能为空的。

5. 轻量的sharding-jdbc在我目前工作项目的集成方案

支付中台系统用户表是一张oracle的单表,使用唯一索引的情况下,查询和更新性能是满足要求的,但是如果是高并发的情况,性能是完全不符合要求的,这时候大表性能就非常差了。

因此账户表这张大表就需要进行分库分表,而且每笔支付请求都要去查询校验账户的信息,因此账户表的访问量跟交易量是正相关的。一张大的单表在高并发场景下首先考虑的就是要分库分表,把访问压力拆分到不同的磁盘和数据库服务器。

目前订单交易表是经过了分表处理的,总共8张表,每张表也做了分区处理,按订单创建时间月份分区,但是交易表使用的还是oracle数据库。目前互联网公司分库分表的解决方案都倾向于使用mysql数据库。

8张表存放的是交易数据,这8张表只用于支付订单业务。对账,财务业务是不使用这8张交易表的,因为对账,财务业务等一些其他的支付交易之外的业务使用的是一张独立的订单数据表,这张表是一张进行分区的大表,主要用来给对账,财务等业务提供复杂的数据库操作,这些是分表的交易表无法提供的。对于订单数据的BI业务,我们还有另外一张查询表,同样这张表也存放一份交易数据,用于数据的操作。

用于业务处理的订单表和BI数据分析的订单表的数据都是和8张交易表中的数据是一样的。数据同步是以消息队列方式来处理的:交易表数据入库后,会发送数据的插入消息放到消息队列,消费端会将数据入库两张单表中。

通过冗余订单数据,创建多分订单表数据,将非核心业务与核心交易隔离开来。 alt

对于这样的数据库设计架构,我这把可以很方便的将交易表数据迁移到mysql数据库。

除了对交易表的数据迁移之外,现在消息队列目前还只是使用redis的list数据结构,不能保证消息的高可用和数据的表之间的数据一致性以及消息的不丢失。

关注共图社,有更多惊喜。


还要配置状态转移信息以及事件处理器逻辑的开发。完整的demo项目,请关注公众号“前沿科技bot“并发送"分库分表"获取。

alt

扫码或搜索:前沿科技
发送 290992
即可立即永久解锁本站全部文章