分库分表介绍
一、背景
业务系统一开始是使用的单机数据库的模式,随着后面的需求越来越多,为了能够在性能上得到提升,我们将数据库的读写进行分离,根据数据库的主从架构实现从主写入,从从读取。从库与主库同步更新数据,保证数据的一致性。但是这只是解决了在数据请求处理方面的问题,随着业务量越来越大,用户越来越多,写请求越来越多的情况下,该如何处理?
如果为了应付写请求,增加多的主节点是不现实的,因为数据库要保持一致性的话,多主架构就要保证多写,即一条插入命令就要写到几个主库当中。这个时候新的解决方案就出来了,那就是分库分表。这里的思想与redis的cluster模式有点相似。
二、什么时候进行分库分表?
对于分库分表,并不是说盲目的进行分库和分表。
- 分表:随着单表数据量的不断增加,达到了一定量级的时候,不论是做数据查询还是更新。数据查询基数大,执行效率还是低下,哪怕是经过索引等手段的优化还是会存在性能上的问题。这时候把表进行拆分,将数据由单张表分配多多张表当中,来解决单表下的性能问题。
- 分库:当数据库的QPS随着业务量不断的提高,一个数据库很难支撑起对数据库请求,因为如果仅仅是读请求的QPS提高,可以通过读写分离,增加几个从节点的方式就能够得到一定的缓解,但是对于写请求的QPS,上面说到增加主节点的方式并不现实,这个时候可以考虑进行分库,降低单库的请求压力。
三、如何分库分表
如果需要分表,那么也不是说分的表越多越好,要根据现阶段的数据量来进行判断。这些都要视具体情况而定,没有绝对的答案。
比如:数据库单表每天的平均业务量是3W,一年大概就是3W×365=1095W的数据量,由于我们要考虑新的需求,还有业务的持续增长,将数据量提高到4W每天,那一年就是4W×365=1460W,在考虑到系统设计的使用年限,假设为5年。总共要考虑这五年内的数据总量大概为1460W×5=7300W。我们以500W一张表为瓶颈来界定,那需要分的表数量大概为7300÷500=15张表。这里仅仅是针对业务表的粗略考虑。
那么对于分库而言,又该如何进行拆分呢。因为需要分库是根据系统的QPS进行考虑的,那要考虑到顶峰的QPS,然后增加一点的估值(比如业务推广导致的系统业务量在增加的情况)
假设业务系统去年的QPS和RT等等数量进行评估,数据库只需要5000个连接即可,单库可以支撑1000个数据库的连接情况(这里说的是假设,mysql支持的最大连接数是16384),我们可以将数据库拆分成6个,多出一个考虑到系统可能会出现增长的情况。
四、如何进行切分
分库分表分为水平切分和垂直切分两种方式。
- 水平切分:水平切分是按照一定的业务维度把数据进行拆分,如saas平台里,根据租户id,分成不同的数据库,保证租户的数据进行隔离。还有根据用户id将不同的业务数据分到不同的表当中。
- 垂直切分:垂直拆分就是把一张表的不同字段拆分到不同的表当中,通过唯一的业务id进行关联。这是我们单表常用的手段,但是主表的数据还是会不断的叠加。这样可以防止在处理某些业务的时候由于主表的一些锁表操作,导致了其它的业务收到影响。
五、分库分表带来的问题
上面说了分库分表简单的一些实现,分库分表的思想都是通过分而治之的达到目的。但是也会伴随着各式各样的问题。
- 数据库全局id,由于拆分了表,不能使用单表的自增id,需要引入全局的id。
- 分片的键选择
- 分布式事务,如果是分库的情况,跨库进行更新操作涉及到分布式事务的问题
- 跨表关联查询
解决方案:
- 使用全局的分号器(雪花算法),或者使用全局的唯一id(分布式id)
- 分片的键根据业务而定义,如租户id,用户id,日期等,并且加上索引
- 通过第三方分布式事务,如mysql的XA协议
- 修改相应不兼容的sql