海量数据存储——分库分表策略详解

科学之前

百家号 04-13 15:55

一、背景:

系统刚开始的时候,数据库都是单库单表结构。随着业务量的增加进行第一次数据库升级,根据业务垂直拆分数据库,这样多变成多个业务数据库,每个数据库里面还是单表结构。接下来,继续随着业务量的继续增加,单表已经很难承受数据量,就要进行分表,这个时候就是,多个业务库,每个业务库下对需要分表的表进行分表。再接下来,随着应用的增加,数据库IO,磁盘等等都抗不住了,就要把分表的表分到多个库,这样就形成了如下的结构。

重点:本文主要讨论的是分库分表的策略,也就是分库分表的规则或者说是算法。

二、分库分表的依据--分库分表字段的选择

分库分表首先要确定根据哪个字段、或者哪几个字段进行路由,一般的原则是按使用频率最高维度的字段去分库分表,尽量保证高使用维度下只查询单表。

常用的字段有主键ID,用户ID,时间,商户ID,产品ID,业务类型等等

三、分库分表策略

主要原理:分区、取模、数据路由表

1. 按照时间区间

1)基本原理:

一定区间内时间产生的数据放到一张表里面,多个时间区间的表放到一个库里面

2)简单例子:

单库多表结构,按月分表可以这样,user_201601,user_201602,...,user_201612这种结构。按年分表可以这样,user_2016,user_2017,...这种。

3)多库多表算法:

比如按天分表,每天一张表,当单库超过100张表的时候,进行分库到下一张表。那么假如第一张报表在库BD0,表名是user_20160201。从DB0.user_20160201,..到DB0.user_20160511就100张表了,接下来就要进行分库了,进入20160512,就是DB1.user_20160512,这个算法就是上线的时候定一个上线日期,具体算法如下

库ID = (当前日期 - 上线日期)/ 100

表ID = user_yyyyMMdd

注:好处是可以直接根据时间经过简单计算定位到哪个库和哪个表

还有一种算法:

表ID = (当前日期 - 上线日期) % 100

表名如下: DB0.user_0001, user_0002,....,user_01000。

注:表名和库名都要经过计算,比较麻烦

4)按月分表,每个月一张表;这种情况,一般就不用分库了,一年12张表说明量也不会特别大,如果量特别大,或者是热点数据,可以一年分一个库,具体算法和上面差不多。

5)按季度分表,基本不用分库。

6)按年分表,肯定不用分库了,没有必要了。

2. 按照主键ID区间

对于自增的主键ID,可以按照ID区间进行分表,以1000万数据量为分界线,对线性的ID进行切割分表,每涨到1000万数据,分到下一张表,超过一定数目的表,进行分库。

库ID = 主键ID / 1000万 / 100

表ID = 主键ID / 1000万 % 100

如:DB0.user_0000,...,DB0.user_0099, DB1.user_0000,...,DB1.user_0099

3. 按照指定字段hash后再取模

如果要取模的字段不是整数型,要先hash后,再通过取模算法,算出在哪个库和那个表。具体算法,参照下面的按用户ID取模。

4. 按照用户ID取模

这里把按照用户ID取模单独拎出来,因为就使用而言,是使用场景最多的情况,很多时候都是用户相关数据量最大,需要分库分表,查询维度更多也是按照用户来查询,所以对用户取模,让同一个用户的数据落到一张表里面,再好不过了。

这里模式用户ID是整数型的。假设库数量要分4库,每个库表数量8表,一共32张表。

库ID = userId % 库数量4

表ID = userId / 库数量4 % 表数量8

或者

库ID = userId / 表数量4 % 库数量4

表ID = userId % 表数量8

5. 数据路由表

如果分库分表的算法很复杂,可以通过路由表+程序算法,来存储和计算分库分表规则,不过一般不建议,分库分表搞得太复杂,不便于维护和查询问题

四、各个方案对比

本文仅代表作者观点,不代表百度立场。系作者授权百家号发表,未经许可不得转载。

返回顶部