前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >springboot实战之mysql分库分表

springboot实战之mysql分库分表

作者头像
lyb-geek
发布2019-10-28 17:21:44
6.7K0
发布2019-10-28 17:21:44
举报
文章被收录于专栏:Linyb极客之路

什么是分库分表

把存于一个库的数据分散到多个库中,把存于一个表的数据分散到多个表中。如果说读写分离是为了分散数据库读写操作压力,分库分表就是为了分散存储压力

什么时候考虑切分

1、能不切分尽量不要切分

并不是所有表都需要进行切分,主要还是看数据的增长速度。切分后会在某种程度上提升业务的复杂度,数据库除了承载数据的存储和查询外,协助业务更好的实现需求也是其重要工作之一。

不到万不得已不用轻易使用分库分表这个大招,避免"过度设计"和"过早优化"。分库分表之前,不要为分而分,先尽力去做力所能及的事情,例如:升级硬件、升级网络、读写分离、索引优化等等。当数据量达到单表的瓶颈时候,再考虑分库分表。

2、数据量过大,正常运维影响业务访问

这里说的运维,指:

1)对数据库备份,如果单表太大,备份时需要大量的磁盘IO和网络IO。例如1T的数据,网络传输占50MB时候,需要20000秒才能传输完毕,整个过程的风险都是比较高的

2)对一个很大的表进行DDL修改时,MySQL会锁住全表,这个时间会很长,这段时间业务不能访问此表,影响很大。如果使用pt- online-schema-change,使用过程中会创建触发器和影子表,也需要很长的时间。在此操作过程中,都算为风险时间。将数据表拆分,总量减 少,有助于降低这个风险。

3)大表会经常访问与更新,就更有可能出现锁等待。将数据切分,用空间换时间,变相降低访问压力

3、随着业务发展,需要对某些字段垂直拆分

4、数据量快速增长

随着业务的快速发展,单表中的数据量会持续增长,当性能接近瓶颈时,就需要考虑水平切分,做分库分表了。此时一定要选择合适的切分规则,提前预估好数据容量

5、安全性和可用性

鸡蛋不要放在一个篮子里。在业务层面上垂直切分,将不相关的业务的数据库分隔,因为每个业务的数据量、访问量都不同,不能因为一个业务把数 据库搞挂而牵连到其他业务。利用水平切分,当一个数据库出现问题时,不会影响到100%的用户,每个库只承担业务的一部分数据,这样整体的可用性就能提高。

分库分表的方式

垂直切分

适用场景:如果是因为表的个数多而让数据多,可以按照功能划分,把联系密切的表切分出来放在同一个库中(分库);

垂直拆分是指,将一个属性较多,一行数据较大的表,将不同的属性拆分到不同的表中,以降低单库(表)大小,达到提升性能的目的的方法,垂直切分后,各个库(表)的特点是:

(1)每个库(表)的结构都不一样

(2)一般来说,每个库(表)的属性至少有一列交集,一般是主键

(3)所有库(表)的并集是全量数据

水平切分

适用场景:如果是因为表中的数据量过于庞大,则可以采用水平切分,按照某种约定好的规则将数据切分到不同的数据库中;

水平切分是指,以某个字段为依据(例如uid),按照一定规则(例如取模),将一个库(表)上的数据拆分到多个库(表)上,以降低单库(表)大小,达到提升性能的目的的方法,水平切分后,各个库(表)的特点是:

(1)每个库(表)的结构都一样

(2)每个库(表)的数据都不一样,没有交集

(3)所有库(表)的并集是全量数据

几种常用的分库分表的策略

1、HASH取模

假设有用户表user,将其分成3个表user0,user1,user2.路由规则是对3取模,当uid=1时,对应到的是user1,uid=2时,对应的是user2.

2、范围分片

从1-10000一个表,10001-20000一个表。

3、地理位置分片

华南区一个表,华北一个表。

4、时间分片

按月分片,按季度分片等等,可以做到冷热数据。

分库分表后引入的问题

分布式事务问题

如果我们做了垂直分库或者水平分库以后,就必然会涉及到跨库执行SQL的问题,这样就引发了互联网界的老大难问题-"分布式事务"。

那要如何解决这个问题呢?

  • 使用分布式事务中间件
  • 使用MySQL自带的针对跨库的事务一致性方案(XA),不过性能要比单库的慢10倍左右。
  • 能否避免掉跨库操作(比如将用户和商品放在同一个库中)

跨库join的问题

分库分表后表之间的关联操作将受到限制,我们无法join位于不同分库的表,也无法join分表粒度不同的表, 结果原本一次查询能够完成的业务,可能需要多次查询才能完成。

粗略的解决方法:

  • 全局表:基础数据,所有库都拷贝一份。
  • 字段冗余:这样有些字段就不用join去查询了。
  • 系统层组装:分别查询出所有,然后组装起来,较复杂。

横向扩容的问题

当我们使用HASH取模做分表的时候,针对数据量的递增,可能需要动态的增加表,此时就需要考虑因为reHash导致数据迁移的问题。

结果集合并、排序的问题

因为我们是将数据分散存储到不同的库、表里的,当我们查询指定数据列表时,数据来源于不同的子库或者子表,就必然会引发结果集合并、排序的问题。如果每次查询都需要排序、合并等操作,性能肯定会受非常大的影响。走缓存可能一条路!

分库分表实现方法

分库分表的实现主要有2种方案,第一种是代码层封装,比如使用Sharding-JDBC,本文的主要就是通过Sharding-JDBC来进行分库分表。第二种是通过中间件代理,比如使用mycat。

Sharding-JDBC分库分表

正常分库分表大部分都是先单库分表,再来分库分表,下面的例子也是遵循这个原则。另外例子的sharding-jdbc版本为

代码语言:javascript
复制
<sharding.boot.version>3.1.0</sharding.boot.version>

1、单库分表

a、表结构如下

代码语言:javascript
复制
DROP TABLE IF EXISTS `book_0`;

CREATE TABLE `book_0` (
  `id` bigint(20) NOT NULL,
  `book_name` varchar(200) DEFAULT NULL,
  `author` varchar(50) DEFAULT NULL,
  `description` varchar(500) DEFAULT NULL,
  `price` decimal(10,2) DEFAULT NULL,
  `stock` int(6) DEFAULT NULL,
  `update_date` datetime DEFAULT NULL,
  `create_date` datetime DEFAULT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

/*Table structure for table `book_1` */

DROP TABLE IF EXISTS `book_1`;

CREATE TABLE `book_1` (
  `id` bigint(20) NOT NULL,
  `book_name` varchar(200) DEFAULT NULL,
  `author` varchar(50) DEFAULT NULL,
  `description` varchar(500) DEFAULT NULL,
  `price` decimal(10,2) DEFAULT NULL,
  `stock` int(6) DEFAULT NULL,
  `update_date` datetime DEFAULT NULL,
  `create_date` datetime DEFAULT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

b、pom.xml

代码语言:javascript
复制
<dependencies>
        <dependency>
            <groupId>io.shardingsphere</groupId>
            <artifactId>sharding-jdbc-spring-boot-starter</artifactId>
        </dependency>
        <dependency>
            <groupId>com.github.dozermapper</groupId>
            <artifactId>dozer-core</artifactId>
        </dependency>
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>druid-spring-boot-starter</artifactId>
        </dependency>
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
        </dependency>
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>fastjson</artifactId>
        </dependency>
        <dependency>
            <groupId>org.slf4j</groupId>
            <artifactId>log4j-over-slf4j</artifactId>
        </dependency>

        <dependency>
            <groupId>com.baomidou</groupId>
            <artifactId>mybatis-plus-boot-starter</artifactId>
        </dependency>


    </dependencies>

c、application.yml 配置

代码语言:javascript
复制
sharding:
  jdbc:
    datasource:
      names: master-ds
      # 数据源master-ds
      master-ds:
        type: com.alibaba.druid.pool.DruidDataSource
        driver-class-name: com.mysql.cj.jdbc.Driver
        url: jdbc:mysql://localhost:3306/springboot-learning?allowMultiQueries=true&useUnicode=true&characterEncoding=UTF-8&useSSL=false&autoReconnect=true&serverTimezone=UTC
        username: root
        password: 123456
    config:
      sharding:
        props:
          sql.show: true
        tables:
          book:  #逻辑表名
            key-generator-column-name: id  #主键
            actual-data-nodes: master-ds.book_${0..1}   #物理表数据节点,均匀分布
            table-strategy:  #分表策略
              inline: #行表达式
                sharding-column: id
                algorithm-expression: book_${id % 2}  #按id模运算分配
spring:
  main:
    allow-bean-definition-overriding: true

仅需上面3步就可以实现一个单库分表方案,更多详细配置可以查看如下链接

https://shardingsphere.apache.org/document/current/cn/manual/sharding-jdbc/configuration/config-yaml/

2、分库分表

例子分库分表表结构和单库分表的表结构是一样的,仅仅只是又多了一个库。

分库分表其配置文件内容如下

代码语言:javascript
复制
sharding:
  jdbc:
    datasource:
      #Canonical names should be kebab-case ('-' separated), lowercase alpha-numeric characters and must start with a letter
      names: ds0,ds1
      ds0:
        type: com.alibaba.druid.pool.DruidDataSource
        driver-class-name: com.mysql.cj.jdbc.Driver
        url: jdbc:mysql://localhost:3306/boot-learning?allowMultiQueries=true&useUnicode=true&characterEncoding=UTF-8&useSSL=false&autoReconnect=true&serverTimezone=UTC
        username: root
        password: 123456
      ds1:
        type: com.alibaba.druid.pool.DruidDataSource
        driver-class-name: com.mysql.cj.jdbc.Driver
        url: jdbc:mysql://localhost:3306/springboot-learning?allowMultiQueries=true&useUnicode=true&characterEncoding=UTF-8&useSSL=false&autoReconnect=true&serverTimezone=UTC
        username: root
        password: 123456
    config:
      sharding:
        props:
          sql.show: true
        tables:
         book:
            key-generator-column-name: id  #主键
            actual-data-nodes: ds${0..1}.book_${0..1}    #数据节点,均匀分布
            database-strategy:   #分库策略
              inline: #行表达式
                sharding-column: id        #列名称,多个列以逗号分隔
                algorithm-expression: ds${id % 2}    #按id模运算分配
            table-strategy:  #分表策略
              inline: #行表达式
                sharding-column: stock
                algorithm-expression: book_${stock % 2}

spring:
  main:
    allow-bean-definition-overriding: true

同单库分表相比,通过sharding-jdbc进行分库分表,就配置文件内容不一样,其他sharding-jdbc底层都已经帮你实现好了。更多详细配置可以查看如下链接

https://shardingsphere.apache.org/document/current/cn/manual/sharding-jdbc/configuration/config-yaml/

总结

通过那个例子的整合,也许会给大家一个错觉,分库分表实现看起来也很简单啊,通过shariding-jdbc就可以快速实现,但事实上任何脱离业务的实现,都是纸上谈兵,上边的例子也只是一个简单的入门,具体分库分表方案,还得根据业务的复杂性来定。对于分库分表的一些介绍,大家也可以查看这篇文章浅谈高性能数据库集群 —— 分库分表

参考文档

一分钟掌握数据库垂直拆分

http://1t.click/azW4

数据库分库分表,何时分?怎样分?详细解读,一篇就够了

http://1t.click/azW9

MySQL分库分表原理

https://www.jianshu.com/p/7aec260ca1a2

demo链接

https://github.com/lyb-geek/springboot-learning/tree/master/springboot-split-table

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2019-10-27,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 Linyb极客之路 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 什么是分库分表
  • 什么时候考虑切分
  • 分库分表的方式
  • 几种常用的分库分表的策略
  • 分库分表后引入的问题
  • 分库分表实现方法
  • Sharding-JDBC分库分表
  • 总结
  • 参考文档
  • demo链接
相关产品与服务
云数据库 SQL Server
腾讯云数据库 SQL Server (TencentDB for SQL Server)是业界最常用的商用数据库之一,对基于 Windows 架构的应用程序具有完美的支持。TencentDB for SQL Server 拥有微软正版授权,可持续为用户提供最新的功能,避免未授权使用软件的风险。具有即开即用、稳定可靠、安全运行、弹性扩缩等特点。
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档