ShardingSphere分库分表入门实战学习

前置引入

随着互联网的飞速发展,传统的数据库服务器已经无法满足我们的需求,必须寻找其他办法,如数据库集群的方式去提系统性能。高性能数据库集群目前有两种架构模式:1. “读写分离"模式, 2. “数据库分片”模式。

读写分离架构


从上图可以看到,在数据库集群中,分为了主节点和众多从节点,对于业务服务器来说,读取数据一般与从节点进行交互,写数据的时候和主节点进行交互,主节点的数据更新之后,主节点与从节点之间会进行主从复制操作进行数据的同步。

问题
  • 数据一致性问题:当我们向数据库主节点写入一条数据,在主从节点之间数据还没有更新的时候,向从节点查询数据,这显然是无法查到的。这里涉及到了分布式系统中的CAP定理在一个分布式系统中,当涉及到读写操作时,只能保证一致性(Consistence),可用性(Availability),分区容错性(Partition tolerance)三者中的两个
    • Consistence:对某个指定的客户端来说,读操作保证能返回最新的结果(现实中无法完美实现)
    • Availability:非故障的节点在合理的时间内返回合理的响应
    • Partition tolerance:当出现网络分区(各个服务器之间的交互出现了问题,如丢包、连接中断等)之后,系统能继续正常工作
  • 分散了数据库的读写压力,但没有分散存储压力,解决办法就是数据分片,将数据分片后,存储到多台数据库服务器上,其实也就是我们常说的分库分表,一般分库分表的操作分为两种拆分方式:
    • 垂直拆分:
      • 垂直拆分之垂直分库
        垂直拆分的核心理念是专库专用,按照业务拆分的方式进行拆分,举个例子,假设现在数据库中有几张表:分别是用户数据表,订单 表,商品数据表,拆分前这些表都是在同一个数据库中的,而拆分后,这些数据都被分到了不同的数据库中,如下所示是三个不同的数据库。
        在这里插入图片描述
        这种拆分方式可以缓解数据量和访问量带来的问题,这种方式还是无法解决单表数据过于庞大的情况,此时就需要用到水平分片了。
      • 垂直拆分之垂直分表
        垂直分表将以前的表中,一些不常用的列,或者是占用了大量空间的列进行拆分。举个栗子,假设一个婚恋网站,现在用户信息的字段有name、age、sex、nickName、description这些字段,而在网站搜索用户信息的时候,一般都是展示name、age、sex这几个字段信息,后面两个字段一般不进行展示,那此时我们就可以单独将name、age、sex作为一张表,nickName、description作为另外一张表。
    • 水平分片
      • 水平分片之水平分库
        如果单个表拆分为多个表之后,单台服务器依然无法满足性能要求,那就需要将表分散在不同的数据库服务器中
      • 水平分片之水平分表
        根据阿里巴巴的规范,当一个表中行数超过500w或容量超过2GB,就推荐进行分表操作了

ShardingSphere

简介:Apache ShardingSphere是一款开源分布式数据库生态项目,旨在碎片化的异构数据库上层构建生态,在最大限度的复用数据库原生存算能力的前提下,进一步提供面向全局的扩展和叠加计算能力。其核心采用可插拔架构,对上以数据库协议及SQL方式提供诸多增强功能,包括数据分片、访问路由、数据安全等。

ShardingSphere-JDBC

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

  1. Mysql集群的安装(基于Centos7和docker)读写分离的测试
  • 在docker中创建并启动MySQL主服务器,端口3307
    这里前提是已经下载好了centos和docker,以及mysql的镜像,这里我就不演示安装了。
    在这里插入图片描述
    我的mysql镜像是mysql:8.0.26,我根据这个镜像创建容器。

    docker run -d \    
    -p 3307:3306 \
    -v /home/docker/software/mysql/master/conf:/etc/mysql/conf.d \
    -v /home/docker/software/mysql/master/data:/var/lib/mysql \
    -e MYSQL_ROOT_PASSWORD=123456 \
    --name mysql-master \
    mysql:8.0.26
    

    -d标识mysql容器以守护线程的方式创建,-p 3307:3306表示将宿主机的3307端口映射到docker的3306端口,下面两个-v是进行配置文件的映射,-e是设置MySQL的密码,-name给容器取名字。
    在这里插入图片描述
    执行成功后,可以看到容器已经运行成功!

  • 切换至/home/docker/software/mysql/master/conf下,创建my.conf文件,文件内容如下

    [mysqld]
    #服务器唯一id
    server-id=1
    #设置日志格式,默认row
    binlog-format=STATEMENT
    

    保存后重启容器,docker restart mysql-master

  • 进入mysql-master容器中,使用命令行登录主服务器

    #进入容器内部
    docker exec -it mysql-master env lANG=C.UTF-8 /bin/bash
    #进入容器内的mysql命令行
    mysql -u root -p 123456
    #修改默认密码校验方式
    ALTER USER 'root'@'%' IDENTIFIED WITH mysql_native_password BY '123456';
    
  • 设置mysql的主节点服务器
    在主从同步的时候,从服务器会开一个io线程向主服务器中读取binlog日志,因此我们要在主节点中开一个账号给从节点,以访问主节点,下面是具体的命令:

    # 创建slave用户
    CREATE USER ’slave‘@’%‘;
    # 设置密码
    ALTER USER ’slave‘@’%' IDENTIFIED WITH mysql_native_password BY '123456';
    # 授予复制权限
    GRANT REPLICATION SLAVE ON *.* TO ’slave‘@’%‘;
    # 刷新权限
    FLUSH PRIVILEGES;
    
  • 安装从节点服务器

    • 创建容器,端口为3308

      docker run -d \
      -p 3308:3306 \
      -v /home/docker/software/mysql/slave/conf:/etc/mysql/conf.d \
      -v /home/docker/software/mysql/slave/data:/var/lib/mysql \
      -e MYSQL_ROOT_PASSWORD=123456 \
      --name mysql-slave01 \
      mysql:8.0.26
      
    • 创建slave01的配置文件
      进入 /home/docker/software/mysql/slave/conf创建my.conf文件,文件内容如下:

      [mysqld]
      #服务器唯一id
      server-id=2
      
    • 重启slave节点

      docker restart mysql-slave01
      
    • 进入容器内部,配置密码等,和主节点的操作一样,这里省略了。。。

    • 在从节点上配置主从关系
      在这里插入图片描述

      # 在主节点的mysql控制台输入show master status 查看binlog的名字,以及偏移量position,填在下面
      # slave是在主节点上为从节点创建的账号,上面已经创建了,主节点的端口是3307
      CHANGE MASTER TO MASTER_HOST='192.168.101.65',
      MASTER_USER='slave',MASTER_PASSWORD='123456',MASTER_PORT=3307,
      MASTER_LOG_FILE='binlog.ooo003',MASTER_LOG_POS=1332;
      
    • 安装slave02,步骤和安装01一样,注意命名和端口即可
      例如:

      docker run -d \
      -p 3309:3306 \
      -v /home/docker/software/mysql/slave2/conf:/etc/mysql/conf.d \
      -v /home/docker/software/mysql/slave2/data:/var/lib/mysql \
      -e MYSQL_ROOT_PASSWORD=123456 \
      --name mysql-slave02 \
      mysql:8.0.26
      

      当我们安装好一台主节点master和两台从节点slave01和slave02,并开启主从复制后,我们在主节点的任何操作,都会同步到所有从节点上。大家可以自己尝试操作一下!

  1. 水平分片

    2.1 需求
    现在我们的需求就是,订单数据在两台数据库服务器的数据库db_order中,我们在向数据库插入数据的时候,要实现根据不同的算法,分别插入到这两个数据库服务器不同的订单表(t_order)中。以下是具体的操作。

    2.2 具体执行过程
    先使用docker创建两个mysql容器,具体步骤上面有,名字分别为server-order0,server-order1,创建完成之后,分别在这两个数据库服务器中执行一下sql命令:

    CREATE DATABASE db_order;
    
    USE db_order;
    
    CREATE TABLE t_order0 (
      id BIGINT,
      order_no VARCHAR(30),
      user_id BIGINT,
      amount DECIMAL(10,2),
      PRIMARY KEY(id) 
    );
    
    CREATE TABLE t_order1 (
      id BIGINT,
      order_no VARCHAR(30),
      user_id BIGINT,
      amount DECIMAL(10,2),
      PRIMARY KEY(id) 
    );
    

    现在server-order0和server-order1的服务器中有了一个名为db_order的数据库,且包含两张表t_order0和t_order1
    在这里插入图片描述

    2.3 shardingsphere配置文件编写

    #-----------------------------------------基本配置
    # 应用名称
    spring.application.name=sharding-jdbc-demo
    # 开发环境设置
    spring.profiles.active=dev
    # 内存模式
    spring.shardingsphere.mode.type=Memory
    
    # 打印SQl
    spring.shardingsphere.props.sql-show=true
    #-----------------------------------------数据源配置
    
    # 配置真实数据源
    spring.shardingsphere.datasource.names=master,server-order0,server-order1
    
    # 配置第1个数据源
    spring.shardingsphere.datasource.master.type=com.zaxxer.hikari.HikariDataSource
    spring.shardingsphere.datasource.master.driver-class-name=com.mysql.cj.jdbc.Driver
    spring.shardingsphere.datasource.master.jdbc-url=jdbc:mysql://192.168.101.65:3307/db_user?serverTimezone=Asia/Shanghai&useUnicode=true&characterEncoding=utf-8&zeroDateTimeBehavior=convertToNull&useSSL=false&allowPublicKeyRetrieval=true
    spring.shardingsphere.datasource.master.username=root
    spring.shardingsphere.datasource.master.password=123456
    
    # 配置第2个数据源
    spring.shardingsphere.datasource.server-order0.type=com.zaxxer.hikari.HikariDataSource
    spring.shardingsphere.datasource.server-order0.driver-class-name=com.mysql.cj.jdbc.Driver
    spring.shardingsphere.datasource.server-order0.jdbc-url=jdbc:mysql://192.168.101.65:3310/db_order?serverTimezone=Asia/Shanghai&useUnicode=true&characterEncoding=utf-8&zeroDateTimeBehavior=convertToNull&useSSL=false&allowPublicKeyRetrieval=true
    spring.shardingsphere.datasource.server-order0.username=root
    spring.shardingsphere.datasource.server-order0.password=123456
    
    # 配置第3个数据源
    spring.shardingsphere.datasource.server-order1.type=com.zaxxer.hikari.HikariDataSource
    spring.shardingsphere.datasource.server-order1.driver-class-name=com.mysql.cj.jdbc.Driver
    spring.shardingsphere.datasource.server-order1.jdbc-url=jdbc:mysql://192.168.101.65:3311/db_order?serverTimezone=Asia/Shanghai&useUnicode=true&characterEncoding=utf-8&zeroDateTimeBehavior=convertToNull&useSSL=false&allowPublicKeyRetrieval=true
    spring.shardingsphere.datasource.server-order1.username=root
    spring.shardingsphere.datasource.server-order1.password=123456
    
    #-----------------------------------------标准分片配置
    spring.shardingsphere.rules.sharding.tables.t_user.actual-data-nodes=master.t_user
    spring.shardingsphere.rules.sharding.tables.t_order.actual-data-nodes=server-order$->{0..1}.t-order0
    
    #------------------------分库策略
    # 分片列名称
    spring.shardingsphere.rules.sharding.tables.t_order.database-strategy.standard.sharding-column=user_id
    # 分片算法名称
    spring.shardingsphere.rules.sharding.tables.t_order.database-strategy.standard.sharding-algorithm-name=alg_inline_userid
    #------------------------分片算法配置
    # 分片算法类型
    spring.shardingsphere.rules.sharding.sharding-algorithms.alg_inline_userid.type=INLINE
    # 分片算法属性配置
    spring.shardingsphere.rules.sharding.sharding-algorithms.alg_inline_userid.props.algorithm-expression=server-order$->{user_id % 2}
    

    在上述配置文件中,我们配置了三个数据源,分别是master,server-order0,server-order1,在标准分片配置注释下面,我们配置了真实的数据节点,server-order$->{0..1}.t-order0使用了行表达式,拆开看就是server-order0.t-order0,server-order1.t-order0,这样2个,分别对应数据源的不同表。在分片算法配置中,选择的分片算法为INLINE,这种类型支持我们自定义分片算法,spring.shardingsphere.rules.sharding.sharding-algorithms.alg_inline_userid.props.algorithm-expression=server-order$->{user_id % 2}这行代码代表的是,当插入数据的user_id为偶数的时候,就插入数据源server-order0中的t-order0中,当user_id为奇数的时候,就插入数据源server-order1中的t-order0中。
    2.4 测试代码编写

    @Test
        public void testOrderInsert() {
            for (long i = 1; i < 5; i++) {
                Order order = new Order();
                order.setOrderNo("Sharding" + i);
                order.setUserId(i);
                order.setAmount(new BigDecimal(100));
                orderMapper.insert(order);
            }
        }
    

    在你的springboot测试类中加入上面的方法,并运行,最后的结果如下,user_id为偶数时,数据插入到server-order0中,反之插入到server-order1中
    在这里插入图片描述
    在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值