共计 4476 个字符,预计需要花费 12 分钟才能阅读完成。
这篇文章主要介绍“怎么理解 MySQL 垂直和水平切分”,在日常操作中,相信很多人在怎么理解 MySQL 垂直和水平切分问题上存在疑惑,丸趣 TV 小编查阅了各式资料,整理出简单好用的操作方法,希望对大家解答”怎么理解 MySQL 垂直和水平切分”的疑惑有所帮助!接下来,请跟着丸趣 TV 小编一起来学习吧!
replication 的限制: 一旦数据库过于庞大,尤其是当写入过于频繁,很难由一台主机支撑的时候,我们还是会面临到扩展瓶颈。数据切分 (sharding): 通过某种特定的条件,将我们存放在同一个数据库中的数据分散存放到多个数据库(主机)上面,以达到分散单台设备负载的效果。。数据的切分同时还可以提高系统的总体可用性,因为单台设备 Crash 之后,只有总体数据的某部分不可用,而不是所有的数据。
数据的切分(Sharding)模式
一种是按照不同的表(或者 Schema)来切分到不同的数据库(主机)之上,这种切可以称之为数据的垂直(纵向)切分;另外一种则是根据表中的数据的逻辑关系,将同一个表中的数据按照某种条件拆分到多台数据库(主机)上面,这种切分称之为数据的水平(横向)切分。
垂直切分:
一个架构设计较好的应用系统,其总体功能肯定是由很多个功能模块所组成的,而每一个功能模块所需要的数据对应到数据库中就是一个或者多个表。而在架构设计中,各个功能模块相互之间的交互点越统一越少,系统的耦合度就越低,系统各个模块的维护性以及扩展性也就越好。这样的系统,实现数据的垂直切分也就越容易。
一般来说,如果是一个负载相对不是很大的系统,而且表关联又非常的频繁,那可能数据库让步,将几个相关模块合并在一起减少应用程序的工作的方案可以减少较多的工作量,这是一个可行的方案。一个垂直拆分的例子:
1. 用户模块表:user,user_profile,user_group,user_photo_album
2. 群组讨论表:groups,group_message,group_message_content,top_message
3. 相册相关表:photo,photo_album,photo_album_relation,photo_comment
4. 事件信息表:event
群组讨论模块和用户模块之间主要存在通过用户或者是群组关系来进行关联。一般关联的时候都会是通过用户的 id 或者 nick_name 以及 group 的 id 来进行关联,通过模块之间的接口实现不会带来太多麻烦;
相册模块仅仅与用户模块存在通过用户的关联。这两个模块之间的关联基本就有通过用户 id 关联的内容,简单清晰,接口明确;
事件模块与各个模块可能都有关联,但是都只关注其各个模块中对象的 ID 信息,同样可以做到很容易分拆。
垂直切分的优点
数据库的拆分简单明了,拆分规则明确;
应用程序模块清晰明确,整合容易;
数据维护方便易行,容易定位;
垂直切分的缺点
部分表关联无法在数据库级别完成,需要在程序中完成;
对于访问极其频繁且数据量超大的表仍然存在性能瓶颈,不一定能满足要求;
事务处理相对更为复杂;
切分达到一定程度之后,扩展性会遇到限制;
过读切分可能会带来系统过渡复杂而难以维护。
水平切分
将某个访问极其频繁的表再按照某个字段的某种规则来分散到多个表之中,每个表中包含一部分数据。
对于上面的例子: 所有数据都是和用户关联的,那么我们就可以根据用户来进行水平拆分,将不同用户的数据切分到不同的数据库中。
现在互联网非常火爆的 Web2.0 类型的网站,基本上大部分数据都能够通过会员用户信息关联上,可能很多核心表都非常适合通过会员 ID 来进行数据的水平切分。而像论坛社区讨论系统,就更容易切分了,非常容易按照论坛编号来进行数据的水平切分。切分之后基本上不会出现各个库之间的交互。
水平切分的优点
表关联基本能够在数据库端全部完成;
不会存在某些超大型数据量和高负载的表遇到瓶颈的问题;
应用程序端整体架构改动相对较少;
事务处理相对简单;
只要切分规则能够定义好,基本上较难遇到扩展性限制;
水平切分的缺点
切分规则相对更为复杂,很难抽象出一个能够满足整个数据库的切分规则;
后期数据的维护难度有所增加,人为手工定位数据更困难;
应用系统各模块耦合度较高,可能会对后面数据的迁移拆分造成一定的困难。
两种切分结合用:
一般来说,我们数据库中的所有表很难通过某一个(或少数几个)字段全部关联起来,所以很难简单的仅仅通过数据的水平切分来解决所有问题。而垂直切分也只能解决部分问题,对于那些负载非常高的系统,即使仅仅只是单个表都无法通过单台数据库主机来承担其负载。我们必须结合“垂直”和“水平”两种切分方式同时使用
每一个应用系统的负载都是一步一步增长上来的,在开始遇到性能瓶颈的时候,大多数架构师和 DBA 都会选择先进行数据的垂直拆分,因为这样的成本最先,最符合这个时期所追求的最大投入产出比。然而,随着业务的不断扩张,系统负载的持续增长,在系统稳定一段时期之后,经过了垂直拆分之后的数据库集群可能又再一次不堪重负,遇到了性能瓶颈。
如果我们再一次像最开始那样继续细分模块,进行数据的垂直切分,那我们可能在不久的将来,又会遇到现在所面对的同样的问题。而且随着模块的不断的细化,应用系统的架构也会越来越复杂,整个系统很可能会出现失控的局面。
这时候我们就必须要通过数据的水平切分的优势,来解决这里所遇到的问题。而且,我们完全不必要在使用数据水平切分的时候,推倒之前进行数据垂直切分的成果,而是在其基础上利用水平切分的优势来避开垂直切分的弊端,解决系统复杂性不断扩大的问题。而水平拆分的弊端(规则难以统一)也已经被之前的垂直切分解决掉了,让水平拆分可以进行的得心应手。
示例数据库:
假设在最开始,我们进行了数据的垂直切分,然而随着业务的不断增长,数据库系统遇到了瓶颈,我们选择重构数据库集群的架构。如何重构?考虑到之前已经做好了数据的垂直切分,而且模块结构清晰明确。而业务增长的势头越来越猛,即使现在进一步再次拆分模块,也坚持不了太久。
== 选择了在垂直切分的基础上再进行水平拆分。
== 在经历过垂直拆分后的各个数据库集群中的每一个都只有一个功能模块,而每个功能模块中的所有表基本上都会与某个字段进行关联。如用户模块全部都可以通过用户 ID 进行切分,群组讨论模块则都通过群组 ID 来切分,相册模块则根据相册 ID 来进切分,最后的事件通知信息表考虑到数据的时限性(仅仅只会访问最近某个事件段的信息),则考虑按时间来切分。
数据切分以及整合方案.
数据库中的数据在经过垂直和(或)水平切分被存放在不同的数据库主机之后,应用系统面临的最大问题就是如何来让这些数据源得到较好的整合,其中存在两种解决思路:
在每个应用程序模块中配置管理自己需要的一个(或者多个)数据源,直接访问各个数据库,在模块内完成数据的整合;
通过中间代理层来统一管理所有的数据源,后端数据库集群对前端应用程序透明;
第二种方案, 虽然短期内需要付出的成本可能会相对更大一些,但是对整个系统的扩展性来说,是非常有帮助的。针对第二种方案,可以选择的方法和思路有:
1. 利用 MySQLProxy 实现数据切分及整合.
可用来监视、分析或者传输他们之间的通讯信息。他的灵活性允许你最大限度的使用它,目前具备的功能主要有连接路由,Query 分析,Query 过滤和修改,负载均衡,以及基本的 HA 机制等。MySQLProxy 本身并不具有上述所有的这些功能,而是提供了实现上述功能的基础。要实现这些功能,还需要通过我们自行编写 LUA 脚本来实现。
原理:MySQLProxy 实际上是在客户端请求与 MySQLServer 之间建立了一个连接池。所有客户端请求都是发向 MySQLProxy,然后经由 MySQLProxy 进行相应的分析,判断出是读操作还是写操作,分发至对应的 MySQLServer 上。对于多节点 Slave 集群,也可以起做到负载均衡的效果。
2. 利用 Amoeba 实现数据切分及整合
Amoeba 是一个基于 Java 开发的,专注于解决分布式数据库数据源整合 Proxy 程序的开源框架,Amoeba 已经具有 Query 路由,Query 过滤,读写分离,负载均衡以及 HA 机制等相关内容。Amoeba 主要解决的以下几个问题:
数据切分后复杂数据源整合;
提供数据切分规则并降低数据切分规则给数据库带来的影响;
降低数据库与客户端的连接数;
读写分离路由;
AmoebaFor MySQL 主要是专门针对 MySQL 数据库的解决方案,前端应用程序请求的协议以及后端连接的数据源数据库都必须是 MySQL。对于客户端的任何应用程序来说,AmoebaForMySQL 和一个 MySQL 数据库没有什么区别,任何使用 MySQL 协议的客户端请求,都可以被 AmoebaFor MySQL 解析并进行相应的处理。
Proxy 程序常用的功能如读写分离,负载均衡等配置都在 amoeba.xml 中进行。Amoeba 已经支持了实现数据的垂直切分和水平切分的自动路由,路由规则可以在 rule.xml 进行设置。
3. 利用 HiveDB 实现数据切分及整合
HiveDB 同样是一个基于 Java 针对 MySQL 数据库的提供数据切分及整合的开源框架,只是目前的 HiveDB 仅仅支持数据的水平切分。主要解决大数据量下数据库的扩展性及数据的高性能访问问题,同时支持数据的冗余及基本的 HA 机制。
HiveDB 的实现机制与 MySQLProxy 和 Amoeba 有一定的差异,他并不是借助 MySQL 的 Replication 功能来实现数据的冗余,而是自行实现了数据冗余机制,而其底层主要是基于 HibernateShards 来实现的数据切分工作。数据切分与整合中可能存在的问题
引入分布式事务的问题?
一旦数据进行切分被分别存放在多个 MySQLServer 中之后,不管我们的切分规则设计的多么的完美(实际上并不存在完美的切分规则),都可能造成之前的某些事务所涉及到的数据已经不在同一个 MySQLServer 中了。
== 将一个跨多个数据库的分布式事务分拆成多个仅处于单个数据库上面的小事务,并通过应用程序来总控各个小事务。
跨节点 Join 的问题?
== 先从一个节点取出数据, 然后根据这些数据, 再到另一个表中取数据.
== 使用 Federated 存储引擎, 问题是: 乎如果远端的表结构发生了变更,本地的表定义信息是不会跟着发生相应变化的。
跨节点合并排序分页问题?
== Join 本身涉及到的多个表之间的数据读取一般都会存在一个顺序关系。但是排序分页就不太一样了,排序分页的数据源基本上可以说是一个表(或者一个结果集),本身并不存在一个顺序关系,所以在从多个数据源取数据的过程是完全可以并行的。这样,排序分页数据的取数效率我们可以做的比跨库 Join 更高,所以带来的性能损失相对的要更小。
到此,关于“怎么理解 MySQL 垂直和水平切分”的学习就结束了,希望能够解决大家的疑惑。理论与实践的搭配能更好的帮助大家学习,快去试试吧!若想继续学习更多相关知识,请继续关注丸趣 TV 网站,丸趣 TV 小编会继续努力为大家带来更多实用的文章!