架构学习系列:数据库分库分表

Posted 程序杂烩

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了架构学习系列:数据库分库分表相关的知识,希望对你有一定的参考价值。

读写分离主要是分散了数据库读写的压力,但是并没有分散数据存储的压力,当数据过大的时候,单台服务器存储的能力会成为系统的瓶颈。

主要体现在:

  1. 数据量太大,读写性能下降。即使有索引,性能依旧会下降。

  2. 数据文件会变的很大,数据库备份和恢复耗时会很长。

  3. 数据文件越大,极端情况丢失数据的风险越高。

所以,单台服务器数据存储不宜过大,需要控制在一定的范围内。为满足数据存储需求,就需要将数据分散存储到不同的数据库中。

常见的分散存储方式有分库分表

业务分库

业务分库是指按照业务模块将数据分散到不同的数据库服务器。比如在电商系统中,我们可以把商品、用户、订单等数据分别存储到不同的服务器数据库上。

分库可以降低数据存储压力和读写压力,但同样也会带来其他新的应用问题:

1、join操作问题。 在单台数据库中,不考虑性能问题,join 随时可以根据需要使用;但如果数据存储在不同的数据库中,join就没用武之地了,只能分开单个语句去查询了。
2、事物问题。 单台数据库同一个库中不同的表做修改,我们可以通过同一个事物保证数据的最终一致性,但现在多台数据库的表没有在一起,就无法通过事物同意修改,所以需要程序模拟实现事物。
3、成本问题。 本来一台可以搞定的事情,分库后需要两台,四台甚至更多的数据库服务器。

应不应该分库?

如果是初创公司,并不建议一开始就拆分,原因如下:
1、初创业务不确定因素很大,业务未来发展有很大的疑问,并且一开始并没有存储和访问的压力,现在直接上手分库,对成本是一种大的消耗,不仅体现在硬件成本,还有人力成本。
2、业务分局后,简单的join就无法实现,需要程序去实现,从而增加不可控因素。
3、工作量增加。分库的逻辑,业务的实现方式,导致前期消耗过多的时间。而创业初期,时间尤为重要。

如果是成熟的公司业务重构,有大量的数据基础 ,有成熟的业务分库的方案,并且已经满足不了现在的业务需求,那么建议可以使用分库的方式来分散业务数据的存储。

每一个架构师心里都有一种技术情节,希望自己设计的系统高性能,高可用,高扩展,一步登天,设计过分完美的方案。而根据架构设计三原则的演进原则,每一个架构都是通过不断迭代来完善的。如果我们初期设计的方案不能满足现在业务的需求,那么,这个时候在进行分库分表也不迟。

分表

将不同业务数据分散存储到不同的数据库服务器,减轻单库的存储压力,同样同一业务的单表数据也会达到单台数据库服务器的处理瓶颈。例如,过亿用户的存储,全部放在一张表里,肯定无法满足性能的要求的,所以,就会涉及到对单表的拆分。

单表数据拆分有两种方式:垂直分表水平分表

  • 垂直分表:就是对数据表结构字段进行切分,将字段分散存储到两个表,三个表甚至更多的表。

  • 水平分表:就是对数据表中的数据进行切分,存储的字段一致,存储的数据不同。

单表进行切分后,可以将多表存在相同的数据库服务器中,也可以存储在不同的数据库服务器,可以根据我们的实际情况来确定。

分表能够有效的分散单表的存储压力,并带来可观的性能提升,但是,避不可免会带来一些操作复杂性。

垂直分表

垂直分表适合将一些不常用且占用大量空间或者使用率比较小的列拆分出来。而其复杂性主要体现在表操作数量要增加。尽管有些字段不常用,但是一旦需要,则必会涉及到多张表的查询。原本只需要一次查询,现在就需要多次查询才可以获取完整数据。

水平分表

垂直分表的复杂性主要体现在了查询次数上的增加,而水平分表的复杂性可就无比复杂了。首先,水平分表,我们可以要求单表行数超过1000万条或者2000万条数据就需要分表。

那水平分表的复杂性主要体现在哪呢?

路由
水平分表后,数据怎么存储,哪些数据存储在哪些子表中,这个就需要增加路由算法来计算,常见的路由算法有:

  • 范围路由:选取有序的数据列(自增ID、时间等)作为路由条件,不同分段分散到不同的子表中。例如,ID为1-999999存储到表1中,1000000~1999999存储到表2中,依此类推。
    范围路由设计的复杂点主要在分段大小的选取上,分段太小,导致子表的数据过多,维护起来麻烦;分段太大,依旧会有性能的问题,所以需要根据具体业务来选取合适的分段大小,一般在100万到2000万之间。
    范围路由的优点是可以随着数据的增加平滑地扩充新表,不会对原有数据产生影响。缺点是数据分布不均匀,

  • Hash路由。选取某个列或者几个列的组合的值进行Hash运算,然后根据Hash结果分散到不同的数据库表中。比如,我们规划为10个表,则可以根据id取10的余来选择存储。
    Hash路由设计的复杂点在于初始表数量的选取上,以及后面增加表数量对数据的影响。
    Hash路由的优点在于,数据分布比较均匀,缺点在于,扩充新表很麻烦,恰恰与范围路由相应。

  • 配置路由:就是新建一张路由表,用一些独立的表来记录路由信息。
    配置路由设计比较简单,也比较灵活,在扩充表时,只需迁移指定的数据,然后修改路由表就可以了。
    配置路由缺点就是每次必须多查询一次,会影响整体性能,而且数据过多就会遇到同样要分表的死循环问题。


join操作

水平分表后,数据分散在多个表中,join查询就需要多次join以后进行数据合并,或者通过数据库中间件来处理。


count()操作

水平分表前,一个count就能得到结果,分表后就需要进行特殊处理了。常见的主要有两种方式:

  • count()相加。但是性能可能会比较低。

  • 记录数表。新增一张表,将每张表记录相应的数量,在每次插入或删除后,都需要更新数据。在性能方面会比count()相加好一些,但是缺点在于,每次插入与删除都需要维护。而且容易遗漏导致数据不一致。


order by 操作
同join一样,排序无法在数据库中完成,只有由业务代码或者中间件来满足了。


声明:本系列学习内容来自于《从零开始学架构》。另,图片源于网络,若有侵权,请及时联系删除。


以上是关于架构学习系列:数据库分库分表的主要内容,如果未能解决你的问题,请参考以下文章

MySQL系列之分库分表学习笔记

成为架构师课程系列数据库性能优化:写入数据量增加时,如何实现分库分表?如何保证分库分表后 ID 的全局唯一性?

大型网站架构系列:电商网站架构案例

大型网站架构系列:电商网站架构案例

浅谈高性能数据库集群之分库分表

分库分表常见概念解读+Sharding-JDBC实战