简谈数据库分库分表
为何分表
当一张表的数据达到千万级时甚至亿级时,查询一次所花的时间会变多,如果有联合查询的话可能会死在那儿了。分表的目的就在于此,减小数据库的负担,缩短查询时间。
大数据量并且访问频繁的表,将其分为若干个表:
比如对于某些网站平台的数据库表,数据量很大,这种能预估出来的大数据量表,我们就事先分出个N个表,这个N是多少,根据实际情况而定。
某网站现在的数据量假设是5000万条,可以设计每张表容纳的数据量是500万条,也就是拆分成10张表。
那么如何判断某张表的数据是否容量已满呢?可以在程序段对于要新增数据的表,在插入前先做统计表记录数量的操作,当<500万条数据,就直接插入,当已经到达阀值,可以在程序段新创建数据库表(自动扩容),再执行插入操作。
数据库架构
1.简单的数据库(PG/MySQL)主从复制:
数据库的主从复制解决了数据库的读写分离,(一主多备)能很好的提升读的性能,其图如下:
但是,主从复制也带来其他一系列性能瓶颈问题:
:---------:1.写入无法扩展
:---------:2.写入无法缓存
:---------:3.复制延时
:---------:4.锁表率上升
:---------:5.表变大,缓存率下降
那问题产生总得解决的,这就产生下面的优化方案,一起来看看。
1、垂直分区
如果把业务切割得足够独立,那把不同业务的数据放到不同的数据库服务器将是一个不错的方案,而且万一其中一个业务崩溃了也不会影响其他业务的正常进行,并且也起到了负载分流的作用,大大提升了数据库的吞吐能力。经过垂直分区后的数据库架构图如下:
已经足够独立了,但是有些业务之间或多或少总会有点联系,如用户,基本上都会和每个业务存在关联,况且这种分区方式,也不能解决单张表数据量暴涨的问题。
2、水平分区(Sharding)
将用户按一定规则(按id哈希)分组,并把该组用户的数据存储到一个数据库分片中,即一个sharding,这样随着用户数量的增加,只要简单地配置一台服务器即可,原理图如下:
如何来确定某个用户所在的shard呢,这个时候我们可以建一张用户和shard对应的数据表,每次请求先从这张表找用户的shard id,再从对应shard中查询相关数据,如下图所示:
单库单表
单库单表是最常见的数据库设计,例如,有一张用户(user)表放在数据库db中,所有的用户都可以在db库中的user表中查到
单库多表
随着用户数量的增加,user表的数据量会越来越大,当数据量达到一定程度的时候对user表的查询会渐渐的变慢,从而影响整个DB的性能。还有一个更严重的问题是,事务提交会锁表,期间所有的读写操作只能等待。
一主多备
在实际的应用中,大部分情况都是读远大于写。DB提供了读写分离的机制,所有的写操作都必须对应到Master,读操作可以在 Master和Slave机器上进行,Slave与Master的结构完全一样,一个Master可以有多个Slave,甚至Slave下还可以挂 Slave,通过此方式可以有效的提高DB集群的 QPS.
所有的写操作都是先在Master上操作,然后同步更新到Slave上,所以从Master同步到Slave机器有一定的延迟,当系统很繁忙的时候,延迟问题会更加严重,Slave机器数量的增加也会使这个问题更加严重。
此外,可以看出Master是集群的瓶颈,当写操作过多,会严重影响到Master的稳定性,如果Master挂掉,整个集群都将不能正常工作。