MySQL9-可扩展性设计之数据切分

何谓数据切分

简单来说,就是指通过某种特定的条件,将我们存放在同一个数据库中的数据分散存放到多个数据库(主机)上面,以达到分散单台设备负载的效果。数据的切分同时还可以提高系统的总体可用性,因为单台设备Crash 之后,只有总体数据的某部分不可用,而不是所有的数据。

数据的切分(Sharding)根据其切分规则的类型,可以分为两种切分模式:一种是按照不同的表(或者Schema)来切分到不同的数据库(主机)之上,这种切可以称之为数据的垂直(纵向)切分;另外一种则是根据表中的数据的逻辑关系,将同一个表中的数据按照某种条件拆分到多台数据库(主机)上面,这种切分称之为数据的水平(横向)切分。

垂直切分的最大特点就是规则简单,实施也更为方便,尤其适合各业务之间的耦合度非常低,相互影响很小,业务逻辑非常清晰的系统。在这种系统中,可以很容易做到将不同业务模块所使用的表分拆到不同的数据库中。根据不同的表来进行拆分,对应用程序的影响也更小,拆分规则也会比较简单清晰。

水平切分于垂直切分相比,相对来说稍微复杂一些。因为要将同一个表中的不同数据拆分到不同的数据库中,对于应用程序来说,拆分规则本身就较根据表名来拆分更为复杂,后期的数据维护也会更为复杂一些。

数据的垂直切分

一个架构设计较好的应用系统,其总体功能肯定是由很多个功能模块所组成的,而每一个功能模块所需要的数据对应到数据库中就是一个或者多个表。而在架构设计中,各个功能模块相互之间的交互点越统一越少,系统的耦合度就越低,系统各个模块的维护性以及扩展性也就越好。这样的系统,实现数据的垂直切分也就越容易。

当我们的功能模块越清晰,耦合度越低,数据垂直切分的规则定义也就越容易。完全可以根据功能模块来进行数据的切分,不同功能模块的数据存放于不同的数据库主机中,可以很容易就避免掉跨数据库的Join 存在,同时系统架构也非常的清晰。

当然,很难有系统能够做到所有功能模块所使用的表完全独立,完全不需要访问对方的表或者需要两个模块的表进行Join 操作。这种情况下,我们就必须根据实际的应用场景进行评估权衡。决定是迁就应用程序将需要Join 的表的相关某快都存放在同一个数据库中,还是让应用程序做更多的事情,也就是程序完全通过模块接口取得不同数据库中的数据,然后在程序中完成Join 操作。

垂直切分的优点

◆ 数据库的拆分简单明了,拆分规则明确;

◆ 应用程序模块清晰明确,整合容易;

◆ 数据维护方便易行,容易定位;

垂直切分的缺点

◆ 部分表关联无法在数据库级别完成,需要在程序中完成;

◆ 对于访问极其频繁且数据量超大的表仍然存在性能平静,不一定能满足要求;

◆ 事务处理相对更为复杂;

◆ 切分达到一定程度之后,扩展性会遇到限制;

◆ 过读切分可能会带来系统过渡复杂而难以维护。

数据的水平切分

简单来说,我们可以将数据的水平切分理解为是按照数据行的切分,就是将表中的某些行切分到一个数据库,而另外的某些行又切分到其他的数据库中。当然,为了能够比较容易的判定各行数据被切分到哪个数据库中了,切分总是都需要按照某种特定的规则来进行的。如根据某个数字类型字段基于特定数目取模,某个时间类型字段的范围,或者是某个字符类型字段的hash 值。如果整个系统中大部分核心表都可以通过某个字段来进行关联,那这个字段自然是一个进行水平分区的上上之选了,当然,非常特殊无法使用就只能另选其他了。

水平切分的优点

◆ 表关联基本能够在数据库端全部完成;

◆ 不会存在某些超大型数据量和高负载的表遇到瓶颈的问题;

◆ 应用程序端整体架构改动相对较少;

◆ 事务处理相对简单;

◆ 只要切分规则能够定义好,基本上较难遇到扩展性限制;

水平切分的缺点

◆ 切分规则相对更为复杂,很难抽象出一个能够满足整个数据库的切分规则;

◆ 后期数据的维护难度有所增加,人为手工定位数据更困难;

◆ 应用系统各模块耦合度较高,可能会对后面数据的迁移拆分造成一定的困难。

垂直与水平联合切分的使用

联合切分的优点

◆ 可以充分利用垂直切分和水平切分各自的优势而避免各自的缺陷;

◆ 让系统扩展性得到最大化提升;

联合切分的缺点

◆ 数据库系统架构比较复杂,维护难度更大;

◆ 应用程序架构也相对更复杂;

数据切分及整合方案

总的来说,存在两种解决思路:

1. 在每个应用程序模块中配置管理自己需要的一个(或者多个)数据源,直接访问各个数据库,在模块内完成数据的整合;

2. 通过中间代理层来统一管理所有的数据源,后端数据库集群对前端应用程序透明;

可能90%以上的人在面对上面这两种解决思路的时候都会倾向于选择第二种,尤其是系统不断变得庞大复杂的时候。确实,这是一个非常正确的选择,虽然短期内需要付出的成本可能会相对更大一些,但是对整个系统的扩展性来说,是非常有帮助的。

①自行开发中间代理层。

②利用MySQL Proxy 实现数据切分及整合。

③利用Amoeba 实现数据切分及整合。

④利用HiveDB 实现数据切分及整合

⑤其他实现数据切分及整合的解决方案

数据切分与整合中可能存在的问题

问题:引入分布式事务的问题

在MySQL 各个版本中,只有从MySQL 5.0 开始以后的各个版本才开始对分布式事务提供支持,而且目前仅有Innodb 提供分布式事务支持。不仅如此,即使我们刚好使用了支持分布式事务的MySQL 版本,同时也是使用的Innodb 存储引擎,分布式事务本身对于系统资源的消耗就是很大的,性能本身也并不是太高。而且引入分布式事务本身在异常处理方面就会带来较多比较难控制的因素。

其实我们可以可以通过一个变通的方法来解决这种问题,首先需要考虑的一件事情就是:是否数据库是唯一一个能够解决事务的地方呢?其实并不是这样的,我们完全可以结合数据库以及应用程序两者来共同解决。各个数据库解决自己身上的事务,然后通过应用程序来控制多个数据库上面的事务。也就是说,只要我们愿意,完全可以将一个跨多个数据库的分布式事务分拆成多个仅处于单个数据库上面的小事务,并通过应用程序来总控各个小事务。当然,这样作的要求就是我们的应用程序必须要有足够的健壮性,当然也会给应用程序带来一些技术难度。

问题:跨节点Join 的问题

对待这类问题,我还是推荐通过应用程序来进行处理,在驱动表所在的MySQL Server中取出相应的驱动结果集,然后根据驱动结果集再到被驱动表所在的MySQL Server 中取出相应的数据。可能很多读者朋友会认为这样做对性能会产生一定的影响,是的,确实是会对性能有一定的负面影响,但是除了此法,基本上没有太多其他更好的解决办法了。而且,由于数据库通过较好的扩展之后,每台MySQL Server 的负载就可以得到较好的控制,单纯针对单条Query 来说,其响应时间可能比不切分之前要提高一些,所以性能方面所带来的负面影响也并不是太大。更何况,类似于这种需要跨节点Join 的需求也并不是太多,相对于总体性能而言,可能也只是很小一部分而已。所以为了整体性能的考虑,偶尔牺牲那么一点点,其实是值得的,毕竟系统优化本身就是存在很多取舍和平衡的过程。

问题:跨节点合并排序分页问题

如何解决?解决的思路大体上和跨节点Join 的解决类似,但是有一点和跨节点Join不太一样,Join 很多时候都有一个驱动与被驱动的关系,所以Join 本身涉及到的多个表之间的数据读取一般都会存在一个顺序关系。但是排序分页就不太一样了,排序分页的数据源基本上可以说是一个表(或者一个结果集),本身并不存在一个顺序关系,所以在从多个数据源取数据的过程是完全可以并行的。这样,排序分页数据的取数效率我们可以做的比跨库Join 更高,所以带来的性能损失相对的要更小,在有些情况下可能比在原来未进行数据切分的数据库中效率更高了。当然,不论是跨节点Join 还是跨节点排序分页,都会使我们的应用服务器消耗更多的资源,尤其是内存资源,因为我们在读取访问以及合并结果集的这个过程需要比原来处理更多的数据。

猜你喜欢

转载自blog.csdn.net/attack_breast/article/details/84547181