MySQL分库分表详解

随着业务的规模不断扩大,数据量的成倍增长,查询效率越来越低,单个数据库已经不足以支撑大量并发请求,严重甚至导致服务器宕机,这个时候我们就需要做些优化了

主要从以下几个方面优化数据库:

  • 业务拆分
  • 读写分离
  • 数据库分库与分表

 业务拆分

对于电商项目,会包含用户、商品、订单、仓库等模块,项目初期我们可能是放在同一个数据库来存储的扩大,单库压力非常大,这个时候我们可以根据业务拆分为多个数据库,这样系统的吞吐量大大提升。,但是随着规模

如下图:

主从复制,读写分离

数据库写入效率要低于读取效率,一般系统中数据读取频率高于写入频率,单个数据库实例在写入的时候会影响读取性能,这是做读写分离的原因。
实现方式主要基于MySQL的主从复制,通过路由的方式使应用对数据库的写请求只在master上进行,读请求在slave上进行。

主从复制怎么配置

同步原理:Mysql服务器之间的主从同步是基于二进制日志机制,主服务器使用二进制日志来记录数据库的变动情况,从服务器通过读取和执行该日志文件来保持和主服务器的数据一致。

有很多种配置主从同步的方法,可以总结为如下的步骤:

  1. 在主服务器上,必须开启二进制日志机制和配置一个独立的ID
  2. 在每一个从服务器上,配置一个唯一的ID,创建一个用来专门复制主服务器数据的账号
  3. 在开始复制进程前,在主服务器上记录二进制文件的位置信息
  4. 如果在开始复制之前,数据库中已经有数据,就必须先创建一个数据快照(可以使用mysqldump导出数据库,或者直接复制数据文件)
  5. 配置从服务器要连接的主服务器的IP地址和登陆授权,二进制日志文件名和位置

具体步骤:https://blog.csdn.net/qq_38727626/article/details/82632649

读写分离代码实现

思路:之前在做项目的时候实现过mybatis数据源的动态切换。基于原来的方案,用aop来拦截dao层方法,根据方法名称就可以判断要执行的sql类型,动态切换主从数据源。

数据源动态切换可以看这里:https://blog.csdn.net/qq_43037478/article/details/109648880

aop实现

/**
 * 数据源切换类
 */
@Aspect
@Component
public class DataSourceAspect {
    private static final Logger logger = LoggerFactory.getLogger(DataSourceAspect.class);
    private static final String[] queryStrs = {"query", "select", "get"};

    /**
     * 定义切入点,切入点为com.angla.demo.dao下的所有方法
     */
    @Pointcut("execution(* com.xiateng.dao.*(..))")
    public void executeSql(){}

    @Before("executeSql()")
    public void doBefore(JoinPoint joinPoint){
        MethodSignature methodSignature = (MethodSignature) joinPoint.getSignature();
        String mName = methodSignature.getMethod().getName();
        logger.info("拦截sql方法:{}", mName);
        // 默认设置pre为Master
        DataSourceContext.setDataSource(StaticConst.DATA_SOURCE_MASTER);
        for (String name : queryStrs) {
            if (mName.startsWith(name)) {
                logger.info("查询语句,设置数据源为slave");
                DataSourceContext.setDataSource(StaticConst.DATA_SOURCE_SLAVE);
                break;
            }
        }
        logger.info("当前数据源:{}",DataSourceContext.getDataSource());
    }
}

分库分表

1、分表

垂直拆分

概念:以 字段为依据,按照字段的活跃性,将 中字段拆到不同的 (主表和扩展表)中。

结果:

  • 每个 的 结构都不一样;
  • 每个 的 数据也不一样,一般来说,每个表的 字段至少有一列交集,一般是主键,用于关联数据;
  • 所有 的 并集是全量数据;

场景:系统绝对并发量并没有上来,表的记录并不多,但是字段多,并且热点数据和非热点数据在一起,单行数据所需的存储空间较大。以至于数据库缓存的数据行减少,查询时会去读磁盘数据产生大量的随机读IO,产生IO瓶颈。

分析:可以用列表页和详情页来帮助理解。垂直分表的拆分原则是将热点数据(可能会冗余经常一起查询的数据)放在一起作为主表,非热点数据放在一起作为扩展表。这样更多的热点数据就能被缓存下来,进而减少了随机读IO。拆了之后,要想获得全部数据就需要关联两个表来取数据。但记住,千万别用join,因为join不仅会增加CPU负担并且会讲两个表耦合在一起(必须在一个数据库实例上)。关联数据,应该在业务Service层做文章,分别获取主表和扩展表数据然后用关联字段关联得到全部数据。

水平拆分

概念:以 字段为依据 ,按照一定策略(hash、range等),将一个 中的数据拆分到多个 

结果:

  • 每个 的 结构都一样;
  • 每个 的 数据都不一样,没有交集;
  • 所有 的 并集是全量数据;

场景:系统绝对并发量并没有上来,只是单表的数据量太多,影响了SQL效率,加重了CPU负担,以至于成为瓶颈。

分析:表的数据量少了,单次SQL执行效率高,自然减轻了CPU的负担。

2、分库

水平分库

概念:以 字段为依据 ,按照一定策略(hash、range等),将一个 中的数据拆分到多个 中。

结果:

  • 每个 的 结构都一样;
  • 每个 的 数据都不一样,没有交集;
  • 所有 的 并集是全量数据;

场景:系统绝对并发量上来了,分表难以根本上解决问题,并且还没有明显的业务归属来垂直分库。

分析:库多了,io和cpu的压力自然可以成倍缓解。

垂直分库

概念:以 为依据,按照业务归属不同,将不同的 拆分到不同的 中 。

结果:

  • 每个 的 结构都不一样;
  • 每个 的 数据也不一样,没有交集;
  • 所有 的 并集是全量数据;

场景:系统绝对并发量上来了,并且可以抽象出单独的业务模块。

分析:到这一步,基本上就可以服务化了。例如,随着业务的发展一些公用的配置表、字典表等越来越多,这时可以将这些表拆到单独的库中,甚至可以服务化。再有,随着业务的发展孵化出了一套业务模式,这时可以将相关的表拆到单独的库中,甚至可以服务化。

分库分表工具

sharding-sphere:jar,前身是sharding-jdbc;

TDDL:jar,Taobao Distribute Data Layer;

Mycat:中间件。

分库分表步骤

根据容量(当前容量和增长量)评估分库或分表个数 -> 选key(均匀)-> 分表规则(hash或range等)-> 执行(一般双写)-> 扩容问题(尽量减少数据的移动)。

 

 

 

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值