从 SQL Server 到 MySQL (一):异构数据库迁移

201803/migration-bird.png

背景

沪江成立于 2001 年,作为较早期的教育学习网站, 当时技术选型范围并不大: Java 的版本是 1.2,C# 尚未诞生,MySQL 还没有被 Sun 收购, 版本号是 3.23。 工程师们选择了当时最合适的微软体系,并在日后的岁月里, 逐步从 ASP 过度到 .net,数据库也跟随 SQL Server 进行版本升级。

十几年过去了,技术社区已经发生了天翻地覆的变化。 沪江的技术栈还基本在 .net 体系上,这给业务持续发展带来了一些限制。 人才招聘、社区生态、架构优化、成本风险方面都面临挑战。 集团经过慎重考虑,发起了大规模的去 Windows 化项目。 这其中包含两个重点子项目:开发语言从 C# 迁移到 Java, 数据库从 SQL Server 迁移到 MySQL。

本系列文章就是向大家介绍, 从 SQL Server 迁移到 MySQL 所面临的问题和我们的解决方案。

迁移方案的基本流程

设计迁移方案需要考量以下几个指标:

  • 迁移前后的数据一致性
  • 业务停机时间
  • 迁移项目是否对业务代码有侵入
  • 需要提供额外的功能:表结构重构、字段调整

经过仔细调研,在平衡复杂性和业务方需求后, 迁移方案设计为两种:停机数据迁移和在线数据迁移。 如果业务场景允许数小时的停机,那么使用停机迁移方案, 复杂度低,数据损失风险低。 如果业务场景不允许长时间停机,或者迁移数据量过大, 无法在几个小时内迁移完成,那么就需要使用在线迁移方案了。

数据库停机迁移的流程:

201803/migration-db-offline-readonly.png

停机迁移逻辑比较简单,使用 ETL(Extract Translate Load) 工具从 Source 写入 Target,然后进行一致性校验,最后确认应用运行 OK, 将 Source 表名改掉进行备份。

在线迁移的流程:

201803/migration-db-online.png

在线迁移的方案稍微复杂一些,流程上有准备全量数据,然后实时同步增量数据, 在数据同步跟上(延迟秒级别)之后,进行短暂停机(Hang 住,确保没有流量), 就可以使用新的应用配置,并使用新的数据库。

需要解决的问题

从 SQL Server 迁移到 MySQL,核心是完成异构数据库的迁移。

基于两种数据迁移方案,我们需要解决以下问题:

  • 两个数据库的数据结构是否可以一一对应?出现不一致如何处理?
  • MySQL 的使用方式和 SQL Server 使用方式是否一致?有哪些地方需要注意?
  • 如何确保迁移前后的数据一致性?
  • 在迁移中,如何支持数据结构调整?
  • 如何保证业务不停情况下面,实现在线迁移?
  • 数据迁移后如果发现业务异常需要回滚,如何处理新产生的数据?

为了解决以上的问题,我们需要引入一整套解决方案,包含以下部分:

  • 指导文档 A:SQL Server 转换 MySQL 的数据类型对应表
  • 指导文档 B:MySQL 的使用方式以及注意点
  • 支持表结构变更,从 SQL Server 到 MySQL 的 ETL 工具
  • 支持 SQL Server 到 MySQL 的在线 ETL 工具
  • 一致性校验工具
  • 一个回滚工具

让我们一一来解决这些问题。

SQL Server 到 MySQL 指导文档

非常幸运的是,MySQL 官方早就准备了一份如何其他数据库迁移到 MySQL 的白皮书。 MySQL :: Guide to Migrating from Microsoft SQL Server to MySQL 里提供了详尽的 SQL Server 到 MySQL 的对应方案。 包含了:

  • SQL Server to MySQL - Datatypes 数据类型对应表
  • SQL Server to MySQL - Predicates 逻辑算子对应表
  • SQL Server to MySQL – Operators and Date Functions 函数对应表
  • T-SQL Conversion Suggestions 存储过程转换建议

需要额外处理的数据类型:

SQL Server MySQL
IDENTITY AUTO_INCREMENT
NTEXT, NATIONAL TEXT TEXT CHARACTER SET UTF8
SMALLDATETIME DATETIME
MONEY DECIMAL(19,4)
SMALL MONEY DECIMAL(10,4)
UNIQUEIDENTIFIER BINARY(16)
SYSNAME CHAR(256)

在实际进行中,还额外遇到了一个用来解决树形结构存储的字段类型 Hierarchyid。这个场景需要额外进行业务调整。

我们在内部做了针对 MySQL 知识的摸底排查工作, 并进行了若干次的 MySQL 使用技巧培训, 将工程师对 MySQL 的认知拉到一根统一的线。

关于存储过程使用,我们和业务方也达成了一致:所有 SQL Server 存储过程使用业务代码进行重构,不能在 MySQL 中使用存储过程。 原因是存储过程增加了业务和 DB 的耦合,会让维护成本变得极高。 另外 MySQL 的存储过程功能和性能都较弱,无法大规模使用。

最后我们提供了一个 MySQL 开发规范文档,借数据库迁移的机会, 将之前相对混乱的表结构设计做了统一了约束(部分有业务绑定的设计, 在考虑成本之后没有做调整)。

ETL 工具

ETL 的全称是 Extract Translate Load(读取、转换、载入), 数据库迁移最核心过程就是 ETL 过程。 如果将 ETL 过程简化,去掉 Translate 过程, 就退化为一个简单的数据导入导出工具。 我们可以先看一下市面上常见的导入导出工具, 了解他们的原理和特性,方便我们选型。

MySQL 同构数据库数据迁移工具:

异构数据库迁移工具:

看上去异构数据库迁移工具和方案很多,但是经过我们调研,其中不少是为老派的传统行业服务的。 比如 Kettle / Ispirerer,他们关注的特性,不能满足互联网公司对性能、迁移耗时的要求。 简单筛选后,以下几个工具进入我们候选列表(为了做特性对比,加入几个同构数据库迁移工具):

工具名称 热数据备份保证一致性 batch 操作 支持异构数据库 断点续接 开源 开发语言 GUI
mysqldump V 使用 single-transaction X X X V C X
pt-table-sync V 使用 transaction 或 lock table 的 FTWRL V X V V Pell X
DataX X V V X V Java X
yugong X V V V V Java X
DB2DB X V V X X .net V
MySQL Workbench X ? V X V C++ V

由于异构数据库迁移,真正能够进入我们选型的只有 DataX / yugong / DB2DB / MySQL Workbench。 经过综合考虑,我们最终选用了三种方案, DB2DB 提供小数据量、简单模式的停机模式支持, 足以应付小数据量的停机迁移,开发工程师可以自助完成。 DataX 为大数据量的停机模式提供服务, 使用 JSON 进行配置,通过修改查询 SQL,可以完成一部分结构调整工程。 yugong 的强大可定制性也为在线迁移提供了基础, 我们在官方开源版本的基础之上,增加了以下额外功能:

  • 支持 SQL Server 作为 Source 和 Target
  • 支持 MySQL 作为 Source
  • 支持 SQL Server 增量更新
  • 支持使用 YAML 作为配置格式
  • 调整 yugong 为 fat jar 模式运行
  • 支持表名、字段名大小写格式变化,驼峰和下划线自由转换
  • 支持表名、字段名细粒度自定义
  • 支持复合主键迁移
  • 支持迁移过程中完成 Range / Time / Mod / Hash 分表
  • 支持新增、删除字段

关于 yugong 的二次开发,我们也积累了一些经验,这个我们下篇文章会来分享。

一致性校验工具

在 ETL 之后,需要有一个流程来确认数据迁移前后是否一致。 虽然理论上不会有差异,但是如果中间有程序异常, 或者数据库在迁移过程中发生操作,数据就会不一致。

业界有没有类似的工具呢? 有,Percona 提供了 pt-table-checksum 这样的工具, 这个工具设计从 master 使用 checksum 来和 slave 进行数据对比。 这个设计场景是为 MySQL 主从同步设计, 显然无法完成从 SQL Server 到 MySQL 的一致性校验。 尽管如此,它的一些技术设计特性也值得参考:

  • 一次检查一张表
  • 每次检查表,将表数据拆分为多个 trunk 进行检查
  • 使用 REPLACE...SELECT 查询,避免大表查询的长时间带来的不一致性
  • 每个 trunk 的查询预期时间是 0.5s
  • 动态调整 trunk 大小,使用指数级增长控制大小
  • 查询超时时间 1s / 并发量 25
  • 支持故障后断点恢复
  • 在数据库内部维护 src / diff,meta 信息
  • 通过 Master 提供的信息自动连接上 slave
  • 必须 Schema 结构一致

我们选择 yugong 作为 ETL 工具的一大原因也是因为它提供了多种模式。 支持 CHECK / FULL / INC / AUTO 四种模式。 其中 CHECK 模式就是将 yugong 作为数据一致性检查工具使用。 yugong 工作原理是通过 JDBC 根据主键范围变化,将数据取出进行批量对比。

这个模式会遇到一点点小问题,如果数据库表没有主键,将无法进行顺序对比。 其实不同数据库有自己的逻辑主键,Oracle 有 rowid, SQL Server 有 physloc。这种方案可以解决无主键进行比对的问题。

如何回滚

我们需要考虑一个场景,在数据库迁移成功之后业务已经运行了几个小时, 但是遇到了一些 Critical 级别的问题,必须回滚到迁移之前状态。 这时候如何保证这段时间内的数据更新到老的数据库里面去?

最朴素的做法是,在业务层面植入 DAO 层的打点, 将 SQL 操作记录下来到老数据库进行重放。 这种方式虽然直观,但是要侵入业务系统,直接被我们否决了。 其实这种方式是 binlog statement based 模式, 理论上我们可以直接从 MySQL 的 binlog 里面获取数据变更记录。 以 row based 方式重放到 SQL Server。

这时候又涉及到逆向 ETL 过程, 因为很可能 Translate 过程中,做了表结构重构。 我们的解决方法是,使用 Canal 对 MySQL binlog 进行解析, 然后将解析之后的数据作为数据源, 将其中的变更重放到 SQL Server。

由于回滚的过程也是 ETL,基于 yugong, 我们继续定制了 SQL Server 的写入功能, 这个模式类似于在线迁移,只不过方向是从 MySQL 到 SQL Server。

其他实践

我们在迁移之前做了大量压测工作, 并针对每个迁移的 DB 进行线上环境一致的全真演练。 我们构建了和生产环境机器配置一样, 数据量一样的测试环境,并要求每个系统在上线之前都进行若干次演练。 演练之前准备详尽的操作手册和事故处理方案。 演练准出的标准是:能够在单次演练中不出任何意外,时间在估计范围内。 通过演练我们保证了整个操作时间可控,减少操作时候的风险。

为了让数据库的状态更为直观的展现出来, 我们对 MySQL / SQL Server 添加了细致的 Metrics 监控。 在测试和迁移过程中,可以便利地看到数据库的响应情况。

201803/sql-server-metrics.png
201803/mysql-metrics.png

为了方便 DBA 快速 Review SQL。 我们提供了一些工具,直接将代码库中的 SQL 拎出来, 可以方便地进行 SQL Review。 再配合其他 SQL Review 工具, 比如 Meituan-Dianping/SQLAdvisor, 可以实现一部分自动化,提高 DBA 效率,避免线上出现明显的 Slow SQL。

最后

基于这几种方案我们打了一套组合拳。经过将近一年的使用, 进行了 28 个通宵,迁移了 42 个系统, 完成了包括用户、订单、支付、电商、学习、社群、内容和工具的迁移。 迁移的数据总规模接近百亿,所有迁移项目均一次成功。 迁移过程中积累了丰富的实战经验,保障了业务快速向前发展。


原文链接: https://blog.alswl.com/2018/03/sql-server-migration-1/

欢迎关注我的微信公众号:窥豹

qrcode-mp.jpg

3a1ff193cee606bd1e2ea554a16353ee

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,547评论 6 477
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,399评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,428评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,599评论 1 274
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,612评论 5 365
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,577评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,941评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,603评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,852评论 1 297
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,605评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,693评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,375评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,955评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,936评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,172评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 43,970评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,414评论 2 342

推荐阅读更多精彩内容