解密网易MySQL实例迁移高效完成背后的黑科技
作者:温正湖,网易杭研院资深工程师,负责网易云数据库平台核心开发和运维工作,对MySQL、MongoDB等数据库和Linux存储领域具有深入研究。
网易蜂巢团队:为企业提供专业容器云平台,深度整合IaaS、PaaS及容器技术,提供弹性计算、DevOps工具链、微服务基础设施等服务,帮助企业解决IT、架构及运维等问题,使企业更聚焦于业务,是新一代的云计算平台。
1简介
我们把数据库里部分或全部Schema和数据迁移到另一个实例的行为称为实例迁移,将导出数据的实例称为源实例,导入数据的实例称为目标实例。根据迁移数据库类型的不同,可以分为同种数据库之间的迁移,如从MySQL迁到MySQL;跨数据库类型的迁移,如从Oracle迁移到MySQL等。本文将介绍蜂巢RDS实例迁移功能的实现,并探讨如何高效完成实例迁移任务。
2使用场景
那么,为什么要进行MySQL实例迁移呢?实例迁移的场景归纳起来主要有以下几种:
1、从自建实例迁移到RDS:在云服务还未充分推广时,存在大量的自建数据库实例,举网易公司为例,网易博客、网易邮箱等产品数百个MySQL实例直接部署在物理服务器上,随着业务的扩展,必然要对实例进行扩容、升规格等操作,相比自建实例,RDS实例在故障处理、在线扩容、升级等方面存在天然的优势,所以,目前绝大部分网易互联网产品的数据库均已使用实例迁移功能迁移到RDS上;
2、从其他公有云平台迁移到RDS:蜂巢RDS推出近一年以来,很多用户将部署在其他公有云平台上的MySQL实例迁移到蜂巢RDS上,对实例迁移功能进行统计发现有50%是用于迁移其他公有云的MySQL实例。
3实例迁移技术实现
在设计实例迁移功能前,我们对业界公有云进行了充分调研,仅有两家主流公有云平台提供实例迁移功能,那么为什么仅两家呢,主要是因为提供在线实例迁移功能需要解决一系列问题,概括起来有以下几点:
1、如何快速地对源实例进行一致性数据备份?
2、如何处理备份过程中对源实例业务的影响?
3、如何快速地将备份导入到目标实例?
4、如何同步源实例的增量数据到目标实例?
5、如何确保实例迁移高效完成?
下面逐条解析蜂巢RDS是如何解决这些难题的。
我们解决第一个问题的方法是采用多线程逻辑备份的方式来进行源实例一致性数据导出。
MySQL的数据备份工具有很多,逻辑备份工具包括经典的mysqlpump,MySQL 5.7版本新推出的mysqlpump,Percona开源工具mydumper;物理备份主要是Percona的xtrabackup工具。俗话说没有最好的,只有最合适的,那么在这些备份工具中,哪种工具最适合用于进行实例迁移呢?我们的答案是mydumper。
首先我们排除了xtrabackup,虽然物理备份在性能上有优势,但其无法在远程备份源实例,在进行实例迁移时,我们不可能要求用户赋予操作源实例服务器的权限,尤其在迁移其他公有云平台的RDS实例时更不现实。此外,物理备份产生的备份数据往往比逻辑备份导出的数据更大,因为xtrabackup直接拷贝物理文件,而逻辑备份是导出SQL语句。下面是我们对几种备份工具的对比测试结果,可供参考:
排除了物理备份后,还有三个选项:mysqldump、mysqlpump和mydumper。我们最终选择了mydumper,因为mydumper是多线程的。等等!了解MySQL的同学会质疑,mysqlpump也是多线程的?对,mysqlpump的多线程思想甚至比mydumper更先进,详见参考文献1和2。但mysqlpump是表级的并发,且还不成熟,而mydumper是记录级的并发,针对单个大表的场景,更容易发挥多线程优势。
也许你会好奇,mydumper是如何实现记录级的多线程一致性备份的,其备份流程图如下:
mydumper由主线程和多个工作线程配合完成数据一致性备份,主线程执行FTWRL或Lock Tables tablelist Read阻塞写操作来建立一致性备份点并记录当前BinLog和GTID。工作线程在主线程仍持有锁的情况下将各session的事务级别设置为可重复读(repeatable-read),并开始进行快照读,由于此时各表无法进行数据写入或更新,所以工作线程快照读的数据就是主线程建立一致性备份点的数据。待所有工作线程均已开始快照读后,如果不存在MyISAM等非事务性表,主线程即可释放读锁。mydumper原理的详细分析详见参考文献3。
无论是物理备份还是逻辑备份,都会或多或少对数据库线上业务造成影响。如何处理备份过程中对源实例业务的影响是我们需要解决的第二个问题。蜂巢RDS实例的设计原则是线上业务永远比迁移任务更重要。由于无法有效了解源实例所在服务器层的监控数据,我们在MySQL数据库层进行大量的优化来减低影响,包括引入持锁时间超时机制、基于业务负载智能调整导出并发度和InnoDB Buffer Pool(BP)污染控制等。
如前所述,为了能够得到一致性的数据,各种备份工具,包括xtrabackup和mydumper,都需要有个短暂给源实例加读锁的过程,正常情况下短暂,但也会有例外,如源实例中存在数据量较大的MyISAM表时,持锁时间会变长。
为了能够避免持锁时间过长导致业务的写操作被阻塞,使用蜂巢RDS进行实例迁移时,用户可以选择允许持有读锁的最长时间,如下图所示,如果超过该阈值时间,会无条件解锁并让迁移操作失败,用户可以选择在业务低峰期进行重试。
在顺利加锁建立一致性快照并解锁后,就进入到各种Schema和表数据的导出环节,用户应根据源实例的线上业务负载和实例的服务器IO能力来合理选择导出数据的并发线程数,如上图所示。
业务负载并不总是可以预测的,但业务总是最重要的,那么当短暂的业务高峰上来时,我们希望将服务器有限的IO能力还给业务,而不是用在迁移上。蜂巢RDS提供了负载监控阈值选项,在业务负载超过该阈值时,会暂停迁移操作,直到负载重新低于阈值。如果用户选择了多线程导出,则能够根据业务负载动态调整线程个数,确保在业务优先的前提尽可能快速的完成数据导出操作。下图为基于业务负载自适应调整导出线程的例子。
在逻辑导出过程中,还会根据用户提供的迁移账号权限,选择性调整InnoDB BP参数来最大限度减小迁移连接的查询操作对BP热点数据的污染。尽可能将因迁移而进入BP的数据保留在BP的LRU List冷数据一侧,并尽快被替换出BP,详见参考文献4。当然设置BP的参数需要账号有Super权限,对于公有云上的源实例,无法进行该项优化。
使用与mydumper配套的多线程恢复工具myloader来将备份的数据导入到目标RDS实例上,myloader执行流程如下图所示。由于此时目标实例没有负载,所以可以尽可能调大导入并发线程数,将目标实例的IO能力吃满。此外,在数据导入时,我们通过关闭slow log和binary log,将innodb_flush_log_at_trx_commit设置为0来最大限度提高导入性能,在完成数据导入后再将对应的参数调整为原值。这是我们解决第三个问题的方法。
在完成数据导入后,对于全量迁移的场景,迁移就结束了。若选择增量迁移,还需将数据导出和导入时在源实例上产生的增量数据(Update/Delete)也迁移到目标实例,我们采用MySQL复制的方式来同步这些数据。
由于MySQL 5.5、5.6和5.7版本的复制存在较大差别,我们根据源实例的版本选择对应的目标实例版本。对于MySQL 5.5及更低版本的源实例,选择网易开源MySQL版本InnoSQL 5.5.30作为目标RDS实例版本,对于MySQL 5.6和5.7,选择InnoSQL 5.7.12为目标实例版本。进行上述版本配对的原因在于:
一是希望用户尽可能采用MySQL最新的稳定版本5.7,因为MySQL 5.7是有史以来最好的版本,带来了众多优秀的特性,包括基于GTID的复制、sys表等,同时相比之前的版本解决或优化了大量缺陷或不足。
二是能够更加方便地配置复制。MySQL 5.7版本提供了基于GTID和基于BinLog两套复制机制,针对源实例的不同的复制配置,能无缝适配。用户在迁移源实例时,可选择迁移实例上全部数据库,也可选择仅迁移部分数据库,MySQL 5.7版本可使用新增的“CHANGE REPLICATION FILTER”语法在线进行过滤复制设置而无需重启mysqld。由于MySQL 5.5及更低版本无法满足MySQL 5.7版本与之建立复制所需的实例UUID,所以目标实例使用InnoSQL 5.5.30版本。当然,相比社区版MySQL 5.5.30,InnoSQL 5.5.30实现了在线过滤复制功能。
我们采用并行复制技术来提高增量数据同步的效率,快速缩短主从复制延迟。由于MySQL 5.6版本GTID特性并不完善,在将其迁移到MySQL 5.7版本时,采用基于DATABASE的并行复制方式,避免LOGICAL_CLOCK并行复制时由于GTID EVENT未记录并行信息导致复制出错的bug。这样,第四个问题也得到了解决。
4如何高效完成迁移
相信大家都认同,实例迁移是个重型操作,谁都不会闲得无事对线上库来一把实例迁移。既然决定要进行实例迁移,那么就希望能够一次性完成迁移,避免来回折腾。如何确保高效地迁移就显得尤为重要,用户需先进行迁移评估并完成准备工作,蜂巢RDS通过迁移预检查、提供出错重试等措施来提高迁移成功率。
用户首先需在迁移前做好评估工作,包括选择业务低峰期进行迁移,这样既最小化对业务的影响同时也能够提高迁移速度;确认业务连接数据库的配置能够进行一次性切换,缩短切换所需时间,同时避免部分业务逻辑连接源库,另一部分连接目标库导致数据不一致;其次,根据所迁移的数据量,合理选择目标实例的存储空间,避免因为目标实例空间不足导致失败;最后,还需要创建满足迁移要求的数据库账号。
我们希望在开始迁移前就发现所有可能引起迁移失败的因素并纠正。迁移预检查是重要手段,主要包括用户在源实例创建的迁移MySQL账号权限检查、MySQL参数设置检查。
迁移权限检查用于确认迁移账号是否能够顺利完成迁移操作,主要包括对数据库定义、表定义,视图、触发器、存储过程和函数等Schema的查看权限;对所选中数据库中表的Lock Table权限,及表中数据Select权限;如果选择增量迁移,则还需检查账号是否具备Replication slave和Replication client权限等。通过查询源实例的MySQL、information_schema或performance_schema等系统库来检查迁移所需权限。MySQL参数检查主要针对需要做增量数据同步的场景,如果用户选择增量迁移,源实例需正确设置server_id和log_bin等参数。如果在预检查中发现错误,会给出明确的提示,引导用户进行参数调整后再重新进行预检查。
在迁移过程中,提供了进度显示功能,如下所示:
迁移的每个阶段都会有带进度条的百分比显示,并周期性自动刷新。同时还会显示整体的迁移进度,方便用户随时查看。若在数据导出或导入等阶段发生错误,则会提示错误信息,一般出现迁移错误的原因主要是由于存在MyISAM表导致持锁时间超时,根据错误信息可以对迁移参数进行针对性修改后进行重试,无需重新开始迁移。
在确认目标实例和源实例间没有复制延迟后,就可以结束迁移并将业务的IP切换为目标实例IP,当然,在IP切换前,请确认已经在蜂巢RDS实例上创建业务访问所需的数据库账号并赋予合适的权限。
参考文献:
http://www.innoMySQL.com/article/25383.html
http://MySQLserverteam.com/introducing-MySQLpump/
http://www.innoMySQL.com/article/25456.html
http://dev.MySQL.com/doc/refman/5.7/en/innodb-performance-midpoint_insertion.html
http://dev.MySQL.com/doc/refman/5.7/en/replication.html
相关专题:
◆ 近期热文 ◆
从SQL Server到MySQL,4款主流迁移工具到底哪家强?
从DBA管理角度,看12c那些令人倾心的内存新特性
如何用一款小工具大大加速MySQL SQL语句优化
从微软和小米的转型之痛,解读DevOps落地的核心要点
数据库高可用实战:化繁为简搭建一套轻量级架构
◆ 专家专栏 ◆
◆ 近期活动 ◆
Gdevops全球敏捷运维峰会上海站
峰会官网:www.gdevops.com