之前有被问到过数据库亿万级数据的优化问题,分表和分库是其中的一个重要知识点。

分表的概念与策略

对于大型的互联网应用来说,数据库单表的记录行数可能达到千万级甚至是亿级,并且数据库面临着极高的并发访问。采用主从复制(Master-Slave)模式的MySQL架构,只能够对数据库的读进行扩展,而对数据库的写入操作还是集中在Master上,并且单个Master挂载的Slave也不可能无限制多,Slave的数量受到Master能力和负载的限制。因此就需要对数据库的吞吐能力进一步扩展,以满足高并发访问与海量数据存储的需要。

对于访问极为频繁且数据量巨大的单表(百万到千万级别)来说,我们首先要做的就是减少单表的记录条数,以便减少数据查询所需要的时间,提高数据库的吞吐,这就是分表的概念。在分表之前,首先需要选择适当的分表策略,使得数据能够较为均衡地分布到多张表中,且不能影响正常的查询。

对于互联网企业来说,大部分数据都是与用户关联的,因此,用户id是最常用的分表字段。因为大部分查询都需要带上用户ID,这样的分表策略既不会影响正常查询,又能够使数据较为均衡地分布到各个表中(有些场景可能会出现冷热数据分配不均衡的情况)。

假设有一个用来记录用户购买信息的订单表(ORDER),由于ORDER表中的记录条数太多,需要被拆分为256张表(拆分表的数量一般是2的N次方),拆分的规则是根据USER_ID%256取得对应的表存储记录。而前台应用则能根据USER_ID%256的规则去找到对应订单存储的表,再去存储该记录的表中取出数据(余数为0,则查0号表,余数为233,则查233号表)。这样以来,USER_ID便变成了一个必须的查询条件,否则将会因为无法定位数据存储的表而无法对数据进行访问。

这时,如果要访问USER_ID是257的订单记录,则根据USER_ID%256的规则得到要访问的表是ORDER_1。这里可能会有个疑问,就是如果257这个用户特别有钱,下了一亿个订单,ORDER_1表岂不是又数据量过大了。当然这种情况现实是不可能出现的,但是这个疑问可以推出一个观点,就是说具体的分表策略是要根据实际情况来制定的。

分库的概念与策略

分表能够解决单表数据量过大带来的查询效率下降的问题,但是却无法给数据库的并发处理能力带来质的提升。面对高并发的读写访问,当数据库Master服务器无法承载写操作压力时,不管如何扩展Slave服务器,都没有什么意义了。因此必须换一种思路:既然拆分多个表不行了,那就拆分多个数据库好了,聚集多个单数据库的写入能力提高整体的写入能力,这就是分库的概念。

与分表策略类似,分库也可以采用通过一个关键字取模的方式来对数据访问进行路由。比如还是之前的订单表,假设USER_ID字段的值是258,将原有的单库分为256个库,那么应用程序对数据库的访问请求将被路由到第二个库(258%256 = 2)。

分库分表的概念与策略

大多数时候,数据库是会同时面临高并发访问的压力和海量数据的存储问题的。这时候就需要采用分表策略,又要采用分库策略,以便能既扩展系统的并发处理能力,又提升单表的查询性能。这种分库和分表联合使用的方式,就是分库分表的概念。

分库分表的策略比起仅分库或仅分表的策略要更为复杂,一种分库分表的路由策略如下:

1.中间变量=USER_ID%(分库数量*每个库的表数量)

2.库=取整数(中间变量/每个库的表数量)

3.表=中间变量%每个库的表数量

同样是订单表,同样采用用户ID作为路由字段,首先使用USER_ID对库数量*每个库表的数量取模,得到一个中间变量;然后使用中间变量除以每个库表的数量,取整,便得到对应的库;而中间变量对每个库表的数量取模,即得到对应的表。

假设将原来的单库单表ORDER表拆分为256个库,每个库包含1024个表,那么按照前面所提到的路由策略,对于USER_ID=262145的访问,路由的计算过程如下:

1.中间变量=262145%(256*1024)=1

2.库=(1/1024)取整=0

3.表=1%1024=1

因此得出,对于USER_ID=262145的订单记录的查询和修改,将会被路由到第0个库的第1个ORDER_1表中执行。

"我懂得了那么多道理,却仍然过不好这一生。"

03-18 03:42