MySQL可扩展设计的基本原则

Published on 2016 - 06 - 07

什么是可扩展性

一个数据库据系统的扩展性实际上主要体现在两个方面,一个是横向扩展,另一个则是纵向扩展,也就是常说的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缺点:

  1. 高端设备成本高,且竞争少,容易受到厂家限制;
  2. 受到硬件设备发展速度限制,单台主机的处理能力总是有极限的,容易遇到最终无法解决的性能瓶颈;
  3. 设备和数据集中,发生故障后的影响较大。

从短期来看,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等技术来实现。

参考文档