MySQL 可扩展设计的基本原则


Posted in MySQL onMay 14, 2021

前言

随着信息量的飞速增加,硬件设备的发展已经慢慢的无法跟上应用系统对处理能力的要求了。此时,我们如何来解决系统对性能的要求?

只有一个办法,那就是通过改造系统的架构体系,提升系统的扩展能力,通过组合多个低处理能力的硬件设备来达到一个高处理能力的系统,也就是说,我们必须进行可扩展设计。

一、什么是可扩展性

在讨论可扩展性之前,可能很多朋有会问:常听人说起某某网站某某系统在可扩展性方面设计的如何如何好,架构如何如何出色,到底什么是扩展?怎样算是可扩展?什么又是可扩展性呢?其实也就是大家常听到的 Scale,Scalable 和 Scalability 这三个词。

从数据库的角度来说,Scale(扩展)就是让我们的数据库能够提供更强的服务能力,更强的处理能力。而 Scalable(可扩展)则是表明数据库系统在通过相应升级(包括增加单机处理能力或者增加服务器数量)之后能够达到提供更强处理能力。在理论能上来说,任何数据库系统都是 Scalable 的,只不过是所需要的实现方式不一样而已。

最后, Scalability(扩展性)则是指一个数据库系统通过相应的升级之后所带来处理能力提升的难以程度。虽然理论上任何系统都可以通过相应的升级来达到处理能力的提升,但是不同的系统提升相同的处理能力所需要的升级成本(资金和人力)是不一样的,这也就是我们所说的各个数据库应用系统的 Scalability 存在很大的差异。

在这里,我所说的不同数据库应用系统并不是指数据库软件本身的不同(虽然数据库软件不同也会存在 Scalability 的差异),而是指相同数据库软件的不同应用架构设计。

首先,我们需要清楚一个数据库据系统的扩展性实际上是主要体现在两个方面,一个是横向扩展,另一个则是纵向扩展,也就是我们常说的 Scale Out 和 Scale Up。

Scale Out 就是指横向的扩展,向外扩展,也就是通过增加处理节点的方式来提高整体处理能力,说的更实际一点就是通过增加机器来增加整体的处理能力。

Scale Up 则是指纵向的扩展,向上扩展,也就是通过增加当前处理节点的处理能力来提高整体的处理能力,说白了就是通过升级现有服务器的配置,如增加内存,增加 CPU,增加存储系统的硬件配置,或者是直接更换为处理能力更强的服务器和更为高端的存储系统。

通过比较两种 Scale 方式,我们很容易看出各自的优缺点。

Scale Out 优点:

  1. 成本低,很容易通过价格低廉的 PC Server 搭建出一个处理能力非常强大的计算集群;
  2. 不太容易遇到瓶颈,因为很容易通过添加主机来增加处理能力;
  3. 单个节点故障对系统整体影响较小;也存在缺点,更多的计算节点,大部分时候都是服务器主机,这自然会带来整个系统维护复杂性的提高,在某些方面肯定会增加维护成本,而且对应用系统的架构要求也会比 Scale Up 更高,需要集群管理软件的配合。

Scale Out 缺点:

  1. 处理节点多,造成系统架构整体复杂度提高,应用程序复杂度提高;
  2. 集群维护难以程度更高,维护成本更大;

Scale Up 优点:

  1. 处理节点少,维护相对简单;
  2. 所有数据都集中在一起,应用系统架构简单,开发相对容易;

Scale Up 缺点:

高端设备成本高,且竞争少,容易受到厂家限制;
受到硬件设备发展速度限制,单台主机的处理能力总是有极限的,容易遇到最终无法解决的性能瓶颈;
设备和数据集中,发生故障后的影响较大;
从短期来看,Scale Up 会有更大的优势,因为可以简化运维成本,简化系统架构和应用系统的开发,对技术方面的要求要会更简单一些。

但是,从长远影响来看,Scale Out 会有更大的优势,而且也是系统达到一个规模之后的必然趋势。因为不管怎样,单台机器的处理能力总是会受到硬件技术的限制,而硬件技术的发展速度总是有限的,很多时候很难跟得上业务发展的速度。而且越是高处理能力的高端设备,其性价比总是会越差。所以通过多台廉价的 PC Server 构建高处理能力的分布式集群,总是会成为各个公司节约成本,提高整体处理能力的一个目标。虽然在实现这个目标的时候可能会遇到各种各样的技术问题,但总是值得去研究实践的。

后面的内容,我们将重点针对 Scale Out 方面来进行分析设计。要能够很好的 Scale Out,势必需要进行分布式的系统设计。对于数据库,要想较好的 Scale Out,我们只有两个方向,一个是通过数据的不断复制来实现很多个完全一样的数据源来进行扩展,另一个就是通过将一个集中的数据源切分成很多个数据源来实现扩展。

下面我们先看看在设计一个具有很好的 Scalability 的数据库应用系统架构方面,需要遵循一些什么样的原则。

二、事务相关性最小化原则

搭建分布式数据库集群的时候,很多人都会比较关心事务的问题。毕竟事务是数据库中非常核心的一个功能。

在传统的集中式数据库架构中,事务的问题非常好解决,可以完全依赖数据库本身非常成熟的事务机制来保证。但是一旦我们的数据库作为分布式的架构之后,很多原来在单一数据库中所完成的事务现在可能需要跨多个数据库主机,这样原来单机事务可能就需要引入分布式事务的概念。

但是大家肯定也有一些了解,分布式事务本身就是一个非常复杂的机制,不管是商业的大型数据库系统还是各开源数据库系统,虽然大多数数据库厂家基本上都实现了这个功能,但或多或少都存在各种各样的限制。而且也存在一些 Bug,可能造成某些事务并不能很好的保证,或者是不能顺利的完成。

这时候,我们可能就需要寻求其他的替代方案来解决这个问题,毕竟事务是不可忽视的 ,不关我们如何去实现,总是需要实现的。

就目前来说,主要存在的一些解决方案主要有以下三种:

第一、进行 Scale Out 设计的时候合理设计切分规则,尽可能保证事务所需数据在同一个 MySQL Server 上,避免分布式事务。

如果可以在设计数据切分规则的时候就做到所有事务都能够在单个 MySQL Server 上面完成,我们的业务需求就可以比较容易的实现,应用程序就可以做到通过最少的调整来满足架构的改动,使整体成本大大减少。毕竟,数据库架构改造并不仅仅只是 DBA 的事情,还需要很多外围的配合与支持。即使是在设计一个全新系统的时候,我们同样要考虑到各个环境各项工作的整体投入,既要考虑数据库本身的成本投入,同时也要考虑到相应的开发代价。如果各环节之间出现“利益”冲突,那我们就必须要作出一个基于后续扩展以及总体成本的权衡,寻找出一个最适合当前阶段平衡点。

不过,即使我们的切分规则设计的再高明,也很难让所有的事务所需的数据都在同一个 MySQL Server 上。所以,虽然这种解决方案所需要付出的成本最小,但大多数时候也只能兼顾到一些大部分的核心事务,也不是一个很完美的解决方案。

第二、大事务切分成多个小事务,数据库保证各个小事务的完整性,应用控制各个小事务之间的整体事务完整性。

和上一个方案相比,这个方案所带来的应用改造就会更多,对应用的要求也会更为苛刻 。应用不仅需要分拆原来的很多大事务,同时还需要保证各个小事务的之间的完整性。也就是说,应用程序自己需要具有一定的事务能力,这无疑会增加应用程序的技术难度。

但是,这个方案也有不少自己的优势。首先我们的数据的切分规则就会更为简单,很难遇到限制。而且更简单,就意味着维护成本更低。其次,没有数据切分规则的太多限制,数据库方面的可扩展性也会更高,不会受到太多的约束,当出现性能瓶颈的时候可以快速进行进一步拆分现有数据库。最后,数据库做到离实际业务逻辑更远,对后续架构扩展也就更为有利。

第三、结合上述两种解决方案,整合各自的优势,避免各自的弊端。

前面两种解决方案都存在各自的优缺点,而且基本上都是相互对立的,我们完全可以利用两者各自的优势,调整两个方案的设计原则,在整个架构设计中做一个平衡。比如我们可以在保证部分核心事务所需数据在同一个 MySQL Server 上,而其他并不是特别重要的事务,则通过分拆成小事务和应用系统结合来保证。而且,对于有些并不是特别重要的事务,我们也可以通过深入分析,看是否不可避免一定需要使用事务。

通过这样相互平衡设计的原则,我们既可以避免应用程序需要处理太多的小事务来保证其整体的完整性,同时也能够避免拆分规则太多复杂而带来后期维护难度的增加及扩展性受阻的情况。

当然,并不是所有的应用场景都非要结合以上两种方案来解决。比如对于那些对事务要求并不是特别严格,或者事务本身就非常简单的应用,就完全可以通过稍加设计的拆分规则就可满足相关要求,我们完全可以仅仅使用第一种方案,就可以避免还需要应用程序来维护某些小事务的整体完整性的支持。这在很大程度上面可以降低应用程序的复杂度。

而对于那些事务关系非常复杂,数据之间的关联度非常高的应用,我们也就没有必要为了保持事务数据能够集中而努力设计,因为不管我们如何努力,都很难满足要求,大都是遇到顾此失彼的情景。对于这种情况,我们还不如让数据库方面尽可能保持简洁,而让应用程序做出一些牺牲。

在当前很多大型的互联网应用中,不论是上面哪一种解决方案的使用案例都有,如大家所熟知的 Ebay,在很大程度上就是第三种结合的方案。在结合过程中以第二种方案为主,第一种方案为辅。选择这样的架构,除了他们应用场景的需求之外,其较强的技术实力也为开发足够强壮的应用系统提供了保证。又如某国内大型的 BBS 应用系统(不便公开其真实名称),其事务关联性并不是特别的复杂,各个功能模块之间的数据关联性并不是特别的高,就是完全采用第一种解决方案,完全通过合理设计数据拆分的规则来避免事务的数据源跨多个 MySQL Server。

最后,我们还需要明白一个观点,那就是事务并不是越多越好,而是越少越好越小越好 。不论我们使用何种解决方案,那就是在我们设计应用程序的时候,都需要尽可能做到让数据的事务相关性更小,甚至是不需要事务相关性。当然,这只是相对的,也肯定只有部分数据能够做到。但可能就是某部分数据做到了无事务相关性之后,系统整体复杂度就会降低很大一个层次,应用程序和数据库系统两方面都可能少付出很多的代价。

三、数据一致性原则

不论是 Scale Up 还是 Scale Out,不论我们如何设计自己的架构,保证数据的最终一致性都是绝对不能违背的原则,保证这个原则的重要性我想各位读者肯定也都是非常明白清楚的。

而且,数据一致性的保证就像事务完整性一样,在我们对系统进行 Scale Out 设计的时候,也可能会遇到一些问题。当然,如果是 Scale Up,可能就很少会遇到这类麻烦了。当然,在很多人眼中,数据的一致性在某种程度上面也是属于事务完整性的范畴。不过这里为了突出其重要性和相关特性,我还是将他单独提出来分析。

那我们又如何在 Scale Out 的同时又较好的保证数据一致性呢?很多时候这个问题和保证事务完整性一样让我们头疼,也同样受到了很多架构师的关注。经过很多人的实践,大家最后总结出了 BASE 模型。即:基本可用,柔性状态,基本一致和最终一致。 这几个词看着挺复杂挺深奥,其实大家可以简单的理解为非实时的一致性原则。

也就是说,应用系统通过相关的技术实现,让整个系统在满足用户使用的基础上,允许数据短时间内处于非实时状态,而通过后续技术来保证数据在最终保证处于一致状态。这个理论模型说起来确实听简单,但实际实现过程中我们也会遇到不少难题。

首先,第一个问题就是我们需要让所有数据都是非实时一致吗?我想大多数读者朋友肯定是投反对票的。那如果不是所有的数据都是非实时一致,那我们又该如何来确定哪些数据需要实时一致哪些数据又只需要非实时的最终一致呢?其实这基本可以说是一个各模块业务优先级的划分,对于优先级高的自然是规属于保证数据实时一致性的阵营,而优先级略低的应用,则可以考虑划分到允许短时间端内不一致而最终一致的阵营。这是一个非常棘手的问题。我们不能随便拍脑袋就决定,而是需要通过非常详细的分析和仔细的评估才能作出决定。因为不是所有数据都可以出现在系统能不短时间段内不一致状态,也不是所有数据都可以通过后期处理的使数据最终达到一致的状态,所以之少这两类数据就是需要实时一致的。而如何区分出这两类数据,就必须经过详细的分析业务场景商业需求后进行充分的评估才能得出结论。

其次,如何让系统中的不一致数据达到最终一致?一般来说,我们必须将这类数据所设计到的业务模块和需要实时一致数据的业务模块明确的划分开来。然后通过相关的异步机制技术,利用相应的后台进程,通过系统中的数据,日志等信息将当前并不一致的数据进行进一步处理,使最终数据处于完全一致状态。对于不同的模块,使用不同的后台进程,既可以避免数据出现紊乱,也可以并发执行,提高处理效率。如对用户的消息通知之类的信息,就没有必要做到严格的实时一致性,只需要现记录下需要处理的消息,然后让后台的处理进程依次处理,避免造成前台业务的拥塞。

最后,避免实时一致与最终一致两类数据的前台在线交互。由于两类数据状态的不一致性,很可能会导致两类数据在交互过程中出现紊乱,应该尽量让所有非实时一致的数据和实时一致数据在应用程序中得到有效的隔离。甚至在有些特别的场景下,记录在不同的 MySQL Server 中来进行物理隔离都是有必要的。

四、高可用及数据安全原则

除了上面两个原则之外,我还想提一下系统高可用及数据安这两方面。经过我们的 Scale Out 设计之后,系统整体可扩展性确实是会得到很大的提高,整体性能自然也很容易得到较大的改善。但是,系统整体的可用性维护方面却是变得比以前更为困难。因为系统整体架构复杂了,不论是应用程序还是数据库环境方面都会比原来更为庞大,更为复杂。这样所带来的最直接影响就是维护难度更大,系统监控更难。

如果这样的设计改造所带来的结果是我们系统经常性的 Crash,经常性的出现 Down 机事故,我想大家肯定是无法接受的,所以我们必须通过各种技术手段来保证系统的可用性不会降低,甚至在整体上有所提高。

所以,这里很自然就引出了我们在进行 Scale Out 设计过程中另一个原则,也就是高可用性的原则。不论如何调整设计系统的架构,系统的整体可用性不能被降低。

其实在讨论系统可用性的同时,还会很自然的引出另外一个与之密切相关的原则,那就是数据安全原则。要想达到高可用,数据库中的数据就必须是足够安全的。这里所指的安全并不针对恶意攻击或者窃取方面来说,而是针对异常丢失。也就是说,我们必须保证在出现 软/硬件故障 的时候,能够保证我们的数据不会出现丢失。数据一旦丢失,根本就无可用性可言了。而且,数据本身就是数据库应用系统最核心的资源,绝对不能丢失这一原则也是毋庸置疑的。

要确保高可用及数据安全原则,最好的办法就是通过冗余机制来保证。所有软硬件设备都去除单点隐患,所有数据都存在多份拷贝。这样才能够较好的确保这一原则。在技术方面 ,我们可以通过 MySQL Replication,MySQL Cluster 等技术来实现。

总结

不论我们如何设计架构,不管我们的可扩展性如何变化,本章中所提到的一些原则都是非常重要的。不论是解决某些问题的原则,还是保证性的原则,不论是保证可用性的原则,还是保证数据安全的原则,我们都应该在设计中时时刻刻都关注,谨记。

MySQL 数据库之所以在互联网行业如此火爆,除了其开源的特性,使用简单之外,还有一个非常重要的因素就是在扩展性方面有较大的优势。其不同存储引擎各自所拥有的特性可以应对各种不同的应用场景。其 Replication 以及 Cluster 等特性更是提升扩展性非常有效的手段。

以上就是MySQL 可扩展设计的基本原则的详细内容,更多关于MySQL 可扩展设计的资料请关注三水点靠木其它相关文章!

MySQL 相关文章推荐
MySQL索引知识的一些小妙招总结
May 10 MySQL
一看就懂的MySQL的聚簇索引及聚簇索引是如何长高的
May 25 MySQL
MySQL 常见的数据表设计误区汇总
Jun 07 MySQL
mysql获取指定时间段中所有日期或月份的语句(不设存储过程,不加表)
Jun 18 MySQL
MySQL中存储时间的最佳实践指南
Jul 01 MySQL
MySQL 数据类型详情
Nov 11 MySQL
Mysql存储过程、触发器、事件调度器使用入门指南
Jan 22 MySQL
Mysql数据库表中为什么有索引却没有提高查询速度
Feb 24 MySQL
Mysql事务索引知识汇总
Mar 17 MySQL
Mysql超详细讲解死锁问题的理解
Apr 01 MySQL
MySQL中一条SQL查询语句是如何执行的
Apr 08 MySQL
提高系统的吞吐量解决数据库重复写入问题
Apr 23 MySQL
MySQL主从搭建(多主一从)的实现思路与步骤
May 13 #MySQL
MySQL如何构建数据表索引
May 13 #MySQL
MySQL 自定义变量的概念及特点
May 13 #MySQL
为什么mysql字段要使用NOT NULL
MySQL表字段时间设置默认值
May 13 #MySQL
MySql新手入门的基本操作汇总
May 13 #MySQL
MySQL中你可能忽略的COLLATION实例详解
You might like
饭制《星际争霸》Mod:优化游戏机制 增加新单位
2017/07/02 星际争霸
德生S2000南麂列岛台湾FM收听记录
2021/03/02 无线电
php中flush()、ob_flush()、ob_end_flush()的区别介绍
2013/02/17 PHP
PHP中file_get_contents函数抓取https地址出错的解决方法(两种方法)
2015/09/22 PHP
ThinkPHP中Common/common.php文件常用函数功能分析
2016/05/20 PHP
PHP使用openssl扩展实现加解密方法示例
2020/02/20 PHP
Javascript中的数学函数集合
2007/05/08 Javascript
jquery中获得$.ajax()事件返回的值并添加事件的方法
2010/04/15 Javascript
一个简单的js动画效果代码
2010/07/20 Javascript
6款经典实用的jQuery小插件及源码(对话框/提示工具等等)
2013/02/04 Javascript
单击浏览器右上角的X关闭窗口弹出提示的小例子
2013/06/12 Javascript
JavaScript中访问节点对象的方法有哪些如何使用
2013/09/24 Javascript
JQuery简单实现锚点链接的平滑滚动
2015/05/03 Javascript
利用HTML5+Socket.io实现摇一摇控制PC端歌曲切换
2017/01/13 Javascript
Vue-Router实现页面正在加载特效方法示例
2017/02/12 Javascript
vue-router:嵌套路由的使用方法
2017/02/21 Javascript
ES6扩展运算符用法实例分析
2017/10/31 Javascript
Vue源码学习之初始化模块init.js解析
2017/11/02 Javascript
bootstrap fileinput插件实现预览上传照片功能
2018/01/23 Javascript
JavaScript定时器常见用法实例分析
2019/11/15 Javascript
微信小程序实现页面监听自定义组件的触发事件
2020/11/01 Javascript
Element el-button 按钮组件的使用详解
2021/02/01 Javascript
在 Python 应用中使用 MongoDB的方法
2017/01/05 Python
解决python测试opencv时imread导致的错误问题
2019/01/26 Python
Java ExcutorService优雅关闭方式解析
2020/05/30 Python
GLAMGLOW格莱魅美国官网:美国知名的面膜品牌
2016/12/31 全球购物
查环查孕证明
2014/01/10 职场文书
国际商务专业职业生涯规划书范文
2014/01/17 职场文书
空中乘务员岗位职责
2014/03/08 职场文书
医学生就业推荐表自我鉴定
2014/03/26 职场文书
《诚实与信任》教学反思
2014/04/10 职场文书
班组长安全工作职责
2014/07/15 职场文书
奥巴马上海演讲稿
2014/09/10 职场文书
学术会议邀请函
2015/01/30 职场文书
英文辞职信范文
2015/05/13 职场文书
Redis Cluster 字段模糊匹配及删除
2021/05/27 Redis