死磕数据库系列(十二):MySQL 分库分表(何时分?怎么分?)

刚开始我们只用单机数据库就够了,随后面对越来越多的请求,我们将数据库的写操作和读操作进行分离, 使用多个从库副本(Slaver Replication)负责读,使用主库(Master)负责写, 从库从主库同步更新数据,保持数据一致。架构上就是数据库主从同步。 从库可以水平扩展,所以更多的读请求不成问题。

但是当用户量级上来后,写请求越来越多,该怎么办?加一个Master是不能解决问题的,因为数据要保存一致性,写操作需要 2 个 master 之间同步,相当于是重复了,而且更加复杂。

上一期我们学习了:,在正式介绍分库分表之前,我们需要了解一下数据库的性能瓶颈在哪?

数据库瓶颈

不管是 IO 瓶颈还是 CPU 瓶颈,终都会导致数据库的活跃连接数增加,进而逼近甚至达到数据库可承载的活跃连接数的阈值。在业务 service 来看,

就是可用数据库连接少甚至无连接可用,接下来就可以想象了(并发量、吞吐量、崩溃)。

IO 瓶颈

  • 种:磁盘读IO瓶颈,热点数据太多,数据库缓存放不下,每次查询会产生大量的IO,降低查询速度->分库和垂直分表
  • 第二种:网络IO瓶颈,请求的数据太多,网络带宽不够 ->分库

CPU 瓶颈

  • 种:SQl问题:如SQL中包含join,group by, order by,非索引字段条件查询等,增加CPU运算的操作->SQL优化,建立合适的索引,在业务Service层进行业务计算。
  • 第二种:单表数据量太大,查询时扫描的行太多,SQl效率低,增加CPU运算的操作。->水平分表。

什么时候考虑分库分表

能不分就不分

并不是所有表都需要切分,主要还是看数据的增长速度。切分后在某种程度上提升了业务的复杂程度。不到万不得已不要轻易使用分库分表这个“大招”,避免“过度设计”和“过早优化”。分库分表之前,先尽力做力所能及的优化:升级硬件、升级网络、读写分离、索引优化等。当数据量达到单表瓶颈后,在考虑分库分表。

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

这里说的运维,指:

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

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

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

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

举个例子,假如项目一开始设计的用户表如下:

id                  bigint     #用户的IDname                varchar    #用户的名字last_login_time     datetime   #近登录时间personal_info       text       #私人信息.....                          #其他信息字段