您现在的位置是:网站首页> 编程资料编程资料

SQL Server携程核心系统无感迁移到MySQL实战_Mysql_

2023-05-26 436人已围观

简介 SQL Server携程核心系统无感迁移到MySQL实战_Mysql_

前言

携程酒店订单系统的存储设计从1999年收录第一单以来,已经完成了从单一SQLServer数据库到多IDC容灾、完成分库分表等多个阶段,在见证了大量业务奇迹的同时,也开始逐渐暴露出老骥伏枥的心有余而力不足之态。基于更高稳定性与高效成本控制而设计的订单存储系统,已经是携程在疫情后恢复业务的必然诉求。

目前携程酒店订单系统,在着在业务高增长的同时,也面临着信息读写管理能力受制于数据库自身性能与稳定性的窘境。综合分析,一则为携程服役了十多年的SQLServer服务器集群的磁盘容量设计,已经跟不上时下新增订单量的空间诉求;二则在系统能力提升上造成了各大业务系统巨大的底层瓶颈与风险,同时又相比业界主流已基于MySQL架构设计存储系统而言,我们的订单存储系统仍基于SQLServer构建也整体推高了运营成本。

为了支撑未来每日千万级订单的业务增长目标,同时满足高可用、高性能、高可扩展的高效成本控制期望,我们为酒店部门的订单DB所有访问开发并落地了一套稳定且可靠的统一中间件封装方案,对现状收敛并提供了全局统一的热点缓存系统,彻底解决了当下订单上层应用与数据库间直连的方案缺陷。

新系统由中间件服务统一实现了对上层应用提供数据链服务,并达成了为现有依赖订单库的应用以及其他直接或间接的数据应用无感的实现存储底层由SQLServer向MySQL技术架构迁移的目标。

一、架构综述

通过对现有系统瓶颈的分析,我们发现核心缺陷集中在订单数据缓存分散导致数据各端不一致,各订单应用则与数据库直连又造成可扩展性差。通过实践我们编写中间件抽象并统一了数据访问层,以及基于数据库部署架构镜像构建了订单缓存统一管理热点数据,解决了各端差异。

图1.1  存储系统架构图

二、应用场景

1、新单秒级各端同步

从订单的提交到各端可见的速度为存储服务的核心指标之一,我们对数据链的主要环节进行了优化,覆盖了新单同步、消息实时推送、查询索引构建以及数据平台离线归档等主要环节,使大系统内数据到达速度在3秒以内,即用户刚下完单即可跳转我携列表可见。

当新用户创单时,同步服务作为数据链入口将用户订单数据通过中间件写入订单库,此时中间件同时完成订单缓存的构建;

当订单完成入库行为和热点数据构建后抛订单消息,实时输出给各子系统;

当新单入库完毕即刻构建订单明细信息的ES索引,为第三方提供检索支持;

最后数据平台T+1实施当日数据的归档供BI等各类离线业务使用。

图2.1 数据链

2、自动发单与工作台

对客、商、员工工作台三端的支持是订单存储系统的基本角色,图2.1数据链在新单提交后为自动发单与工作台起到的衔接作用功不可没。自动发单即在客人提交订单后,以最快的响应速度向商户发送订单明细信息进行核实货位、确认订单等流程。工作台则协助员工介入流程及时获取订单处理人工事件。

图2.2 基于存储系统的发单与工作台关系(缩略细节)​

3、查询与数据分析

基于订单数据为核心的主要分为在线查询和数据分析两条业务线,以对详情查询为例,访问QPS终年保持在高位,每逢假期高峰则容易造成查询瓶颈,根因复盘后在本次架构升级中我们做了调整来优化相关场景的高可用性。

  • 在线查询以订单缓存为主,订单提交即构建热点缓存纾解查询压力,并可按配置时间参数长时段有效。
  • 非在线查询场景,以实时消息推送并结合Hive数仓T+1方式交付,凡需要长周期订单数据的场合(例如实时报表)均接入订单消息实时计算。离线BI按年度等大批量数据分析时使用Hive表,并每日凌晨低峰时段以从库低频访问的方式实施数据同步。

如此以上,我们将订单主库的访问保护在订单缓存、实时消息、Hive数仓三驾马车之后,与业务尽最大可能的解耦。

三、系统升级实践 

在对携程核心存储系统进行更新换代的过程中,贯穿全程需要做到的是热迁移,并达成所有操作对数据链路上的各应用透明无损的目标。我们的设计通盘分析了集团数据链路的特性,由订单缓存系统提供数据库镜像降低应用与数据库的直连耦合,继而再通过中间件对应用透明掉数据源于SQLServer / MySQL的物理关系,提供底层热迁移的操作空间。

结合无损迁移的工艺设计,注重对每一笔数据库流量的可见及可控,支持全库、Shard级、表级、CRUD操作级的流量分配策略,提供了底层数据迁移足够的实施手段。数仓衔接设计则侧重于解决数据平台百亿级离线数据与双库在线期间的同步问题,以及解决全量接入MySQL期间产生的数据问题。

以下将分三个部分分享我们在这一过程中学到的经验。

1、分布式订单缓存

随着业务发展,用户数和访问量越来越大,订单系统应用和服务器的压力也与日俱增。在没有引入订单缓存之前,每个应用独立连接数据库,造成查询出来的数据无法在应用间共享,并且DB每秒查询量和连接数都有上限,而酒店核心交易链路基于DB存储,存在单点故障风险。

经过埋点数据分析,订单系统是典型的读多写少,为了共享热点查询数据以及降低DB负载,一个有效的办法就是引入缓存,如图3.1,用户的请求过来时,优先查询缓存,如果存在缓存数据,则直接返回结果;缓存没有命中,则去查询DB,根据配置策略校验DB结果数据,校验通过则将DB数据写入缓存留作后续查询使用,否则不写入缓存,最后返回DB查询结果。

图3.1 订单缓存基本设计

关于引入新的缓存组件后的硬件开销,可通过收敛原来各应用分散的硬件资源来降低总成本,但还会因为中心化管理带来可用性挑战以及数据一致性等问题,故需要充分对现有系统进行容量评估、流量估算和缓存表价值分析。只缓存访问量高的热点数据表,通过恰当的缓存结构设计、数据压缩和缓存淘汰策略,最大程度提高缓存命中率,在缓存容量、硬件成本和可用性之间做好权衡。

传统的缓存设计,是一条数据库表记录对应一条缓存数据。而在订单系统中,一个订单查询多表的场景很常见,如果采用传统设计,在一次用户查询中,Redis的访问次数是随着表数量增加的,这种设计网络IO较大并且耗时较长。在盘点表维度流量数据时,我们发现有些表经常一起查询,不到30%的表其查询流量超过90%,在业务上完全可以划分为同一个抽象领域模型,然后基于hash结构进行存储,如图3.2,以订单号作为key,领域名称作为field,领域数据作为value。

这样无论是单表还是多表查询,每个订单都只需要访问一次Redis,即减少了key,又减少了多表查询次数,提升了性能。同时value基于protostuff进行压缩,还减少了Redis的存储空间,以及随之而来的网络流量开销。

图3.2 基于domain的存储结构简述

2、无损迁移工艺

如何做到无损热迁移是整个项目最具挑战性的地方。在工艺设计之前我们的前置工作首先完成了中间件的开发,通过中间件将数据库与业务层应用一分为二。其次抽象Dao层实现领域化,并由数据领域层向应用提供数据服务,领域之下适配SQLServer和MySQL两种数据库并统一封装。以此为基础才能为以下述工艺设计实施无损热迁移。

  • SQLServer和MySQL双库在线,实施双写,主写SQLServer,同步副写MySQL,如果SQLServer操作失败则整体失败,回滚双写事务。
  • SQLServer和MySQL之间增加一路同步Job,实时查询SQLServer最近时间窗口变更的数据进行一致性校验MySQL中的条目,差异点追齐,可以确保双写期间不可预期的两边不一致,特别是还残有直连写SQLServer应用的阶段特别有用。
  • 中间件设计有配置系统,支持任一主要查询维度可按配置精准的将数据源定向到SQLServer或MySQL,并可控制是否读取后加载到订单缓存。初期设定只加载SQLServer数据源,避免因双库间的数据不一致而造成缓存数据跳跃。并在初期可设置灰度,将小批量非核心表直连MySQL验证可靠性。后期数据一致性达成预期后,订单缓存也可自由按指定数据库加载缓存。
  • 解决了查询场景下的数据一致性问题后,流量策略支持图3.3中任一可调控维度进行数据库单写。实际项目中以表维度实施单写为主,当指定表被配置单写MySQL后,所有涉及该表的CRUD行为全部定向MySQL,包括缓存加载源。
  • 最后通过中间件统一收口对外发送的订单消息,所有消息基于中间件的CUD操作发送与物理数据库无关,这样实现消息的数据源透明,且可联动以上所有工艺操作,数据链保持一致。

图3.3  操作工艺简介

3、数仓衔接

为了方便理解生产数据到数据仓库ODS层数据的迁移,做到对下游透明,这里简单介绍一下常规数据仓库的分层体系。通常数据仓库主要分为五层:ODS(原始数据层)、DIM(维度)、EDW(企业数仓)、CDM(通用模型层)、ADM(应用模型层),

如下图所示:

图3.4  数据仓库分层结构

从图3.4上可以看出,数据仓库各层都依赖ODS层的数据,为了不影响数据平台所有应用,我们只需要将原来订单库ODS层数据源从SQLServer迁移到MySQL库即可。

从图上很直观的看出,迁移只需换个数据源不是很麻烦,但是为了保证数据质量,我们做了很多的前置工作,比如:DBA预先将生产数据同步到生产MySQL库、MySQL数据实时同步、生产两侧数据一致性校验、MySQL侧数据同步到ODS层、ODS层数据一致性校验及原有ODS层同步Job数据源切换等。

其中,生产两侧数据一致性校验和数据仓库ODS层数据一致性校验最为复杂,耗时也最长,要确保每张表、每个字段都要一致时才能切换数据源。但是,从实际操作过程中,却做不到完全一致。根据实际情况,适当处理时间类型、浮点值精度及小数位等。

下面介绍一下整体流程:

首先,对于线上数据一致校验,我们开发了在线同步Job,将SQLServer的数据和MySQL数据进行比较,发现不一致时,就将MySQL的数据以SQLServer数据为基准更新掉,确保两边数据的一致性。

其次,对于离线数据一致性校验,我们和数据仓库同事合作把MySQL侧数据同步到ODS层(以库名区分是SQLServer还是MySQL的表),并且将定时跑的任务和SQLServer侧任务在时间上尽量一致。两侧数据都准备好后,我们开发了离线数据校验脚本生成器,根据数据仓库元数据,为每张表生成一个同步Job,将其部署到调度平台。

同步任务会依赖两侧ODS层同步数据,T+1数据同步完成后,执行一致性校验,将不一致的订单号记录到不一致明细表中,并统计不一致的数据量,将结果保存到统计表中。然后在自助报表平台制作一个报表,将每天统计的不一致的表及不一致量发送到邮箱,我们每天对不一致的表进行排查找出问题,调整比较策略,更新比较Job。大致流程如下:

图3.5  一致性校验整体流程

最后,随着线上和离线数据逐步趋于一致后,我们将原先SQLServer同步到ODS层Job的数据源切换到MySQL。这里可能有同学会有疑问:为什么不直接使用MySQL侧ODS层的表呢?原因是,经过统计,依赖原先ODS层表的Job有上千个之多,如果让依赖Job切换到MySQL侧ODS表,修改工作量非常大,所以我们直接将原来的ODS层同步数据源直接切换成MySQL。

实际操作中,切数据源并不能一次全部切完,我们分三批进行,先找十几个不那么重要的表作为第一批,切完后运行两周,并收集下游数据问题的反馈。第一批表顺利切完两周后,我们没收到下游报数据问题,说明数据质量没问题。然后再将剩余的几百张表按重要程度分两批继续切,直到切完。

至此,我们完成了订单库从SQLServer迁移到MySQL在数据仓库层的迁移工作。

四、核心问题精编

实际上再周密的分析与设计,总是难免遇到执行过程中的各种挑战。我们总结了一些经典问题,虽然通过技术手段最终解决了这些大大小小问题并达成了目标,但是相信各位看官必定还有更好的解决方案,我们乐见共同学习与进步。

1、SQLServer & MySQL 流量迁移如何细粒度监控

订单系统涉及到的应用和表数量众多,一个应用对应1到n张表,一张表又对应1到n个应用,是典型的多对多关系。如图4.1,对于上层应用来说,从一个SQLServer数据库,切换到另一个MySQL数据库,其基本流程参照操作工艺章节至少分为以下几步:

  • 从单写SQLServer变成双写SQLServer和MySQL
  • 从单读SQLServer变成单读MySQL
  • 从双写SQLServer和MySQL变成单写MySQL
  • 下线SQLServer

图4.1 应用和数据库以及表的关系图

在生产环境更换数据库系统,就像在高速公路上不停车换轮胎,需要维持原有的车速不变,且对用户无感,否则后果不敢设想。

在切换工艺中双写、单读和单写流程,环环相扣,步步相依,作为配套设计监控手段必须确认上一个操作达到预期效果才能进行下一个。如果跳过或者没有切换干净就贸然进行下一步,比如还没有双写完全一致,就开始读MySQL数据,可能造成查无此数据或者查到脏数据!那么就需要对每一个CRUD操作的读写进行监控,在迁移过程中做到360度无死角可视化流量细分控制,所见即所得。具体的做法如下:

  • 所有应用接入中间件,CRUD由中间件根据配置控制读写哪个DB的哪张表;
  • 每一个读写操作的详细信息均写入ES,在Kibana和Grafana上可视化展示,并且通过DBTrace,可以知道每条SQL是在哪个DB上执行;
  • 按照应用级别逐步配置双写DB,通过同步Job实时比对、修复和记录两侧DB差异,再通过离线T+1校验双写中出现的最终不一致,如此往复直到双写一致;
  • 双写一致之后,就开始逐步将读SQLServer切换到读MySQL,通过ES监控和DBTrace确认完全没有SQLServer读,则表明单读MySQL完成,考虑到自增主键情况,我们采取按照表维度,按批次断写SQLServer,直至所有表都单写MySQL。

综上所述,基本方案为通过中间件为管道为所有接入的应用统一埋点,通过实时展示应用层的行为观察流量分布,并结合公司数据库侧Trace的可视化工具核实应用的流量切换行为与数据库实际QPS及负载浮动保持一致来监督迁移任务。

2、如何解决双写期间DB一致性问题

酒店的订单库有着二十年左右历史,经年累积,跨部门和酒店内部多个团队直接或间接依赖订单库SQLServer,要想切换到MySQL,就得先解决双写DB一致性问题,不一致主要体现在以下两点:

  • 双写时实际仅单写了SQLServer,漏写MySQL;
  • 双写SQLServer和MySQL成功,并发、不可靠网络、GC等发生时MySQL数据有几率和SQLServer不一致。

关于双写数据一致性的保证,我们基于同步Job将SQLServer数据为准线,根据最后更新时间,拉取两侧DB数据进行比对,如果不一致则修复MySQL的数据并将不一致信息写入ES,供后续排查根因。

但也因为引入了额外的Job操作MySQL数据,带来了新的问题,那就是多表双写时,因为耗时翻倍,Job发现SQLServer有数据而MySQL没有,就立即修复了MySQL数据,造成双写失败。所以双写部分失败又加上了Fai

-六神源码网