如何让分库分表真正落地?(上)

前言

在互联网系统开发的过程中,分库分表并不是一个新概念,很多开发人员对分库分表或多或少都有了解,也知道其使用的场景,但对究竟如何实现实现分库分表并不是很明确。当然,分库分表的含义与实现远比字面意思要复杂的多。这就引出话题:如何让分库分表落地?

首先我们从数据存储和访问的演进过程说起:

先看一个经典案例:

试想在我们平时写的小项目,小课设:电商系统中存在订单表,系统在初始运行期间,一般使用单库和单表的方式来存储和访问数据,因为数据量不大,所以数据库访问的瓶颈并不明显。

如果这时候马爸爸看中了你的项目,想投资商用,那系统每天可能会产生数十万,甚至上百万、千万...(妈耶,想都不敢想)级别的订单数据,订单表就会开始出现瓶颈。

以互联网中常用的MySQL数据库为例,虽然表单存储数据原则上可以达到亿条级别,但此时访问效率会变得很差,即使采用各种调优策略,效果也通常微乎其微。业界普遍认为,MySQL表单容量在1千万以下是最佳状态,一旦超过这个量级,就需要考虑其他方案了。

既然以MySQL为代表的关系数据库中的表单无法支持大量数据量的存储和访问方案,自然而然的,你就可能想到是否可以采用诸如MongDB等NoSQL的方式来管理数据?

但其实这并不是很好的选择,原因有很多:一方面,关系型数据库生态系统非常完善,关系型数据库经过几十年的持续发展,具有非关系数据库无法比拟的稳定性和可靠性;另一方面,关系型数据库的事务特性,也是其他数据存储工具所不具备的一项核心功能。目前绝大部分公司的核心数据都存储在关系型数据库中,就互联网公司而言,MySQL是主流的数据存储方案。

现在,我们选择了关系型数据库,就可以考虑采用分表分库的方案来解决单表库的瓶颈问题。分库分表方案,更多的是对关系型数据库数据存储和访问机制的补充,而不是颠覆。

那究竟什么是分库分表呢?

什么是数据分库分表?

分库和分表是两个概念,但是我们通常会将它们合并在一起,简称为分库分表。它没有一个很严格的定义,你可以简单理解为:

为了解决由于数据量过大而导致的数据库性能降低的问题,将原来独立的数据库拆分成若干数据库,把原来数据量大的表拆分成若干数据表,使得单一数据库、单一数据表的数据量变得足够小,从而达到提升数据库性能的效果。

分库分表的表现形式有很多种

分库和分表是两个维度,在开发过程中,对于每个维度,都可以采用两种拆分思想,即垂直拆分水平拆分

那什么叫垂直拆分,什么叫水平拆分?别着急,我们一起慢慢看

先来看看垂直拆分表,垂直拆分相比水平拆分,更好理解一点,比如在我们前面提到的电商系统中,用户在打开首页时,往往会加载一些用户的个人信息,比如用户名、性别、地理位置等基础数据。对应用户表而言,这些位于首页的基础访问数据频率远比用户头像等数据更高。基于这两种数据的不同访问特性,可以把用户表单单独存放在一张表中,把访问频次高的用户信息单独放在另外一张表中,如图:


如何让分库分表真正落地?(上)


从这里可以看出,垂直分表的处理方式,就是将一个表按照字段分成多张表,每个表存储其中一部分字段。在实现上,我们通常会把头像等blob类型的大字段数据或者热度较低的数据放在一张独立表中,将经常需要组合查询的列放在一张表中,这样也可以认为是分表操作的一种表现形式。

通过垂直分表,能得到一定程度的性能提升,但数据毕竟仍然位于同一个服务器中,也就是操作范围限制在一个服务器上,每个表还是会竞争同一台服务器中的CPU、内存、网络IO等资源。基于这个考虑,在有了垂直分表之后,我们自然就想到可不可以垂直分库?

基于垂直分表的思想,垂直分库,就是将用户的相关数据表单独拆分出来,放在一个独立的数据库中,如图:


如何让分库分表真正落地?(上)

这样的效果就是垂直分库。从定义上讲,垂直分库是按照业务将表进行分类,然后分布到不同的数据库上,其核心理念就是专库专用,而从实现上讲,垂直分库很大程度上取决于业务的规划和系统边界的划分。比如说,用户数据的独立拆分就需要考虑到系统用户体系和其他其他业务模块之间的关联关系,而不是简单地创建一个用户库就可以了。在高并发的场景下,垂直分库能够在一定程度上提升IO访问效率和数据库连接数,并降低单机硬件资源的瓶颈。

从前面的分析中,我们不难明白,垂直拆分尽管实现起来比较简单,但是并不能解决数据量过大的问题,所以,在实际应用中,我们常常需要在垂直拆分的基础上再水平拆分。例如,可以对用户库的用户信息按照用户ID进行取模,然后分别存储在不同的数据库中,这就是水平分库的常见做法:


如何让分库分表真正落地?(上)


可以看到,水平分库,是把同一个表的数据按照一定的规则拆分到不同的数据库中,每个数据库同样可以位于不同的服务器上。这种方案往往可以解决单库存储量及性能的瓶颈问题,但由于同一个表被分配在不同的数据库中,数据的访问需要额外的路由工作,因此大大提高了系统的复杂度。这里所谓的规则实际上就是一系列的算法,常见的包括:

取模算法:取模的方式有很多,比如前面介绍的按照用户 ID 进行取模,当然也可以通过表的一列或多列字段进行 hash 求值来取模;

范围限定算法:范围限定也很常见,比如可以采用按年份、按时间等策略路由到目标数据库或表;

预定义算法:是指事先规划好具体库或表的数量,然后直接路由到指定库或表中。

按照水平分库的思路,也可以对用户库中的用户表进行水平拆分,也就是说,水平分表是在同一个数据库内,把同一个表的数据按一定规则拆到多个表中。


如何让分库分表真正落地?(上)

显然,系统的数据存储架构演变到现在,已经非常复杂了,与拆分前的单库单表相比,现在面临着一系列具有挑战的问题,比如:

如何对多数据库进行高效治理?

如何进行跨节点关联查询?

如何实现跨节点的分页和排序操作?

如何生成全局唯一的主键?

如何确保事务一致性?

如何对数据进行迁移?

...

如果没有很好的工具来支持数据的存储和访问,数据一致性将很难得到保障。

那么下节,松鼠就会整理和分享解决以上问题的原理以及选择怎样的一款分库分表开源框架。

> 文章部分来源于:拉钩教育网

如果对松鼠的文章感兴趣也可以关注我的公众号:松鼠技术站


分享到:


相關文章: