迁移到MySQL的业务架构演进实战

随着业务的快速发展,作到未雨绸缪很重要,在提高关系型数据库的扩展性和高可用性方面须要提早布局,MySQL方案虽然不是万金油,倒是架构演进中的一种典型方案,也是建设MySQL分布式存储平台一个很好的切入点。前端

 

本文会着重讨论迁移到MySQL架构体系的演进过程,相信大大小小的公司在不一样的发展阶段都会碰到其中一些共性的问题。 数据库

 

咱们先来简单介绍一下系统迁移的背景,在这个过程当中咱们不会刻意强调源数据库的一些功能性差别,相对来讲是一种更通用的架构改进方式。后端

 

1、架构改造背景和演进策略缓存

 

迁移前,咱们作了业务梳理,总体的系统现状梳理以下表,能够发现这个业务其实能够划分为两个大类,一个是数据业务,一个是帐单业务。数据业务负责事务性数据,而帐单业务是状态数据的操做历史。性能优化

 

640?wx_fmt=png

 

改造前架构以下图所示,对数据作了过滤,总体上库里面的表有上万张,虽然是多个独立的业务单元,可是状态数据和流水数据是彼此经过存储过程级联调用。服务器

 

640?wx_fmt=png

 

对这样一个系统作总体的改造,存在大量存储过程,在业务耦合度较高的状况下,要拆分为分布式架构是很困难的,主要体如今3个地方:架构

 

(1)研发和运维对于分布式架构的理解有限,认为改造虽然可行,可是改动量极大,基本会在作和不作之间摇摆。并发

 

(2)对于你们的常规理解来讲,但愿达到的效果是一种透明平移的状态,即原来的存储过程咱们都无缝的平移过来,在MySQL分布式的架构下,这种方案显然是不可行的,并且若是硬着头皮作完,效果也确定很差。app

 

(3)对于分布式的理解,不是仅仅把业务拆开那么简单,咱们心中始终要有一个平衡点,并非全部业务都须要拆分作成分布式。分布式虽能带来好处,可是同时分布式也会带来维护的复杂成本。负载均衡

 

因此对于架构的改进,咱们为了可以落地,要在这个过程当中尽量和研发团队保持架构的同步迭代,总体上走过了以下图所示的4个阶段。

 

640?wx_fmt=png

 

(1)功能阶段:梳理需求,对存储过程进行转移,适配MySQL方向。

 

(2)架构阶段:对系统架构和业务架构进行改进设计,支持分布式扩展。

 

(3)性能阶段:对系统压力进行增量测试和全量测试,全面优化性能问题。

 

(4)迁移阶段:设计数据迁移方案,完成线上环境到MySQL分布式环境的迁移。

 

咱们主要讨论上面前3个阶段,我总结为8个架构演进策略,咱们逐个来讲一下。

 

2、功能设计阶段

 

策略1:功能平移

 

对于一个已经运行稳定的商业数据库系统,若是要把它改造为基于MySQL分布式架构,很天然会存在一种距离感,这是一种重要但不紧急的事情,并且从改进的步调来讲,是很难一步到位的。因此咱们在这里实行的是迭代的方案,以下图所示。

 

640?wx_fmt=png

 

如同你们预期的那样,既然里面有大量的存储过程逻辑,咱们是否是把存储过程转移到MySQL里面就能够了呢。

 

在没有作完这件事情以前,你们谁都不敢这么说,何况MySQL单机的性能和商业数据库相比自己存在差距,在摇摆不定中,咱们仍是选择既有的思惟来进行存储过程转移。

 

在初始阶段,这部分的时间投入会略大一些,在功能和调用方式上,咱们须要作到尽量让应用层少改动或者不改动逻辑代码。

 

存储过程转移以后,咱们的架构演进才算是走入了轨道,接下来咱们要作的是系统拆分。

 

3、系统架构演进阶段

 

策略2:系统架构拆分

 

咱们以前作业务梳理时清楚地知道:系统分为数据业务和帐单业务,那么咱们下一步的改造目标也很明确了。

 

首先的切入点是数据库的存储容量,若是一个TB级别的MySQL库,存在着上万张表,并且业务的请求极高,很明显单机存在着较大的风险,系统拆分是把原来的一个实例拆成两个,经过这种拆分就可以强行把存储过程的依赖解耦。

 

而拆分的核心思路是对于帐单数据的写入从实时转为异步,这样对于前端的响应就会更加高效。

 

拆分后的架构以下图所示。

 

640?wx_fmt=png

 

固然拆分后,新的问题出现了,帐单业务的写入量按照规划是很高的,不管单机的写入性能和存储容量都难以扩展,因此咱们须要想出新的解决方案。

 

策略3:写入水平扩展

 

帐单数据在业务模型上属于流水型数据,不存在事务,因此咱们的改进就是把帐单业务的存储过程转变为insert语句,在转换以后,咱们把帐单数据库改造为基于中间件的分布式架构,这个过程对于应用同窗来讲是透明的,由于它的调用方式依然是SQL。

 

同时由于以前的帐单数据有大量的表,数据分布良莠不齐,表结构都相同,因此咱们也借此机会把数据入口作了统一,根据业务模型梳理了几个固定的数据入口。

 

这样一来,对于应用来讲,数据写入方式就更简单,更清晰了,改造后的架构以下图所示。

 

640?wx_fmt=png

 

这个改造对于应用同窗的收益是很大的,由于这个架构改造让他们直接感觉到:不用修改任何逻辑和代码,数据库层就可以快速实现存储容量和性能的水平扩展。

 

帐单的改进暂时告一段落,咱们开始聚焦于数据业务,发现这部分的读请求很是高,读写比例能够达到8:1左右,咱们继续架构的改进。

 

策略4:读写分离扩展

 

这部分的改进方案相对清晰,咱们能够根据业务特色建立多个从库来对读请求作负载均衡。这个时候数据库业务的数据库中依然有大量的存储过程。

 

因此作读写分离,使用中间件来完成仍是存在瓶颈,业务层有本身的中间件方案,因此读写分离的模式是经过存储过程调用查询数据。这虽然不是咱们理想中的解决方案,可是它会比较有效,以下图所示。经过这种方式分流了大概50%的查询流量。

 

640?wx_fmt=png

 

如今总体来看,业务的压力都在数据业务方向,有的同窗看到这种状况可能会有疑问:为何不直接把存储过程重构为应用层的SQL呢,在目前的状况下,具备说服力的方案是知足已有的需求,并且目前要业务配合改进还存在必定的困难和风险。咱们接下来继续开始演进。

 

4、业务架构演进阶段

 

策略5:业务拆分

 

由于数据业务的压力如今是整个系统的瓶颈,因此一种思路就是先仔细梳理数据业务的状况,咱们发现其实能够把数据业务拆分为平台业务和应用业务,平台业务更加统一,是全局的,应用业务相对来讲种类会多一些。

 

作这个拆分对于应用层来讲工做量也会少一些,并且也可以快速验证改进效果。改进后的架构以下图所示。

 

640?wx_fmt=png

 

这个阶段的改进能够说是架构演进的一个里程碑,根据模拟测试的结果来看,数据库的QPS指标整体在9万左右,而总体的压力通过估算会是目前的20倍以上,因此毫无疑问,目前的改造是存在瓶颈的,简单来讲,就是不具有真实业务的上线条件。

 

这个时候你们的压力都很大,要打破目前的僵局,目前可见的方案就是对于存储过程逻辑进行改造,这是不得已而为之的事情,也是整个架构改进的关键,这个阶段的改进,咱们称之为事务降维。

 

策略6:事务降维

 

事务降维的过程是在通过这些阶段的演进以后,总体的业务逻辑脉络已经清晰,改动的过程居然比想象的还要快不少,通过改进后的方案对原来的大量复杂逻辑校验作了取舍,也通过了反复迭代,最终是基于SQL的调用方案,你们在此的最大顾虑是原来使用存储过程应用层只须要一次请求,而如今的逻辑改造后须要3次请求,可能从数据流量上会带给集群很大的压力,后来通过数据验证这种顾虑消除了。改进后的架构以下图所示,目前已是彻底基于应用层的架构方式了。

 

640?wx_fmt=png

 

在这个基础之上,咱们的梳理就进入了快车道,既然改造为应用逻辑的方式已经见效,那么咱们能够在梳理现有SQL逻辑的基础上来评估是否能够改造为分布式架构。

 

从改进后的效果来看,原来的QPS在近40万,而改造后逻辑清晰简单,在2万左右,经过这个过程也让我对架构优化有了新的理解,咱们不少时候都是但愿可以作得更多,可是反过来却发现可以简化也是一种优化艺术,经过这个阶段的改进以后,你们都充满了信心。

 

策略7:业务分布式架构改造

 

这个阶段的演进是咱们架构改造的第二个里程碑,这个阶段的改造咱们碰到了以下的问题:

 

  • 高并发下的数据主键冲突;

  • 业务表数量巨大。

     

咱们逐个说明一下。

 

1)问题1:高并发下的数据主键冲突和解决方案

 

业务逻辑中对于数据处理是以下图所示的流程,好比id是主键,咱们要修改id=100的用户属性,增长10。

 

640?wx_fmt=png

 

 ① 检查记录是否存在

 

select value from user where id=100;

 

 ② 若是记录存在,则执行update操做

 

update user set id=value+10;

 

 ③ 若是记录不存在,则执行insert操做

 

insert into user(id,value) values(100,10)

 

在并发量很大的状况下,极可能线程1检测数据不存在要执行insert操做的瞬间,线程2已经完成了insert操做,这样一来就很容易抛出主键数据冲突。

 

对于这个问题的解决方案,咱们能够充分使用MySQL的冲突检测功能,即用insert on duplicate update key语法来解决,这个方案从索引维护的角度来看,在基于主键的条件下,实际上是不须要索引维护的,而相似的语法replace操做在delete+insert的过程当中是执行了两条DML,从索引的维护代价来看要高一些。

 

相似下面的形式:

 

Insert into acc_data(id,value,mod_date) values(100,10,now()) on duplicate key update value=value+10,mod_date=now();

 

这种状况不是最完美的,在少数状况下会产生数据的脏读,可是从数据生效的策略来看,咱们后续能够在缓存层进行改进,因此这个问题算是基本解决了。

 

2)问题2:业务表数量巨大

 

对于业务表数量巨大的问题,在以前帐单业务的架构重构中,咱们已经有了借鉴的思路。因此咱们能够经过配置化的方式提供几个统一的数据入口,好比原来的业务的数据表为:

 

app1_data,app2_data,app3_data... app500_data,

 

咱们能够简化为一个或者少数访问入口,好比:

 

app_group1_data(包含app1_data,app2_data... app100_data)

app_group2_data(包含app101_data,app102_data...app200_data),

 

以此类推。

 

经过配置化的方式对于应用来讲不用关心数据存储的细节,而数据的访问入口能够根据配置灵活定制。

 

通过相似的方式改进,咱们把系统架构统一改形成了三套分布式架构,以下图所示。

 

640?wx_fmt=png

 

在总体改进以后,咱们查看如今的QPS,每一个分片节点均在5000左右,基本实现了水平扩展,并且从存储容量上来看也是达到了预期的目标,到了这个阶段,总体的架构已经逐步趋于稳定,可是咱们是面向业务的架构,还须要作后续的迭代。

 

5、性能优化阶段

 

策略8:业务分片逻辑改造

 

咱们经过业务层的检测发现,部分业务处理的延时在10毫秒左右,对于一个高并发的业务来讲,这种结果是不能接受的,可是咱们已是分布式架构,要进行优化能够充分利用动态配置来实现。

 

好比某个数据入口包含10个表数据,其中有个表的数据量过大,致使这个分片的容量过大,这种状况下咱们就能够作一下中和,根据业务状况来重构数据,把容量大的表尽量打散到不一样的组中。

 

经过对数据量较大的表重构,修改分片的数据分布以后,每一个分片节点上的文件大小从200M左右降为70M左右,数据容量也控制在100万条之内,下图是其中一个分片节点的系统负载状况,整体按照线上环境的部署状况,单台服务器的性能会控制在一个有效范围以内,总体的性能提高了15%左右,而从业务的反馈来看,读延迟优化到了1毫秒之内,写延迟优化到了4毫秒之内。

 

640?wx_fmt=jpeg

 

后续业务关闭了数据缓存,这样一来全部的查询和写入压力都加在了现有的集群中,从实际的效果来看QPS仅仅增长了不到15%(以下图),而在后续作读写分离时这部分的压力会彻底释放。

 

640?wx_fmt=png

 

6、架构里程碑和补充:基于分布式架构的水平扩展方案

 

至此,咱们的分布式集群架构初步实现了业务需求,后续就是数据迁移的方案设计了,3套集群的实例部署架构以下图所示。

 

640?wx_fmt=png

 

在这个基础上须要考虑中间件的高可用,好比如今使用中间件服务,若是其中的一个中间件服务发生异常宕机,那么业务如何保证持续访问,若是咱们考虑负载均衡,加入一个代理层,好比使用HAProxy,这就势必带来另一个问题,代理层的高可用如何保证,因此在这个架构设计中,咱们须要考虑得更可能是全局的设计。 

 

咱们能够考虑使用LVS+keepalived的组合方案,通过测试故障转移对于应用层面来讲几乎无感知,整个方案的设计以下图所示。

 

640?wx_fmt=png

 

补充要点1:充分利用硬件性能和容量评估

 

根据上面的分布式存储架构演进和后端的数据监控,咱们能够看到总体的集群对于CPU的使用率并不高,而对于IO的需求更大,在这种状况下,咱们须要基于硬件来完善咱们的IO吞吐量。

 

在基于SATA-SSD,PCIE-SSD等磁盘资源的测试,咱们设定了基于sysbench 的IO压测基准:

 

  • 调度策略:cfq

  • 测试用例:oltp_read_write.lua

  • 压测表数量:10

  • 单表条目数:50000000

  • 压测时长:3600s

     

通过对比测试,总体获得了以下表所示的表格数据。

 

640?wx_fmt=png

 

从以上的数据咱们能够分析获得以下图所示的图形。

 

640?wx_fmt=png

 

其中,TPS:QPS大概是1:20,咱们对于性能测试状况有了一个总体的认识,从成本和业务需求来看,目前SATA-SSD的资源配置可以彻底知足咱们的压力场景。

 

补充要点2:须要考虑的服务器部署架构

 

对于总体架构设计方案已经具有交付条件,那么线上环境的部署咱们还须要设计合理的架构,这个合理主要就是两个边界:

 

  • 知足现有的性能,可以支撑指数级的压力支撑;

  • 成本合理。

     

在这个基础上进行了屡次讨论和迭代,咱们梳理了以下图所示的服务器部署架构,对于30多个实例,咱们最终采用了10台物理服务器来支撑。

 

640?wx_fmt=jpeg

 

从机器的使用成原本说,MySQL的使用场景更偏向于PC服务,可是对于单机来讲,CPU、内存、磁盘资源都会存在较大的冗余,因此咱们考虑了单机多实例,交叉互备,从而提升资源使用效率,同时节省了大量的服务器资源成本。其中LVS服务能够做为通用的配置资源,故如上资源中无需重复申请。