目录
一、可能遇到的问题
1.系统正在持续不断地发展,注册的用户越来越多,产生的订单越来越多,数据库中存储的数据也越来越多,单个表的数据量超过了千万甚至到了亿级别。这时即使你使用了索引,索引占用的空间也随着数据量的增长而增大,数据库就无法缓存全量的索引信息,那么就需要从磁盘上读取索引数据,就会影响到查询的性能了。那么这时你要如何提升查询性能呢?
2.数据量的增加也占据了磁盘的空间,数据库在备份和恢复的时间变长,你如何让数据库系统支持如此大的数据量呢?
3.不同模块的数据,比如用户数据和用户关系数据,全都存储在一个主库中,一旦主库发生故障,所有的模块都会受到影响,那么如何做到不同模块的故障隔离呢?
4.你已经知道了,在4核8G的云服务器上对MySQL 5.7做Benchmark,大概可以支撑500TPS和10000QPS,你可以看到数据库对于写入性能要弱于数据查询的能力,那么随着系统写入请求量的增长,数据库系统如何来处理更高的并发写入请求呢?
数据库的写入请求量大造成的性能和可用性方面的问题,常见的一种方式是对数据库做分库分表。
二、如何对数据库做垂直拆分
分库分表是一种常见的将数据分片的方式,它的基本思想是依照某一种策略将数据尽量平均地分配到多个数据库节点或者多个表中。分库分表后,每个节点只保存部分的数据,这样可以有效地减少单个数据库节点和单个数据表中存储的数据量,在解决了数据存储瓶颈的同时也能有效地提升数据查询的性能。同时,因为数据被分配到多个数据库节点上,那么数据的写入请求也从请求单一主库变成了请求多个数据分片节点,在一定程度上也会提升并发写入的性能。
垂直拆分,顾名思义就是对数据库竖着拆分,也就是将数据库的表拆分到多个不同的数据库中。
一般是按照业务类型来拆分,核心思想是专库专用,将业务耦合度比较高的表拆分到单独的库中。举个形象的例子,就是在整理衣服的时候,将羽绒服、毛衣、T恤分别放在不同的格子里。把不同的业务的数据分拆到不同的数据库节点上,这样一旦数据库发生故障时只会影响到某一个模块的功能,不会影响到整体功能,从而实现了数据层面的故障隔离。
拆分之后,虽然可以暂时缓解存储容量的瓶颈,但并不是万事大吉,因为数据库垂直拆分后依然不能解决某一个业务模块的数据大量膨胀的问题,一旦你的系统遭遇某一个业务库的数据量暴增,在这个情况下,你还需要继续寻找可以弥补的方式。
三、如何对数据库做水平拆分
水平拆分指的是将单一数据表按照某一种规则拆分到多个数据库和多个数据表中
拆分的规则有下面这两种:
1.按照某一个字段的哈希值做拆分
这种拆分规则比较适用于实体表,比如说用户表,内容表,我们一般按照这些实体表的ID字段来拆分。比如说我们想把用户表拆分成16个库,每个库是64张表,那么可以先对用户ID做哈希,哈希的目的是将ID尽量打散,然后再对16取余,这样就得到了分库后的索引值.
2.按照某一个字段的区间来拆分
比较常用的是时间字段,可以把一个月的数据放入一张表中,这样在查询时就可以根据创建时间先定位数据存储在哪个表里面,再按照查询条件来查询。数据库在分库分表之后,数据的访问方式也有了极大的改变,原先只需要根据查询条件到从库中查询数据即可,现在则需要先确认数据在哪一个库表中,再到那个库表中查询数据
四、课程小结
无论是哈希拆分还是区间段的拆分,我们首先都需要选取一个数据库字段,这带来一个问题是:我们之后所有的查询都需要带上这个字段,才能找到数据所在的库和表,否则就只能向所有的数据库和数据表发送查询命令。如果像上面说的要拆分成16个库和64张表,那么一次数据的查询会变成16*64=1024次查询,查询的性能肯定是极差的。
分库分表的原则
1.如果在性能上没有瓶颈点那么就尽量不做分库分表;
2.如果要做,就尽量一次到位,比如说16库,每个库64表就基本能够满足几年内你的业务的需求。
3.很多的NoSQL数据库,例如Hbase,MongoDB都提供auto sharding的特性,可以考虑使用这些NoSQL数据库替代传统的关系型数据库。