前两篇文章重点讲到了Mysql数据库的主从同步和读写分离,使用主从同步实现从数据库从主数据同步数据保持主从数据一致性,读写分离使用主数据库负责写操作,多个从数据库负责读操作,由于从库可以进行拓展,所以处理更多的读请求也没问题。但是如果业务比较多,写请求越来越多要如何处理呢?可能有人说我可以再加一个master分担写操作,但是两个master数据肯定是需要同步的,主主同步 + 主从同步很显然会让我们的系统架构变得更为的复杂。所以本篇文章主要讨论一个对写操作进行切分的技术:分库分表。
我们都知道,在业务量不多的时候,单库单表完全可以支持我们的应用。但是随着业务的逐渐发展,如果使用单库单表是存在几个弊端的:
而分库分表的方式一般有两种:垂直拆分和水平拆分。接下来我们可以分别看看这两种分库分表方式:
垂直拆分
垂直拆分主要有两种:垂直分库和垂直分表。
垂直分库:
垂直分库其实逻辑上会更容易理解,比如目前我数据库有用户相关的表如用户表,积分表,实名认证表,还有订单相关的比如商品表,拼团表,还有商品相关的商品表。如果全部表全部放在同一个数据库,由于数据库连接的匮乏以及磁盘IO等影响,所以性能肯定会收到一定的影响。这时候我们可以可以将用户相关的放在user数据库,商品相关的放在goods数据库,订单相关的放在order数据库。然后不同的数据库存放在不同的服务器上,这样还可以避免因为用户量越来越多导致数据库性能受到服务器瓶颈的影响。所以说分库实际上就是在多个服务器搭建多个不同的数据库,然后按照不同的业务逻辑将不同的表存放在不同的数据库。
垂直分表:
垂直分表主要是表中数据列成百上千的数据表使用的,使用的方案是创建辅助表,将表中数据量较大或者不常用的数据库移动到辅助表,常用的字段留在原表中,这样就可以避免我们在查询大表的时候由于不常用的大字段影响查询的性能。
水平拆分
水平拆分也有两种:水平分表和水平分库分表。
水平分表:
水平分表和垂直分表区别在于垂直分表针对的是列,将不常用的列拆分到辅助表。而水平分表针对的是表,在同一个数据库中创建多张一样的表,比如我们在order数据库中创建三张订单表order1,order2,order3,然后插入订单时将id对3取余,根据不同的值存入不同的订单表,但是由于水平分表是将数据表存放在同一个数据库,水平分表可以降低单标的数据量,有助于提高查询效率。如果业务量很大一样会受到服务器IO的瓶颈,所以我们一般更经常使用的还是水平分库分表。
水平分库分表:
水平分库分表实际上就是在多台不同的机器分别创建数据库和数据表,比如订单表我们可以在三台不同的机器上分别创建order数据库和order数据表,然后根据一定的逻辑将不同的数据存放到不同机器的数据库中。一般来说水平分库分表主要有以下几种拆分规则:
分区
分区是什么意思呢?分区实际上是指同一个数据表中不同行的数据记录到不同的分区中,每个分区都有一个.idb文件,所以说分区可以帮助我们将一个数据表拆分成几个更小的部分。Mysql只支持局部索引分区不支持全局分区,mysql每一个分区既保存了数据,又存放了索引。MySQL分区主要分为以下几种:
分区注意点
分区主要注意一点,如果要分区的表有主键或唯一键,则分区表的主键/唯一键必须包含分区键。分区的意义在于将一张大表根据分区条件分割成几个小表,但是对于数据来说仍然是一张表,可以改善大表的可伸缩性,可管理性,还可以提高数据库的效率。
分区的优点
分库分表产生的问题
分库分表可以一定程度去除数据库的瓶颈,但是不可避免的分库分表会带来一部分问题,分库分表主要有两个问题:联表查询join操作困难和分布式事务的问题。
联表查询
我们一开始单库多表的情况下使用join联表操作是非常简单的,使用一条简单的sql语句配上join就可以得到我们需要的结果,但是分库之后我们可能一次查询无法完成,我们可能需要先去服务器a查询用户信息,再去服务器b, c, d分别查询订单信息才能完成我们的联表查询功能,联表查询功能我觉得比较适合的一个逻辑是分别查询出我们需要的数据,然后代码方面在service层负责组装所有数据,最后再返还给客户端,这样虽然比较复杂,但是数据库的性能可以得到最大化。
分布式事务
进行分库操作之后,事务操作就变成分布式事务了,而之前在谈Redis的时候特提到过分布式,我们都知道涉及到分布式逻辑都是比较复杂的,而且如果使用Mysql自带的分布式事务管理功能会导致性能大大降低,大概是单库的一成左右性能,所以方案一般有两种:使用分布式事务中间件比如Mycat或者在代码中业务逻辑进行控制,不过如果在代码中控制,可能会使系统更加复杂,可维护性比较低。