当数据量达到一定程度时,我们处于性能考虑就需要将我们存放在同一个数据库中的数据分散存放到多个数据库(主机)上面,以达到分散单台设备负载的效果。数据的切分同一时候还能够提高系统的总体可用性,由于单台设备Crash之后。仅仅有总体数据的某部分不可用,而不是全部的数据。
数据的切分(Sharding)依据其切分规则的类型,能够分为垂直切分、水平切分、联合切分模式。
数据的垂直切分
简介
是依照不同的表(或者Schema)来切分到不同的数据库(主机)之上,这样的切能够称之为数据的垂直(纵向)切分。
垂直切分的最大特点就是规则简单,实施也更为方便,尤其适合各业务之间的耦合度非常低。相互影响非常小,业务逻辑非常清晰的系统。在这样的系统中,能够非常容易做到将不同业务模块所使用的表分拆到不同的数据库中。依据不同的表来进行拆分。对应用程序的影响也更小,拆分规则也会比较简单清晰。
一个架构设计较好的应用系统。其总体功能肯定是由非常多个功能模块所组成的。而每一个功能模块所须要的数据对应到数据库中就是一个或者多个表。而在架构设计中,各个功能模块相互之间的交互点越统一越少,系统的耦合度就越低,系统各个模块的维护性以及扩展性也就越好。这样的系统实现数据的垂直切分也就越容易,不同功能模块的数据存放于不同的数据库主机中,能够非常容易就避免掉跨数据库的Join存在。
当然很多情况下系统的耦合度没有那么低,我们就必须依据实际的应用场景进行评估权衡。决定是迁就应用程序将须要Join的表的相关某快都存放在同一个数据库中,还是让应用程序做很多其它的事情,也就是程序全然通过模块接口取得不同数据库中的数据,然后在程序中完毕Join操作。
案例分析
系统功能能够基本分为四个功能模块:用户,群组消息,相册以及事件。分别对应为例如以下这些表:
- 用户模块表:user,user_profile,user_group,user_photo_album
- 群组讨论表:groups,group_message,group_message_content,top_message
- 相册相关表:photo,photo_album,photo_album_relation,photo_comment
- 事件信息表:event
初略一看,没有哪一个模块能够脱离其它模块独立存在,模块与模块之间都存在着关系。莫非无法切分?
当然不是,我们再略微深入分析一下,能够发现,尽管各个模块所使用的表之间都有关联,可是关联关系还算比较清晰,也比较简单。
- 群组讨论模块和用户模块之间主要存在通过用户或者是群组关系来进行关联。一般关联的时候都会是通过用户的id或者nick_name以及group的id来进行关联。通过模块之间的接口实现不会带来太多麻烦。
- 相册模块仅仅与用户模块存在通过用户的关联。这两个模块之间的关联基本就有通过用户id关联的内容。简单清晰,接口明白;
- 事件模块与各个模块可能都有关联,可是都仅仅关注其各个模块中对象的ID信息,相同能够做到非常容易分拆。
所以。我们第一步能够将数据库依照功能模块相关的表进行一次垂直拆分。每一个模块所涉及的表单独到一个数据库中,模块与模块之间的表关联都在应用系统端通过藉口来处理。例如以下图所看到的:
通过这样的垂直切分之后。之前仅仅能通过一个数据库来提供的服务。就被分拆成四个数据库来提供服务,服务能力自然是添加几倍了。
垂直切分的长处
- 数据库的拆分简单明了,拆分规则明白;
- 应用程序模块清晰明白,整合容易。
- 数据维护方便易行,容易定位。
垂直切分的缺点
- 部分表关联无法在数据库级别完毕。须要在程序中完毕。
- 对于访问极其频繁且数据量超大的表仍然存在性能平静,不一定能满足要求。
- 事务处理相对更为复杂;
- 切分达到一定程度之后,扩展性会遇到限制;
- 过读切分可能会带来系统过渡复杂而难以维护。
数据的水平切分
简介
依据表中的数据的逻辑关系,将同一个表中的数据依照某种条件拆分到多台数据库(主机)上面,这样的切分称之为数据的水平(横向)切分。一般来说,简单的水平切分主要是将某个访问极其频繁的表再依照某个字段的某种规则来分散到多个表之中。每一个表中包括一部分数据。
水平切分于垂直切分相比。相对来说略微复杂一些。由于要将同一个表中的不同数据拆分到不同的数据库中,对于应用程序来说,拆分规则本身就较依据表名来拆分更为复杂,后期的数据维护也会更为复杂一些。
如依据某个数字类型字段基于特定数目取模,某个时间类型字段的范围,或者是某个字符类型字段的hash值。假设整个系统中大部分核心表都能够通过某个字段来进行关联。那这个字段自然是一个进行水平分区的上上之选了。
一般来说,像如今互联网非常火爆的Web2.0类型的站点。基本上大部分数据都能够通过会员用户信息关联上,可能非常多核心表都非常适合通过会员ID来进行数据的水平切分。切分之后基本上不会出现各个库之间的交互。
案例分析
全部数据都是和用户关联的。那么我们就能够依据用户来进行水平拆分,将不同用户的数据切分到不同的数据库中。当然,唯一有点差别的是用户模块中的groups表和用户没有直接关系。所以groups不能依据用户来进行水平拆分。对于这样的特殊情况下的表,我们全然能够独立出来。单独放在一个独立的数据库中。
所以,对于我们的演示样例数据库来说,大部分的表都能够依据用户ID来进行水平的切分。不同用户相关的数据进行切分之后存放在不同的数据库中。如将全部用户ID通过5取模然后分别存放于五个不同的数据库中。
每一个和用户ID关联上的表都能够这样切分。这样,基本上每一个用户相关的数据。都在同一个数据库中,即使是须要关联,也能够非常简单的关联上。
我们能够通过下图来更为直观的展示水平切分相关信息:
水平切分的长处
- 表关联基本能够在数据库端全部完毕;
- 不会存在某些超大型数据量和高负载的表遇到瓶颈的问题;
- 应用程序端总体架构修改相对较少;
- 事务处理相对简单;
- 仅仅要切分规则能够定义好。基本上较难遇到扩展性限制;
水平切分的缺点
- 切分规则相对更为复杂,非常难抽象出一个能够满足整个数据库的切分规则;
- 后期数据的维护难度有所添加,人为手工定位数据更困难;
- 应用系统各模块耦合度较高,可能会对后面数据的迁移拆分造成一定的困难。
联合切分
简介
当我们某个(或者某些)表的数据量和访问量特别的大,通过垂直切分将其放在独立的设备上后仍然无法满足性能要求,这时候我们就必须将垂直切分和水平切分相结合。先垂直切分,然后再水平切分,才能解决这样的超大型表的性能问题。
每一个应用系统的负载都是一步一步增长上来的,在开始遇到性能瓶颈的时候,大多数架构师和DBA都会选择先进行数据的垂直拆分,由于这样的成本最小。最符合这个时期所追求的最大投入产出比。然而随着业务的不断扩张,系统负载的持续增长,在系统稳定一段时期之后,经过了垂直拆分之后的数据库集群可能又再一次不堪重负,遇到了性能瓶颈。这时候我们就必须要通过数据的水平切分的优势,来解决这里所遇到的问题。并且,我们全然不必在使用数据水平切分的时候,推倒之前进行数据垂直切分的成果,而是在其基础上利用水平切分的优势来避开垂直切分的弊端。而水平拆分的弊端(规则难以统一)也已经被之前的垂直切分解决掉了,让水平拆分能够进行的得心应手。
案例分析
假设在最开始。我们进行了数据的垂直切分,然而随着业务的不断增长,数据库系统遇到了瓶颈,我们选择重构数据库集群的架构。怎样重构?我们选择了在垂直切分的基础上再进行水平拆分。在经历过垂直拆分后的各个数据库集群中的每一个都仅仅有一个功能模块。而每一个功能模块中的全部表基本上都会与某个字段进行关联。如用户模块全部都能够通过用户ID进行切分,群组讨论模块则都通过群组ID来切分。相册模块则依据相册ID来进切分。最后的事件通知信息表考虑到数据的时限性(仅仅会访问近期某个事件段的信息),则考虑按时间来切分。
下图展示了切分后的整个架构:
实际上,在非常多大型的应用系统中,垂直切分和水平切这两种数据的切分方法基本上都是并存的。并且经常在不断的交替进行,以不断的添加系统的扩展能力。我们在应对不同的应用场景的时候,也须要充分考虑到这两种切分方法各自的局限,以及各自的优势。在不同的时期(负载压力)使用不同的结合方式。
联合切分的长处
- 能够充分利用垂直切分和水平切分各自的优势而避免各自的缺陷;
- 让系统扩展性得到最大化提升。
联合切分的缺点
- 数据库系统架构比较复杂。维护难度更大
- 应用程序架构也相对更复杂;
上一篇 | 《性能优化系列文章目录》 | 下一篇 |
---|