一 背景html
咱们知道,当数据库中的数据量愈来愈大时,不管是读仍是写,压力都会变得愈来愈大。采用MySQL Replication多master多slave方案,在上层作负载均衡,虽然可以必定程度上缓解压力。可是当一张表中的数据变得很是庞大时,压力仍是 很是大的。试想,若是一张表中的数据量达到了千万甚至上亿级别的时候,无论是建索引,优化缓存等,都会面临巨大的性能压力。前端
二 定义mysql
数据sharding,也称做数据切分,或分区。是指经过某种条件,把同一个数据库中的数据分散到多个数据库或多台机器上,以减少单台机器压力。git
三 分类github
数据分区根据切分规则,能够分为两类:sql
1、垂直切分数据库
数据的垂直切分,也能够称之为纵向切分。将数据库想象成为由不少个一大块一大块的“数据块”(表)组成,咱们垂直的将这些“数据块”切开,而后将他们分散 到多台数据库主机上面。这样的切分方法就是一个垂直(纵向)的数据切分。以表为单位,把不一样的表分散到不一样的数据库或主机上。规则简单,实施方便,适合业 务之间耦合度低的系统。编程
Sharding详解" title="MySQL Sharding详解" height="373" width="553">后端
垂直切分的优势缓存
(1)数据库的拆分简单明了,拆分规则明确;
(2)应用程序模块清晰明确,整合容易;
(3)数据维护方便易行,容易定位;
垂直切分的缺点
(1)部分表关联没法在数据库级别完成,须要在程序中完成;
(2)对于访问极其频繁且数据量超大的表仍然存在性能平静,不必定能知足要求;
(3)事务处理相对更为复杂;
(4) 切分达到必定程度以后,扩展性会遇到限制;
(5)过读切分可能会带来系统过渡复杂而难以维护。
2、水平切分
通常来讲,简单的水平切分主要是将某个访问极其平凡的表再按照某个字段的某种规则来分散到多个表之中,每一个表中包含一部分数据。以行为单位,将同一个表中的数据按照某种条件拆分到不一样的数据库或主机上。相对复杂,适合单表巨大的系统。
Sharding详解" title="MySQL Sharding详解" height="372" width="553">
水平切分的优势
(1)表关联基本可以在数据库端所有完成;
(2)不会存在某些超大型数据量和高负载的表遇到瓶颈的问题;
(3)应用程序端总体架构改动相对较少;
(4)事务处理相对简单;
(5)只要切分规则可以定义好,基本上较难遇到扩展性限制;
水平切分的缺点
(1)切分规则相对更为复杂,很难抽象出一个可以知足整个数据库的切分规则;
(2)后期数据的维护难度有所增长,人为手工定位数据更困难;
(3)应用系统各模块耦合度较高,可能会对后面数据的迁移拆分形成必定的困难。
3、联合切分
实际的应用场景中,除了那些负载并非太大,业务逻辑也相对较简单的系统能够经过上面两种切分方法之一来解决扩展性问题以外,恐怕其余大部分业务逻辑稍微 复杂一点,系统负载大一些的系统,都没法经过上面任何一种数据的切分方法来实现较好的扩展性,而须要将上述两种切分方法结合使用,不一样的场景使用不一样的切 分方法。
Sharding详解" title="MySQL Sharding详解" height="480" width="342">
联合切分的优势
(1)能够充分利用垂直切分和水平切分各自的优点而避免各自的缺陷;
(2)让系统扩展性获得最大化提高;
联合切分的缺点
(1)数据库系统架构比较复杂,维护难度更大;
(2)应用程序架构也相对更复杂;
四 实现方案
如今 Sharding 相关的软件实现其实很多,基于数据库层、DAO 层、不一样语言下也都不乏案例。限于篇幅,此处只做一下简要的介绍。
1、 Mysql Proxy + HASCALE
一套比较有潜力的方案。其中MySQL Proxy 是用 Lua 脚本实现的,介于客户端与服务器端之间,扮演 Proxy 的角色,提供查询分析、失败接管、查询过滤、调整等功能。目前的 0.6 版本还作不到读、写分离。HSCALE 则是针对 MySQL Proxy 插件,也是用 Lua 实现的,对 Sharding 过程简化了许多。须要指出的是,MySQL Proxy 与 HSCALE 各自会带来必定的开销,但这个开销与集中式数据处理方式单条查询的开销仍是要小的。
MySQLProxy是MySQL官方提供的一个数据库代理层产品,和MySQLServer同样,一样是一个基于GPL开源协议的开源产品。可用来监视、分析或者传输他们之间的通信信息。他的灵活性容许你最大限度的使用它,目前具有的功能主要有链接路由,Query分析,Query过滤和修改,负载均衡,以及基本的HA机制等。
实际上,MySQLProxy自己并不具备上述全部的这些功能,而是提供了实现上述功能的基础。要实现这些功能,还须要经过咱们自行编写LUA脚原本实现。
MySQLProxy其实是在客户端请求与MySQLServer之间创建了一个链接池。全部客户端请求都是发向MySQLProxy,而后经由MySQLProxy进行相应的分析,判断出是读操做仍是写操做,分发至对应的MySQLServer上。对于多节点Slave集群,也能够起作到负载均衡的效果。如下是MySQLProxy的基本架构图:
Sharding详解" title="MySQL Sharding详解" height="480" width="420">
经过上面的架构简图,咱们能够很清晰的看出MySQLProxy在实际应用中所处的位置,以及能作的基本事情。关于MySQLProxy更为详细的实施细则在MySQL官方文档中有很是详细的介绍和示例,感兴趣的读者朋友能够直接从MySQL官方网站免费下载或者在线阅读,我这里就不累述浪费纸张了。
http://forge.mysql.com/wiki/MySQL_Proxy
2、 Hibernate Shards
这是 Google 技术团队贡献的项目(http://www.hibernate.org/414.html),该项目是在对Google 财务系统数据 Sharding 过程当中诞生的。由于是在框架层实现的,因此有其独特的特性:标准的 Hibernate 编程模型,会用 Hibernate 就能搞定,技术成本较低;相对弹性的 Sharding 策略以及支持虚拟 Shard 等。
3、 Spock Proxy
这也是在实际需求中产生的一个开源项目,基于Mysql Proxy扩展。Spock(http://www.spock.com/)是一我的员查找的 Web 2.0 网站。经过对本身的单一 DB 进行有效 Sharding化 而产生了Spock Proxy(http://spockproxy.sourceforge.net/ ) 项目,Spock Proxy 算得上 MySQL Proxy 的一个分支,提供基于范围的 Sharding 机制。Spock 是基于 Rails 的,因此Spock Proxy 也是基于 Rails 构建,关注 ROR 的朋友不该错过这个项目。
http://spockproxy.sourceforge.net/
4、 Amoeba for MySQL
Amoeba是一个基于Java开发的,专一于解决分布式数据库数据源整合Proxy程序的开源框架,基于GPL3开源协议。目前,Amoeba已经具备Query路由,Query过滤,读写分离,负载均衡以及HA机制等相关内容。
Amoeba 主要解决的如下几个问题:
(1)数据切分后复杂数据源整合;
(2)提供数据切分规则并下降数据切分规则给数据库带来的影响;
(3)下降数据库与客户端的链接数;
(4)读写分离路由。
咱们能够看出,Amoeba所作的事情,正好就是咱们经过数据切分来提高数据库的扩展性所须要的。
Amoeba并非一个代理层的Proxy程序,而是一个开发数据库代理层Proxy程序的开发框架,目前基于Amoeba所开发的Proxy程序有AmoebaForMySQL和AmoebaForAladin两个。
AmoebaForMySQL主要是专门针对MySQL数据库的解决方案,前端应用程序请求的协议以及后端链接的数据源数据库都必须是MySQL。对于客户端的任何应用程序来讲,AmoebaForMySQL和一个MySQL数据库没有什么区别,任何使用MySQL协议的客户端请求,均可以被AmoebaForMySQL解析并进行相应的处理。下如能够告诉咱们AmoebaForMySQL的架构信息(出自Amoeba开发者博客):
Sharding详解" title="MySQL Sharding详解" height="480" width="384">
AmoebaForAladin则是一个适用更为普遍,功能更为强大的Proxy程序。他能够同时链接不一样数据库的数据源为前端应用程序提供服务,可是仅仅接受符合MySQL协议的客户端应用程序请求。也就是说,只要前端应用程序经过MySQL协议链接上来以后,AmoebaForAladin会自动分析Query语句,根据Query语句中所请求的数据来自动识别出该所Query的数据源是在什么类型数据库的哪个物理主机上面。下图展现了AmoebaForAladin的架构细节(出自Amoeba开发者博客):
Sharding详解" title="MySQL Sharding详解" height="480" width="384">
咋一看,二者好像彻底同样嘛。细看以后,才会发现二者主要的区别仅在于经过MySQLProtocalAdapter处理以后,根据分析结果判断出数据源数据库,而后选择特定的JDBC驱动和相应协议链接后端数据库。
其实经过上面两个架构图你们可能也已经发现了Amoeba的特色了,他仅仅只是一个开发框架,咱们除了选择他已经提供的ForMySQL和ForAladin这两款产品以外,还能够基于自身的需求进行相应的二次开发,获得更适应咱们本身应用特色的Proxy程序。
当对于使用MySQL数据库来讲,不管是AmoebaForMySQL仍是AmoebaForAladin均可以很好的使用。固然,考虑到任何一个系统越是复杂,其性能确定就会有必定的损失,维护成本天然也会相对更高一些。因此,对于仅仅须要使用MySQL数据库的时候,我仍是建议使用AmoebaForMySQL。
AmoebaForMySQL的使用很是简单,全部的配置文件都是标准的XML文件,总共有四个配置文件。分别为:
(1)amoeba.xml:主配置文件,配置全部数据源以及Amoeba自身的参数设置;
(2)rule.xml:配置全部Query路由规则的信息;
(3)functionMap.xml:配置用于解析Query中的函数所对应的Java实现类;
(4)rullFunctionMap.xml:配置路由规则中须要使用到的特定函数的实现类;
若是您的规则不是太复杂,基本上仅须要使用到上面四个配置文件中的前面两个就可完成全部工做。Proxy程序经常使用的功能如读写分离,负载均衡等配置都在amoeba.xml中进行。此外,Amoeba已经支持了实现数据的垂直切分和水平切分的自动路由,路由规则能够在rule.xml进行设置。
目前Amoeba少有欠缺的主要就是其在线管理功能以及对事务的支持了,曾经在与相关开发者的沟经过程中提出过相关的建议,但愿可以提供一个能够进行在线维护管理的命令行管理工具,方便在线维护使用,获得的反馈是管理专门的管理模块已经归入开发日程了。另外在事务支持方面暂时仍是Amoeba没法作到的,即便客户端应用在提交给Amoeba的请求是包含事务信息的,Amoeba也会忽略事务相关信息。固然,在通过不断完善以后,我相信事务支持确定是Amoeba重点考虑增长的feature。
关于Amoeba更为详细的使用方法读者朋友能够经过Amoeba开发者博客(http://amoeba.sf.net)上面提供的使用手册获取,这里就再也不细述了。
案例(http://pengranxiang.iteye.com/blog/1145342)
操做文档(http://docs.hexnova.com/amoeba/chap-getting-started.html)
5、 HiveDB
和前面的MySQLProxy以及Amoeba同样,HiveDB一样是一个基于Java针对MySQL数据库的提供数据切分及整合的开源框架,只是目前的HiveDB仅仅支持数据的水平切分。主要解决大数据量下数据库的扩展性及数据的高性能访问问题,同时支持数据的冗余及基本的HA机制。
HiveDB的实现机制与MySQLProxy和Amoeba有必定的差别,他并非借助MySQL的Replication功能来实现数据的冗余,而是自行实现了数据冗余机制,而其底层主要是基于HibernateShards来实现的数据切分工做。
在HiveDB中,经过用户自定义的各类Partitionkeys(其实就是制定数据切分规则),将数据分散到多个MySQLServer中。在访问的时候,在运行Query请求的时候,会自动分析过滤条件,并行从多个MySQLServer中读取数据,并合并结果集返回给客户端应用程序。
单纯从功能方面来说,HiveDB可能并不如MySQLProxy和Amoeba那样强大,可是其数据切分的思路与前面两者并没有本质差别。此外,HiveDB并不只仅只是一个开源爱好者所共享的内容,而是存在商业公司支持的开源项目。
下面是HiveDB官方网站上面一章图片,描述了HiveDB如何来组织数据的基本信息,虽然不能详细的表现出太多架构方面的信息,可是也基本能够展现出其在数据切分方面独特的一面了。
Sharding详解" title="MySQL Sharding详解" height="471" width="553">
http://www.hivedb.org/
6、 DataFabric
application-level sharding
master/slave replication
https://github.com/bpot/data_fabric
7、PL/Proxy
前面几个都是针对MySQL 的 Sharding 方案,PL/Proxy 则是针对 PostgreSQL 的,设计思想相似 Teradata 的 Hash 机制,数据存储对客户端是透明的,客户请求发送到 PL/Proxy 后,由这里分布式存储过程调用,统一分发。 PL/Proxy 的设计初衷就是在这一层充当”数据总线”的职责,因此,当数据吞吐量支撑不住的时候,只须要增长更多的 PL/Proxy 服务器便可。大名鼎鼎的 Skype 用的就是 PL/Proxy 的解决方案。
8、Pyshards
这是个基于Python的解决方案。该工具的设计目标还有个 Re-balancing 在里面,这却是个比较激进的想法。目前只支持 MySQL 数据库。
http://code.google.com/p/pyshards/wiki/Pyshards
9、其余实现数据切分及整合的解决方案
除了上面介绍的几个数据切分及整合的总体解决方案以外,还存在不少其余一样提供了数据切分与整合的解决方案。如基于MySQLProxy的基础上作了进一步扩展的HSCALE,经过Rails构建的SpockProxy,以及基于Pathon的Pyshards等等。
无论你们选择使用哪种解决方案,整体设计思路基本上都不该该会有任何变化,那就是经过数据的垂直和水平切分,加强数据库的总体服务能力,让应用系统的总体扩展能力尽量的提高,扩展方式尽量的便捷。
只要咱们经过中间层Proxy应用程序较好的解决了数据切分和数据源整合问题,那么数据库的线性扩展能力将很容易作到像咱们的应用程序同样方便,只须要经过添加廉价的PCServer服务器,便可线性增长数据库集群的总体服务能力,让数据库再也不轻易成为应用系统的性能瓶颈。
五 注意事项
下面咱们所说的分区,主要是指水平分区。
一、在实施分区前,咱们能够查看所安装版本的mysql是否支持分区:
mysql> show variables like "%partition%";
若是支持则会显示:
+-------------------+-------+
| Variable_name | Value |
+-------------------+-------+
| have_partitioning | YES |
+-------------------+-------+
二、分区适用于一个表的全部数据和索引,不能只对数据分区而不对索引分区,反之亦然,同时也不能只对表的一部分进行分区。
三、分区类型
(1)RANGE 分区:基于属于一个给定连续区间的列值,把多行分配给分区。
(2)LIST 分区:相似于按RANGE分区,区别在于LIST分区是基于列值匹配一个离散值集合中的某个值来进行选择。
(3)HASH分区:基于用户定义的表达式的返回值来进行选择的分区,该表达式使用将要插入到表中的这些行的列值进行计算(新浪微博采用的方案)。
(4)KEY 分区:相似于按HASH分区,区别在于KEY分区只支持计算一列或多列,且MySQL 服务器提供其自身的哈希函数。必须有一列或多列包含整数值。
不管使用何种类型的分区,分区老是在建立时就自动的顺序编号,且从0开始记录。当有一新行插入到一个分区表中时,就是使用这些分区编号来识别正确的分区。
四、MySQL提供了许多修改分区表的方式。添加、删除、从新定义、合并或拆分已经存在的分区是可能的。全部这些操做均可以经过使用ALTER TABLE 命令的分区扩展来实现。
五、能够对已经存在的表进行分区,直接使用alter table命令便可。
六 数据切分与整合可能存在的问题
这里,你们应该对数据切分与整合的实施有了必定的认识了,或许不少读者朋友都已经根据各类解决方案各自特性的优劣基本选定了适合于本身应用场景的方案,后面的工做主要就是实施准备了。
在实施数据切分方案以前,有些可能存在的问题咱们仍是须要作一些分析的。通常来讲,咱们可能遇到的问题主要会有如下几点:
一、引入分布式事务的问题
一旦数据进行切分被分别存放在多个MySQLServer中以后,无论咱们的切分规则设计的多么的完美(实际上并不存在完美的切分规则),均可能形成以前的某些事务所涉及到的数据已经不在同一个MySQLServer中了。
在这样的场景下,若是咱们的应用程序仍然按照老的解决方案,那么势必须要引入分布式事务来解决。而在MySQL各个版本中,只有从MySQL5.0开始之后的各个版本才开始对分布式事务提供支持,并且目前仅有Innodb提供分布式事务支持。不只如此,即便咱们恰好使用了支持分布式事务的MySQL版本,同时也是使用的Innodb存储引擎,分布式事务自己对于系统资源的消耗就是很大的,性能自己也并非过高。并且引入分布式事务自己在异常处理方面就会带来较多比较难控制的因素。
怎么办?其实咱们能够能够经过一个变通的方法来解决这种问题,首先须要考虑的一件事情就是:是否数据库是惟一一个可以解决事务的地方呢?其实并非这样 的,咱们彻底能够结合数据库以及应用程序二者来共同解决。各个数据库解决本身身上的事务,而后经过应用程序来控制多个数据库上面的事务。
也就是说,只要咱们愿意,彻底能够将一个跨多个数据库的分布式事务分拆成多个仅处于单个数据库上面的小事务,并经过应用程序来总控各个小事务。固然,这样做的要求就是咱们的俄应用程序必需要有足够的健壮性,固然也会给应用程序带来一些技术难度。
二、跨节点Join的问题
上面介绍了可能引入分布式事务的问题,如今咱们再看看须要跨节点Join的问题。数据切分以后,可能会形成有些老的Join语句没法继续使用,由于Join使用的数据源可能被切分到多个MySQLServer中了。
怎么办?这个问题从MySQL数据库角度来看,若是非得在数据库端来直接解决的话,恐怕只能经过MySQL一种特殊的存储引擎Federated来解决了。Federated存储引擎是MySQL解决相似于Oracle的DBLink之类问题的解决方案。和OracleDBLink的主要区别在于Federated会保存一份远端表结构的定义信息在本地。咋一看,Federated确实是解决跨节点Join很是好的解决方案。可是咱们还应该清楚一点,那就彷佛若是远端的表结构发生了变动,本地的表定义信息是不会跟着发生相应变化的。若是在更新远端表结构的时候并无更新本地的Federated表定义信息,就极可能形成Query运行出错,没法获得正确的结果。
对待这类问题,我仍是推荐经过应用程序来进行处理,先在驱动表所在的MySQLServer中取出相应的驱动结果集,而后根据驱动结果集再到被驱动表所在的MySQLServer中取出相应的数据。可能不少读者朋友会认为这样作对性能会产生必定的影响,是的,确实是会对性能有必定的负面影响,可是除了此法,基本上没有太多其余更好的解决办法了。并且,因为数据库经过较好的扩展以后,每台MySQLServer的负载就能够获得较好的控制,单纯针对单条Query来讲,其响应时间可能比不切分以前要提升一些,因此性能方面所带来的负面影响也并非太大。更况且,相似于这种须要跨节点Join的需求也并非太多,相对于整体性能而言,可能也只是很小一部分而已。因此为了总体性能的考虑,偶尔牺牲那么一点点,实际上是值得的,毕竟系统优化自己就是存在不少取舍和平衡的过程。
三、跨节点合并排序分页问题
一旦进行了数据的水平切分以后,可能就并不只仅只有跨节点Join没法正常运行,有些排序分页的Query语句的数据源可能也会被切分到多个节点,这样形成的直接后果就是这些排序分页Query没法继续正常运行。其实这和跨节点Join是一个道理,数据源存在于多个节点上,要经过一个Query来解决,就和跨节点Join是同样的操做。一样Federated也能够部分解决,固然存在的风险也同样。
仍是一样的问题,怎么办?我一样仍然继续建议经过应用程序来解决。
如何解决?解决的思路大致上和跨节点Join的解决相似,可是有一点和跨节点Join不太同样,Join不少时候都有一个驱动与被驱动的关系,因此Join本 身涉及到的多个表之间的数据读取通常都会存在一个顺序关系。可是排序分页就不太同样了,排序分页的数据源基本上能够说是一个表(或者一个结果集),自己并 不存在一个顺序关系,因此在从多个数据源取数据的过程是彻底能够并行的。这样,排序分页数据的取数效率咱们能够作的比跨库Join更高,因此带来的性能损失相对的要更小,在有些状况下可能比在原来未进行数据切分的数据库中效率更高了。固然,不管是跨节点Join仍是跨节点排序分页,都会使咱们的应用服务器消耗更多的资源,尤为是内存资源,由于咱们在读取访问以及合并结果集的这个过程须要比原来处理更多的数据。
分析到这里,可能不少读者朋友会发现,上面全部的这些问题,我给出的建议基本上都是经过应用程序来解决。你们可能内心开始犯嘀咕了,是否是由于我是DBA,因此就不少事情都扔给应用架构师和开发人员了?
其实彻底不是这样,首先应用程序因为其特殊性,能够很是容易作到很好的扩展性,可是数据库就不同,必须借助不少其余的方式才能作到扩展,并且在这个扩展 过程当中,很难避免带来有些原来在集中式数据库中能够解决但被切分开成一个数据库集群以后就成为一个难题的状况。要想让系统总体获得最大限度的扩展,咱们只 能让应用程序作更多的事情,来解决数据库集群没法较好解决的问题。
七 MySQL基于Amoeba的水平和垂直分片示例
详细的配置描述请参考:http://pengranxiang.iteye.com/blog/1145342