• java八股文面试[数据库]——分库分表


    什么是分库分表

    简单来说,就是指通过某种特定的条件,将我们存放在同一个数据库中的数据分散存放到多个数据库(主机)上面,以达到分散单台设备负载的效果。

    image.png

    • 分库分表解决的问题

      分库分表的目的是为了解决由于数据量过大而导致数据库性能降低的问题,将原来单体服务的数据库进行拆分.将数据大表拆分成若干数据表组成,使得单一数据库、单一数据表的数据量变小,从而达到提升数据库性能的目的。

    • 什么情况下需要分库分表
      • 单机存储容量遇到瓶颈.

      • 连接数,处理能力达到上限.

    注意:

    分库分表之前,要根据项目的实际情况 确定我们的数据量是不是够大,并发量是不是够大,来决定是否分库分表.

    数据量不够就不要分表,单表数据量超过1000万或100G的时候, 速度就会变慢(官方测试),

    分库分表包括: 垂直分库、垂直分表、水平分库、水平分表 四种方式。
    垂直分库
    • 数据库中不同的表对应着不同的业务,垂直切分是指按照业务的不同将表进行分类,分布到不同的数据库上面

      • 数据库部署在不同服务器上,从而达到多个服务器共同分摊压力的效果

      image.png

    垂直分表

    表中字段太多包含大字段的时候,在查询时对数据库的IO、内存会受到影响,同时更新数据时,产生的binlog文件会很大,MySQL在主从同步时也会有延迟的风险

    • 将一个表按照字段分成多表,每个表存储其中一部分字段

    • 对职位表进行垂直拆分, 将职位基本信息放在一张表, 将职位描述信息存放在另一张表

    image.png

    • 垂直拆分带来的一些提升

      • 解决业务层面的耦合,业务清晰

      • 能对不同业务的数据进行分级管理、维护、监控、扩展等

      • 高并发场景下,垂直分库一定程度的提高访问性能

    • 垂直拆分没有彻底解决单表数据量过大的问题

    水平分库
    • 将单张表的数据切分到多个服务器上去,每个服务器具有相应的库与表,只是表中数据集合不同。 水平分库分表能够有效的缓解单机和单库的性能瓶颈和压力,突破IO连接数硬件资源等的瓶颈.

    • 简单讲就是根据表中的数据的逻辑关系,将同一个表中的数据按照某种条件拆分到多台数据库(主机)上面, 例如将订单表 按照id是奇数还是偶数, 分别存储在不同的库中。

      image.png

    水平分表
    • 针对数据量巨大的单张表(比如订单表),按照规则把一张表的数据切分到多张表里面去。 但是这些表还是在同一个库中,所以库级别的数据库操作还是有IO瓶颈。

      image.png

    • 总结

      • 垂直分表: 将一个表按照字段分成多表,每个表存储其中一部分字段。

      • 垂直分库: 根据表的业务不同,分别存放在不同的库中,这些库分别部署在不同的服务器.

      • 水平分库: 把一张表的数据按照一定规则,分配到不同的数据库,每一个库只有这张表的部分数据.

      • 水平分表: 把一张表的数据按照一定规则,分配到同一个数据库的多张表中,每个表只有这个表的部分数据.

    水平分库分表策略

    分库分表策略一般有几种,使用与不同的场景:

    • range范围

    • hash取模

    • range+hash取模混合

    1 range范围

    range,即范围策略划分表。比如我们可以将表的主键,按照从0~1000万的划分为一个表,1000~2000万划分到另外一个表。如下图:

    图片

    当然,有时候我们也可以按时间范围来划分,如不同年月的订单放到不同的表,它也是一种range的划分策略。

    这种方案的优点:

    • 这种方案有利于扩容不需要数据迁移。假设数据量增加到5千万,我们只需要水平增加一张表就好啦,之前0~4000万的数据,不需要迁移。

    缺点:

    • 这种方案会有热点问题,因为订单id是一直在增大的,也就是说最近一段时间都是汇聚在一张表里面的。比如最近一个月的订单都在1000万~2000万之间,平时用户一般都查最近一个月的订单比较多,请求都打到order_1表啦,这就导致表的数据热点问题。

    2 hash取模

    hash取模策略:指定的路由key(一般是user_id、订单id作为key)对分表总数进行取模,把数据分散到各个表中。

    比如原始订单表信息,我们把它分成4张分表:

    图片

    • 比如id=1,对4取模,就会得到1,就把它放到第1张表,即t_order_0;

    • id=3,对4取模,就会得到3,就把它放到第3张表,即t_order_2;

    这种方案的优点:

    • hash取模的方式,不会存在明显的热点问题。

    缺点:

    • 如果一开始按照hash取模分成4个表了,未来某个时候,表数据量又到瓶颈了需要扩容,这就比较棘手了。比如你从4张表,又扩容成8张表,那之前id=5的数据是在(5%4=1,即第一张表),现在应该放到(5%8=5,即第5张表),也就是说历史数据要做迁移了

    3 range+hash取模混合

    既然range存在热点数据问题,hash取模扩容迁移数据比较困难,我们可以综合两种方案一起嘛,取之之长,弃之之短。

    比较简单的做法就是,在拆分库的时候,我们可以先用range范围方案,比如订单id在04000万的区间,划分为订单库1,id在4000万8000万的数据,划分到订单库2,将来要扩容时,id在8000万~1.2亿的数据,划分到订单库3。然后订单库内,再用hash取模的策略,把不同订单划分到不同的表。

    图片

    分库分表会导致哪些问题

    分库分表之后,也会存在一些问题:

    • 事务问题

    • 跨库关联

    • 排序问题

    • 分页问题

    • 分布式ID

    1 事务问题

    分库分表后,假设两个表在不同的数据库,那么本地事务已经无效啦,需要使用分布式事务了。

    2 跨库关联

    跨节点Join的问题:解决这一问题可以分两次查询实现

    3 排序问题

    跨节点的count,order by,group by以及聚合函数等问题:可以分别在各个节点上得到结果后在应用程序端进行合并。

    4 分页问题

    • 方案1:在个节点查到对应结果后,在代码端汇聚再分页

    • 方案2:把分页交给前端,前端传来pageSize和pageNo,在各个数据库节点都执行分页,然后汇聚总数量前端。这样缺点就是会造成空查,如果分页需要排序,也不好搞。

    5 分布式ID

    据库被切分后,不能再依赖数据库自身的主键生成机制啦,最简单可以考虑UUID,或者使用雪花算法生成分布式ID。

    分库分表中间件

    目前流行的分库分表中间件比较多:

    • cobar

    • Mycat

    • Sharding-JDBC

    • Atlas

    • TDDL(淘宝)

    • vitess

    图片

    知识来源:马士兵教育

    12张图把分库分表讲的明明白白!

  • 相关阅读:
    docker提交镜像到阿里ack整体流程
    Nginx搭配负载均衡和动静分离:构建高性能Web应用的完美组合
    自动控制原理8.2---常见非线性特性及其对系统运动的影响
    LeetCode知识点总结 - 376
    hadoop 编写开启关闭集群脚本, hadoop hdfs,yarn开启关闭脚本。傻瓜式hadoop脚本 hadoop(九)
    基于改进莱维飞行和混沌映射的粒子群优化BP神经网络预测股票价格研究(Matlab代码实现)
    Spring Boot的魔法:构建高性能Java应用
    7.过拟合和正则化
    戏说领域驱动设计(二十)——值对象
    .NET Emit 入门教程:第一部分:Emit 介绍
  • 原文地址:https://blog.csdn.net/u200814342A/article/details/132741779