mysql数据库分库分表

 

何谓数据切分

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

数据的切分(Sharding)依据其切分规则的类型。能够分为两种切分模式。

一种是依照不同的表(或者Schema)来切分到不同的数据库(主机)之上,这样的切能够称之为数据的垂直(纵向)切分。另外一种则是依据表中的数据的逻辑关系,将同一个表中的数据依照某种条件拆分到多台数据库(主机)上面。这样的切分称之为数据的水平(横向)切分。

数据的垂直切分

数据的垂直切分。也能够称之为纵向切分。将数据库想象成为由非常多个一大块一大块的“数据块”(表)组成。我们垂直的将这些“数据块”切开,然后将他们分散到多台数据库主机上面。这样的切分方法就是一个垂直(纵向)的数据切分。

 

垂直切分的长处

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

◆ 应用程序模块清晰明白,整合easy。

◆ 数据维护方便易行,easy定位。

垂直切分的缺点

◆ 部分表关联无法在数据库级别完毕。须要在程序中完毕。

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

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

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

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

针对于垂直切分可能遇到数据切分及事务问题,在数据库层面实在是非常难找到一个较好的处理方案。实际应用案例中,数据库的垂直切分大多是与应用系统的模块相对应,同一个模块的数据源存放于同一个数据库中,能够解决模块内部的数据关联问题。而模块与模块之间,则通过应用程序以服务接口方式来相互提供所须要的数据。

尽管这样做在数据库的总体操作次数方面确实会有所添加,可是在系统总体扩展性以及架构模块化方面,都是故意的。可能在某些操作的单次响应时间会稍有添加。可是系统的总体性能非常可能反而会有一定的提升。而扩展瓶颈问题。就仅仅能依靠下一节将要介绍的数据水平切分架构来攻克了。

数据的水平切分

 

将数据的水平切分理解为是依照数据行的切分。就是将表中的某些行切分到一个数据库,而另外的某些行又切分到其它的数据库中。当然,为了能够比較easy的判定各行数据被切分到哪个数据库中了,切分总是都须要依照某种特定的规则来进行的。

如依据某个数字类型字段基于特定数目取模,某个时间类型字段的范围。或者是某个字符类型字段的hash值。假设整个系统中大部分核心表都能够通过某个字段来进行关联。那这个字段自然是一个进行水平分区的上上之选了,当然,非常特殊无法使用就仅仅能另选其它了。

水平切分的长处

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

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

◆ 应用程序端总体架构修改相对较少;

◆ 事务处理相对简单;

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

水平切分的缺点

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

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

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

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

我们必须结合“垂直”和“水平”两种切分方式同一时候使用,充分利用两者的长处,避开其缺点。
先在垂直切分的基础上再进行水平拆分。
在经历过垂直拆分后的各个数据库集群中的每一个都仅仅有一个功能模块。而每一个功能模块中的全部表基本上都会与某个字段进行关联。如用户模块全部都能够通过用户ID进行切分,群组讨论模块则都通过群组ID来切分。相冊模块则依据相冊ID来进切分。最后的事件通知信息表考虑到数据的时限性(仅仅仅仅会訪问近期某个事件段的信息),则考虑按时间来切分。

实际上,在非常多大型的应用系统中,垂直切分和水平切这两种数据的切分方法基本上都是并存的。并且经常在不断的交替进行,以不断的添加系统的扩展能力。我们在应对不同的应用场景的时候,也须要充分考虑到这两种切分方法各自的局限,以及各自的优势。在不同的时期(负载压力)使用不同的结合方式。

联合切分的长处

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

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

联合切分的缺点

◆ 数据库系统架构比較复杂。维护难度更大。

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

数据切分及整合方案

通过前面的章节。我们已经非常清晰了通过数据库的数据切分能够极大的提高系统的扩展性。可是,数据库中的数据在经过垂直和(或)水平切分被存放在不同的数据库主机之后,应用系统面临的最大问题就是怎样来让这些数据源得到较好的整合。可能这也是非常多读者朋友非常关心的一个问题。这一节我们主要针对的内容就是分析能够使用的各种能够帮助我们实现数据切分以及数据整合的总体解决方式。

 

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

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

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

可能90%以上的人在面对上面这两种解决思路的时候都会倾向于选择另外一种,尤其是系统不断变得庞大复杂的时候。

确实。这是一个非常正确的选择,尽管短期内须要付出的成本可能会相对更大一些,可是对整个系统的扩展性来说,是非常有帮助的。

所以,对于第一种解决思路我这里就不准备过多的分析,以下我重点分析一下在另外一种解决思路中的一些解决方式。

★ 自行开发中间代理层

在决定选择通过数据库的中间代理层来解决数据源整合的架构方向之后,有不少公司(或者企业)选择了通过自行开发符合自身应用特定场景的代理层应用程序。

通过自行开发中间代理层能够最大程度的应对自身应用的特定。最大化的定制非常多个性化需求,在面对变化的时候也能够灵活的应对。这应该说是自行开发代理层最大的优势了。

当然,选择自行开发,享受让个性化定制最大化的乐趣的同一时候,自然也须要投入很多其它的成本来进行前期研发以及后期的持续升级改进工作。并且本身的技术门槛可能也比简单的Web应用要更高一些。所以,在决定选择自行开发之前,还是须要进行比較全面的评估为好。

由于自行开发很多其它时候考虑的是怎样更好的适应自身应用系统,应对自身的业务场景,所以这里也不好分析太多。后面我们主要分析一下当前比較流行的几种数据源整合解决方式。

★利用MySQLProxy实现数据切分及整合

MySQLProxy是MySQL官方提供的一个数据库代理层产品,和MySQLServer一样,相同是一个基于GPL开源协议的开源产品。可用来监视、分析或者传输他们之间的通讯信息。他的灵活性同意你最大限度的使用它,眼下具备的功能主要有连接路由,Query分析,Query过滤和修改,负载均衡。以及主要的HA机制等。

实际上,MySQLProxy本身并不具有上述全部的这些功能。而是提供了实现上述功能的基础。

要实现这些功能,还须要通过我们自行编写LUA脚本来实现。

MySQLProxy实际上是在client请求与MySQLServer之间建立了一个连接池。全部client请求都是发向MySQLProxy,然后经由MySQLProxy进行对应的分析。推断出是读操作还是写操作,分发至对应的MySQLServer上。对于多节点Slave集群,也能够起做到负载均衡的效果。以下是MySQLProxy的基本架构图:

通过上面的架构简图。我们能够非常清晰的看出MySQLProxy在实际应用中所处的位置,以及能做的基本事情。

关于MySQLProxy更为具体的实施细则在MySQL官方文档中有非常具体的介绍和演示样例。感兴趣的读者朋友能够直接从MySQL官方站点免费下载或者在线阅读,我这里就不累述浪费纸张了。

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

Amoeba是一个基于Java开发的,专注于解决分布式数据库数据源整合Proxy程序的开源框架,基于GPL3开源协议。眼下,Amoeba已经具有Query路由,Query过滤,读写分离,负载均衡以及HA机制等相关内容。

Amoeba 主要解决的以下几个问题:

1. 数据切分后复杂数据源整合;

2. 提供数据切分规则并降低数据切分规则给数据库带来的影响。

3. 降低数据库与client的连接数。

4. 读写分离路由;

我们能够看出,Amoeba所做的事情,正好就是我们通过数据切分来提升数据库的扩展性所须要的。

Amoeba并非一个代理层的Proxy程序,而是一个开发数据库代理层Proxy程序的开发框架,眼下基于Amoeba所开发的Proxy程序有AmoebaForMySQL和AmoebaForAladin两个。

AmoebaForMySQL主要是专门针对MySQL数据库的解决方式,前端应用程序请求的协议以及后端连接的数据源数据库都必须是MySQL。对于client的不论什么应用程序来说,AmoebaForMySQL和一个MySQL数据库没有什么差别。不论什么使用MySQL协议的client请求,都能够被AmoebaForMySQL解析并进行对应的处理。下如能够告诉我们AmoebaForMySQL的架构信息(出自Amoeba开发人员博客):

AmoebaForAladin则是一个适用更为广泛。功能更为强大的Proxy程序。

他能够同一时候连接不同数据库的数据源为前端应用程序提供服务,可是仅仅接受符合MySQL协议的client应用程序请求。也就是说,仅仅要前端应用程序通过MySQL协议连接上来之后,AmoebaForAladin会自己主动分析Query语句,依据Query语句中所请求的数据来自己主动识别出该所Query的数据源是在什么类型数据库的哪一个物理主机上面。下图展示了AmoebaForAladin的架构细节(出自Amoeba开发人员博客):

咋一看,两者好像全然一样嘛。细看之后,才会发现两者主要的差别仅在于通过MySQLProtocalAdapter处理之后。依据分析结果推断出数据源数据库。然后选择特定的JDBC驱动和对应协议连接后端数据库。

事实上通过上面两个架构图大家可能也已经发现了Amoeba的特点了,他仅仅仅仅是一个开发框架。我们除了选择他已经提供的ForMySQL和ForAladin这两款产品之外。还能够基于自身的需求进行对应的二次开发。得到更适应我们自己应用特点的Proxy程序。

当对于使用MySQL数据库来说。不论是AmoebaForMySQL还是AmoebaForAladin都能够非常好的使用。当然,考虑到不论什么一个系统越是复杂,其性能肯定就会有一定的损失,维护成本自然也会相对更高一些。所以,对于仅仅须要使用MySQL数据库的时候,我还是建议使用AmoebaForMySQL。

AmoebaForMySQL的使用非常简单,全部的配置文件都是标准的XML文件,总共同拥有四个配置文件。分别为:

◆amoeba.xml:主配置文件,配置全部数据源以及Amoeba自身的參数设置。

◆rule.xml:配置全部Query路由规则的信息。

◆functionMap.xml:配置用于解析Query中的函数所对应的Java实现类;

◆ rullFunctionMap.xml:配置路由规则中须要使用到的特定函数的实现类;

假设您的规则不是太复杂,基本上仅须要使用到上面四个配置文件里的前面两个就可完毕全部工作。Proxy程序经常使用的功能如读写分离。负载均衡等配置都在amoeba.xml中进行。此外。Amoeba已经支持了实现数据的垂直切分和水平切分的自己主动路由。路由规则能够在rule.xml进行设置。

眼下Amoeba少有欠缺的主要就是其在线管理功能以及对事务的支持了,以前在与相关开发人员的沟通过程中提出过相关的建议,希望能够提供一个能够进行在线维护管理的命令行管理工具,方便在线维护使用,得到的反馈是管理专门的管理模块已经纳入开发日程了。另外在事务支持方面临时还是Amoeba无法做到的,即使client应用在提交给Amoeba的请求是包括事务信息的,Amoeba也会忽略事务相关信息。当然,在经过不断完好之后,我相信事务支持肯定是Amoeba重点考虑添加的feature。

关于Amoeba更为具体的用法读者朋友能够通过Amoeba开发人员博客(http://amoeba.sf.net)上面提供的使用手冊获取,这里就不再细述了。

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

和前面的MySQLProxy以及Amoeba一样,HiveDB相同是一个基于Java针对MySQL数据库的提供数据切分及整合的开源框架,仅仅是眼下的HiveDB仅仅支持数据的水平切分。

主要解决大数据量下数据库的扩展性及数据的高性能訪问问题,同一时候支持数据的冗余及主要的HA机制。

HiveDB的实现机制与MySQLProxy和Amoeba有一定的差异,他并非借助MySQL的Replication功能来实现数据的冗余,而是自行实现了数据冗余机制,而其底层主要是基于HibernateShards来实现的数据切分工作。

在HiveDB中,通过用户自己定义的各种Partitionkeys(事实上就是制定数据切分规则),将数据分散到多个MySQLServer中。在訪问的时候。在执行Query请求的时候。会自己主动分析过滤条件,并行从多个MySQLServer中读取数据,并合并结果集返回给client应用程序。

单纯从功能方面来讲,HiveDB可能并不如MySQLProxy和Amoeba那样强大,可是其数据切分的思路与前面二者并无本质差异。此外,HiveDB并不仅仅仅仅是一个开源爱好者所共享的内容,而是存在商业公司支持的开源项目。

以下是HiveDB官方站点上面一章图片,描写叙述了HiveDB怎样来组织数据的基本信息,尽管不能具体的表现出太多架构方面的信息,可是也基本能够展示出其在数据切分方面独特的一面了。

★ mycat 数据整合:具体http://www.songwie.com/articlelist/11

★ 其它实现数据切分及整合的解决方式

除了上面介绍的几个数据切分及整合的总体解决方式之外,还存在非常多其它相同提供了数据切分与整合的解决方式。如基于MySQLProxy的基础上做了进一步扩展的HSCALE,通过Rails构建的SpockProxy。以及基于Pathon的Pyshards等等。

无论大家选择使用哪一种解决方式,总体设计思路基本上都不应该会有不论什么变化。那就是通过数据的垂直和水平切分,增强数据库的总体服务能力,让应用系统的总体扩展能力尽可能的提升。扩展方式尽可能的便捷。

仅仅要我们通过中间层Proxy应用程序较好的攻克了数据切分和数据源整合问题。那么数据库的线性扩展能力将非常easy做到像我们的应用程序一样方便。仅仅须要通过加入便宜的PCServerserver,就可以线性添加数据库集群的总体服务能力,让数据库不再轻易成为应用系统的性能瓶颈。

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

 

这里。大家应该对数据切分与整合的实施有了一定的认识了。也许非常多读者朋友都已经依据各种解决方式各自特性的优劣基本选定了适合于自己应用场景的方案,后面的工作主要就是实施准备了。

在实施数据切分方案之前,有些可能存在的问题我们还是须要做一些分析的。

一般来说,我们可能遇到的问题主要会有以下几点:

◆ 引入分布式事务的问题。

◆跨节点Join的问题;

◆ 跨节点合并排序分页问题。

1. 引入分布式事务的问题

一旦数据进行切分被分别存放在多个MySQLServer中之后,无论我们的切分规则设计的多么的完美(实际上并不存在完美的切分规则),都可能造成之前的某些事务所涉及到的数据已经不在同一个MySQLServer中了。

在这样的场景下,假设我们的应用程序仍然依照老的解决方式。那么势必须要引入分布式事务来解决。而在MySQL各个版本号中,仅仅有从MySQL5.0開始以后的各个版本号才開始对分布式事务提供支持,并且眼下仅有Innodb提供分布式事务支持。不仅如此。即使我们刚好使用了支持分布式事务的MySQL版本号。同一时候也是使用的Innodb存储引擎,分布式事务本身对于系统资源的消耗就是非常大的,性能本身也并非太高。并且引入分布式事务本身在异常处理方面就会带来较多比較难控制的因素。

怎么办?事实上我们能够能够通过一个变通的方法来解决这样的问题。首先须要考虑的一件事情就是:是否数据库是唯一一个能够解决事务的地方呢?事实上并非这样的,我们全然能够结合数据库以及应用程序两者来共同解决。各个数据库解决自己身上的事务。然后通过应用程序来控制多个数据库上面的事务。

也就是说。仅仅要我们愿意。全然能够将一个跨多个数据库的分布式事务分拆成多个仅处于单个数据库上面的小事务。并通过应用程序来总控各个小事务。

当然,这样作的要求就是我们的俄应用程序必须要有足够的健壮性。当然也会给应用程序带来一些技术难度。

2.跨节点Join的问题

上面介绍了可能引入分布式事务的问题,如今我们再看看须要跨节点Join的问题。

数据切分之后。可能会造成有些老的Join语句无法继续使用。由于Join使用的数据源可能被切分到多个MySQLServer中了。

怎么办?这个问题从MySQL数据库角度来看,假设非得在数据库端来直接解决的话,恐怕仅仅能通过MySQL一种特殊的存储引擎Federated来攻克了。Federated存储引擎是MySQL解决相似于Oracle的DBLink之类问题的解决方式。

和OracleDBLink的主要差别在于Federated会保存一份远端表结构的定义信息在本地。咋一看,Federated确实是解决跨节点Join非常好的解决方式。可是我们还应该清晰一点,那就似乎假设远端的表结构发生了变更,本地的表定义信息是不会跟着发生对应变化的。假设在更新远端表结构的时候并没有更新本地的Federated表定义信息。就非常可能造成Query执行出错,无法得到正确的结果。

对待这类问题,我还是推荐通过应用程序来进行处理,先在驱动表所在的MySQLServer中取出对应的驱动结果集。然后依据驱动结果集再到被驱动表所在的MySQLServer中取出对应的数据。可能非常多读者朋友会觉得这样做对性能会产生一定的影响,是的,确实是会对性能有一定的负面影响,可是除了此法,基本上没有太多其它更好的解决的方法了。

并且,由于数据库通过较好的扩展之后,每台MySQLServer的负载就能够得到较好的控制。单纯针对单条Query来说,其响应时间可能比不切分之前要提高一些,所以性能方面所带来的负面影响也并非太大。更何况。相似于这样的须要跨节点Join的需求也并非太多。相对于总体性能而言,可能也仅仅是非常小一部分而已。所以为了总体性能的考虑,偶尔牺牲那么一点点。事实上是值得的。毕竟系统优化本身就是存在非常多取舍和平衡的过程。

3. 跨节点合并排序分页问题

一旦进行了数据的水平切分之后,可能就并不仅仅仅仅有跨节点Join无法正常执行,有些排序分页的Query语句的数据源可能也会被切分到多个节点。这样造成的直接后果就是这些排序分页Query无法继续正常执行。事实上这和跨节点Join是一个道理。数据源存在于多个节点上,要通过一个Query来解决,就和跨节点Join是一样的操作。相同Federated也能够部分解决。当然存在的风险也一样。

还是相同的问题,怎么办?我相同仍然继续建议通过应用程序来解决。

怎样解决?解决的思路大体上和跨节点Join的解决相似,可是有一点和跨节点Join不太一样。Join非常多时候都有一个驱动与被驱动的关系。所以Join本身涉及到的多个表之间的数据读取一般都会存在一个顺序关系。可是排序分页就不太一样了,排序分页的数据源基本上能够说是一个表(或者一个结果集)。本身并不存在一个顺序关系,所以在从多个数据源取数据的过程是全然能够并行的。

这样。排序分页数据的取数效率我们能够做的比跨库Join更高。所以带来的性能损失相对的要更小,在有些情况下可能比在原来未进行数据切分的数据库中效率更高了。

当然,不论是跨节点Join还是跨节点排序分页。都会使我们的应用server消耗很多其它的资源,尤其是内存资源,由于我们在读取訪问以及合并结果集的这个过程须要比原来处理很多其它的数据。

分析到这里,可能非常多读者朋友会发现,上面全部的这些问题,我给出的建议基本上都是通过应用程序来解决。大家可能心里開始犯嘀咕了。是不是由于我是DBA,所以就非常多事情都扔给应用架构师和开发人员了?

事实上全然不是这样,首先应用程序由于其特殊性。能够非常easy做到非常好的扩展性,可是数据库就不一样。必须借助非常多其它的方式才干做到扩展。并且在这个扩展过程中,非常难避免带来有些原来在集中式数据库中能够解决但被切分开成一个数据库集群之后就成为一个难题的情况。

要想让系统总体得到最大限度的扩展,我们仅仅能让应用程序做很多其它的事情。来解决数据库集群无法较好解决的问题。

小结

通过数据切分技术将一个大的MySQLServer切分成多个小的MySQLServer,既攻克了写入性能瓶颈问题,同一时候也再一次提升了整个数据库集群的扩展性。不论是通过垂直切分,还是水平切分。都能够让系统遇到瓶颈的可能性更小。尤其是当我们使用垂直和水平相结合的切分方法之后,理论上将不会再遇到扩展瓶颈了。

转自:http://songwie.com/

 

 

 

 

标签

发表评论