文章目录
因为每个人熟悉的工具不同,其对应的迁移、升级、备份和恢复的方式也都略有不同,本书将尽量对笔者认为最具普遍性的一些操作进行讲述。
另外还整理出了一些注意事项,DBA需要有缜密的思维,要考虑到可能出现的各种情况,并能够冷静地处理异常情况。
13.1 升级
MySQL的升级主要有两类,一种是对数据库表结构或数据的变更,另一种是数据库版本的升级。
13.1.1 升级表结构或变更数据
可以直接在命令行下键入SQL语句进行升级,或者执行SQL文本文件,
为了避免乱码和各种字符集的转换,建议文本文件的字符集与MySQL服务器字符集,以及数据库连接的设置都保持一致,生产环境中建议都统一为utf8。
生产环境中,一般是通过SQL脚本进行升级,以下将详述这种升级方式,大致步骤如下。
1)首先确认要升级的数据库信息:数据库IP、端口、数据库名,是否有多个分库需要升级等。
2)检查升级的脚本。
如果脚本中存在非英文字符,则需要确保是utf8无BOM格式的文件,检查语法是否正确,是否有异常符号,比如全角符号、Windows换行符等。
对于重大的操作,比如删除数据库,如果有疑问,请事先和研发、测试人员进行确认。
3)评估升级对生产的影响,以及升级所耗费的时间。
如果可能会影响到生产,则应该和研发、测试、产品、运营等工作人员沟通协调升级的方式,是否停服,是否需要另选时间,比如在凌晨负荷低峰时期执行。
在操作过程中,应该尽量做到不影响生产负荷,一些操作可能导致服务可用性下降,比如在大表上修改表结构。
一些操作大量数据的语句,比如INSERT INTO SELECT、CREATE TABLE AS SELECT语句,需要锁表,可能也会导致服务可用性的下降。
对于大的更新及删除 语句可考虑分拆成多条语句执行。
尽量平均分布负荷,以减少对生产负荷的冲击。
4)原则上,升级操作,应该是被测试验证过的。如果是复杂的升级,往往还需要进行模拟演练。
5)升级前,应该备份数据。备份的原则是能够尽快回滚,如果要升级的表比较多,可以考虑进行一次全备。注意存储过程和触发器的备份方式不同于普通数据。
6)执行操作前,应该检查是否连接到了正确的数据库,检查执行环境,比如操作系统、mysql客户端,可以在mysql命令行提示符下运行STATUS进行验证。
例如,以下命令将验证客户端、连接、数据库等信息,我们推荐使用utf8字符集。
mysql> STATUS
mysql Ver 14.14 Distrib 5.1.70, for unknown-linux-gnu (x86_64) using readline 5.1
Connection id: 1109769683
Current database: db_name
Current user: root@localhost
SSL: Not in use
Current pager: stdout
Using outfile: ‘’
Using delimiter: ;
Server version: 5.1.70-log MySQL Community Server (GPL)
Protocol version: 10
Connection: Localhost via UNIX socket
Server characterset: utf8
Db characterset: utf8
Client characterset: utf8
Conn. characterset: utf8
UNIX socket: /tmp/3306/mysql.sock
Uptime: 339 days 21 hours 34 min 26 sec
以上连接、客户端、数据库、数据库服务器的字符集都设置为utf8了。
检查是否连接到了正确的数据库及主从库,Current database及UNIX socket都标识了当前正在更新的库。
7)升级前,可能需要停止写入,或者停止一些守护,应该和应用服务器的维护人员一起确认是否已经停止了相关的写入或守护。
8)可以考虑把升级记录到日志里。
连接时加-v参数,执行SQL语句时使用tee filename把操作语句的日志输出到文件,执行完毕后进行操作检查。
这也是一个好习惯,方便以后我们进行回溯和检查升级的细节。
9)对于表结构的调整,如果分配更多的资源能缩短执行的时间,那么可在会话级调大资源分配。
以上是升级的大致步骤,现实中,升级的准确性,不仅仅取决于经验、技能,也取决于流程、研发与测试环节的完善,这点不容忽视。
对大表的升级
MySQL更改表结构时,如果是大表,则可能会导致性能问题,
因为MySQL 5.1、MySQL 5.5更改表结构的绝大部分操作就是生成一个新结构的临时表,
然后把数据插入到新的表,逐条插入记录,同时修改索引,在将所有数据都复制到新的表之后,删除旧表,
然后将新表重命名为旧表的名字,实现新旧表的切换。
这种操作成本高,还会导致不能写入数据,对于许多生产系统来说,这是不可接受的,因为它会严重影响服务的可用性。
由于修改大表的表结构时,需要复制一份数据,所以要留意空间是否足够。
MySQL 5.5提供了更多的在线修改表结构的功能,InnoDB也支持通过排序的方式来创建索引,而之前的MySQL 5.1是以逐行插入数据的方式创建索引的。
但是,相对于一些NoSQL产品,MySQL在线DDL的能力还是比较弱的,需要尽量小心地避免修改大表结构。
在MySQL 5.6版本中,官方更进了一步,增强了很多ALTER TABLE操作,并尽量避免了复制整张表的数据。
在修改表结构的同时,允许SELECT、INSERT、UPDATE、DELETE语句继续执行,这种特性也称为在线DDL(online DDL)。
如果因为更改表结构而导致的写阻塞,那么有什么办法可以减轻或避免呢?
Percona工具“online schema change”可以做到在线修改表结构而不阻塞服务。
M-M架构也可以进行变通解决。
或者你可以把数据库升级到MySQL5.6,从而利用其在线修改表结构的特性。
变更数据或导入数据的时候,需要留意该操作对生产的影响,应该控制记录更新的频率,平均分布生产负荷。
对于不同的硬件,具体控制的写入频率也应不同,对于普通的SAS硬盘,建议控制在每秒小于200条记录;
对于SSD,由于IOPS大大提高,因此每秒控制在500~1000条记录也是可以的。
实际更新数据的频率还取决于生产系统的繁忙程度,以及对缓存的影响,更新数据有一个原则,那就是如果不赶时间,那么慢一些会更安全。
变更数据可能会导致从库延时较长,如果从库也提供生产服务,那么需要留意延时的影响。
平均分布负荷,将修改或导入数据的操作切割为更小的单元,可以缓解延时。
对于导入大量数据的操作,我们可能难以判断导入的进度,可以大致估算下磁盘的空间,估计目前的进度和剩余的时间,例如如下命令。
[mysql@db1000]$ du -sh ;sleep 3600;du -sh
以上命令可以查看空间增长,了解大概导入了多少数据。
有时,我们希望利用主主复制架构实现平滑更改大表的表结构,
即,我们先在从库上更改完大表结构,把数据库流量切换到从库,然后再更改主库的表结构, 再把数据库流量切换回来,
注意,在操作从库和主库之前我们需要在会话(session)中运行Set sql_bin_log=0。
具有SUPER权限的客户端可以通过SET sql_log_bin=0的语句禁止将自己的语句记入二进制记录。
这样就不会在修改大表结构时对它的从库造成影响。
13.1.2 MySQL版本升级
MySQL的版本升级,需要考虑许多因素,如果是大版本的升级,建议首先仔细研读官方的升级文档,因为可能会有一些细节并不包含在常用的步骤之内。
如下是升级的注意事项。
升级前应仔细阅读官方的升级文档。
升级后,应再重启以确认是否正常。
mysqldump备份的转储文件可用于升级。由mysqldump导出来的转储文件,相对于物理文件形式的备份来说,兼容性更高。
使用转储文件升级的步骤大致是:
先用mysqldump把数据导出来,备份权限,然后升级MySQL代码,并运行mysqld_upgrade脚本进行升级,然后导入转储文件,恢复权限信息。
如果是从库,那么需要在升级前停止复制,升级后恢复同步。
一般情况下不需要导入MySQL系统库,因为新版本的mySQL系统库可能会有结构上的变更,如果一定要导入MySQL数据库,则要记得使用FLUSH PRIVILEGES生效权限,并使用mysql_upgrade进行修复。
主从架构升级的话,应先升级从库,从库高于主库一般是可行的,反之则可能出问题。
不要跨越大版本进行升级,比如,4.1升级到5.0是正确的策略,其他跳过版本的升级可能会有问题,如果升级4.0到5.1,那么合适的策略是按照 4.0→4.1→5.0→5.1这样的顺序进行升级。
如下是升级的具体步骤举例,可供读者参考。
1)如是主从架构,则先升级从库。
2)关闭MySQL实例,并确认已经停止了服务。
3)备份并删除MySQL旧版本。注意,不要误删除了数据。
4)安装新版本MySQL,并启动新版本,确认数据能正常加载。为了使数据更安全,可以配置启动时不开启复制,对于小版本的升级,不停止复制一般也不会有问题。
5)运行mysqld_upgrade脚本升级。如果是主库,可禁用二进制日志写入(skip-write-binlog)。
bin/mysql_upgrade -uroot -ppassword -S /path/to/mysql.sock --skip-write-binlog
6)确认升级成功,重启MySQL,确认MySQL启动正常。
13.2 新业务部署上线
新业务上线会涉及相关的其他团队,这里仅做简单的描述,作为DBA,必须做到如下的一些步骤。
首先,我们需要检查数据库服务器,并配置好主从环境。
其次,我们要确认监控、备份、收集信息的策略是否已经实现。
然后,执行SQL脚本部署新数据库和初始化数据,如有遗留的测试数据,请务必先清理掉。
最后,配合其他团队调试并上线,上线后,还需要观察一段时间。
13.3 迁移
13.3.1 迁移步骤
一般迁移数据库时有如下4个步骤。
(1)迁移数据库策略的制定
确定迁移前后的架构和物理部署的变化、迁移的方法、迁移的时间、使用的迁移工具、迁移的风险、迁移的回滚策略等。
如果迁移数据是完全通过应用程序来实现数据迁移的,那么DBA往往不需要进行任何操作,需要做的事情主要是监控迁移过程中数据库负荷的变化。
比较常见的迁移数据库的方式是,DBA在新的数据库主机上部署新的基础环境,
例如,我们有A、B一对数据库主从,因为A、B主机的磁盘空间不够,我们需要将数据库迁移到C、D主机,然后在C、D主机上部署一对数据库主从。
接着通知应用服务器的运维工程师修改应用程序的数据库配置文件指向新的数据库主机C,最后,运维工程师重启应用程序,实现对数据库的切换。
一些公司,实现了中间件,数据库流量都通过Proxy,然后到达后端的MySQL,此类数据库流量的切换一般都比较简单,只需要在平台上修改数据库流量的指向,指到其他的数据库主机即可。
我们这里讨论的主要是另一种情况,即通过修改应用服务器配置文件,或者通过修改内网DNS的方式将数据库流量切换到新的数据库主机。
(2)确定迁移数据库的具体步骤
细化迁移的步骤,预估各个步骤所需要的时间。
我们不仅要考虑实际操作的时间,也需要考虑确认的时间,预留处理异常的时间。
基础环境的准备可以预先完成,并且添加必要的监控。
(3)迁移数据库,并检查
实际操作中,应该严格按照拟定步骤的顺序来执行,尽量做到做完成一项,确认一项。
(4)迁移后的处理
迁移后,要注意清理废旧的环境,对新环境进行完善监控,必须要留出足够的人力和时间用于观察。
对于切换、迁移数据库,有如下一些注意事项。
1)切换前检查新旧服务器的软硬件配置和网络配置。
常见的检查项目有RAID卡、磁盘阵列、CPU、MySQL版本、变量和参数文件的差异、网络、防火墙配置等,
可以用Percona工具pt-config-diff检测来对比迁移前后新旧主机参数的差异,它不仅可以检测参数文件的差异,还可以检测实际变量和参数文件之间的差异。
我们需要关注的参数主要是连接数、字符集、内存参数、步长和偏移量、事务隔离级别、日志保留策略、是否只读、server_id等。
保持主从软硬件的基础环境和配置的一致性,可以让你后期的维护更简单。
需要留意的是,应用程序的逻辑不应该依赖于参数文件,比如应用程序的逻辑不能只依赖于偏移量、步长等参数。
主从库的参数配置最好一致,这样部署一个新的从库时,就只需要修改下server-id即可。
2)主从库的权限设置应该一致。
由于数据库的服务器一般处于内网,没有外网IP,相对来说比较安全,那么建议不要对权限设置得过细,否则迁移环境时,还需要考虑修改权限,而DBA很可能会忽视了这点。
3)如果是新搭建的主从环境,需要确认主从库同步是否正常,可以使用SHOW SLAVE STATUS命令进行确认。
4)如果是主从复制架构,则需要把数据库流量切换到从库,需要在切换前记录从库的SHOW MASTER STATUS信息。
5)应用程序切换数据库流量时,需要防范数据库同时写入主从库的可能性。
如果我们有多台应用服务器,可以临时关闭大部分应用服务器,仅留下一台应用服 务器,这样重启时,就不会发生同时写入主库和从库的情况。
为了安全,我们可能不得不把主库设置成只读。需要注意的是,只读的设置对于Super权限的连接用户是无效的。
如果同时写入主库、从库,可能会有主键冲突,从而影响复制,如果发生了主键冲突,可以考虑忽略部分数据或重做从库。
6)对于数据库流量的切换,需要运行命令确认切换是否成功,SHOW PROCESSLIST、SHOW MASTER STATUS、SHOW SLAVE STATUS\G等命令可以协助你确认信息。
我们还可以用tcpdump或iptables命令判断是否还有流量访问旧的数据库端口。
7)旧的数据库如果已经不再使用,则必须及时清理和删除数据。
如果已经不需要同步关系,则请务必及时清理掉同步关系,以免误操作数据,同步了生产库。
如果将从库提升为主库,则需要停止从库部署的备份脚本。
8)尽量在迁移前就部署好监控,迁移后,需要检查各项的状态信息、性能收集、备份、监控是否完备。
13.3.2 切换数据库时长短连接的影响
由于长连接往往缓存了数据库IP,因此需要重启应用服务器才能实现对数据库访问的变更。
以Nginx+PHP+fpm为例,当我们使用fpm来管理PHP进程时,MySQL长连接缓存了访问数据库的IP;
当我们更改数据库路由时,比如,更改了数据库配置文件,或者更改了内网DNS,我们需要重启php-fpm管理器才能生效。
如果是Nginx+fpm+PHP的部署,那么PHP进程数×主机数=实际的长连接数。
如果查询缓慢则会导致所有的PHP进程都无法处理其他的请求,因为PHP进程需要等待数据库的响应。
短连接可能也会缓存对数据库的访问IP,
比如,PHP应用,使用短连接访问数据库,配置文件内存储的数据库实例的DNS域名,如果更改了内网DNS,那么无须重新启动服务即可生效,
但如果数据库配置文件中存储的是主机名,那么更改/etc/hosts可能会无效,因为主机名被缓存了,我们仍然需要重新启动应用服务器。
Java服务器默认也缓存了DNS结果,你可以将其设置为禁止缓存,但很少有人这么做,所以更改了内网DNS,或者更改了配置文件内的数据库IP,也需要重启Java服务器。
现实中,不同的应用服务器可能会有不同的行为,所以我们需要了解,在更改了数据库配置文件之后,我们的应用服务器是否需要重新启动才能生效。
13.4 生产环境常用的备份策略
为什么我们需要备份呢?
备份的主要目的是为了灾难恢复,备份还可以用于测试应用、回滚数据修改、查询历史数据、审计等。
之前我们在其他章节已经讨论了备份的一些方式和工具的使用方法,本节将从生产运维的角度介绍备份策略的制订。
由于生产环境一般是主从架构,因此本书将基于这种架构,阐述备份的一些策略和方式。
如果是拥有大规模数据库集群的公司,你可能需要专门规划执行数据库备份的机器和海量分布式文件系统,以存储备份,
你可能还需要有专门的检测系统、调度系统、恢复测试系统、预警系统和保留策略,以应对大量数据库的备份。
13.4.1 备份策略
我们需要制订备份策略并文档化。我们需要考虑许多因素,
比如,数据的重要程度、是否需要时间点恢复、数据量的大小、是否有法律规定要保留多久、需要多久恢复、用户可以接受多久恢复、用户是否可以接受部分功能不可用及其他一些因素。
一般常见的方式是每天选择负荷小的时间段进行备份,然后将备份保留一段时间。
我们推荐在从库上进行备份,对于负荷比较小的业务,你也可以选择在主库上进行备份,前提是不影响生产负荷。
对于数据量大的备份,每次制作一个全量从库的代价可能会很大,定期全量备份,然后再进行增量备份,是值得考虑的方法。
备份服务器应该视为与生产服务器一样重要,甚至更重要。
备份文件应该和数据库主机物理分开,可以选择FTP上传或其他网络传输方式把备份文件保留在独立的备份服务器上。
我们也可以使用NFS挂载文件系统的方式进行远程备份,如下是挂载远程文件系统的一个例子。
cat /etc/rc.local
mount -t nfs -o rw,bg,hard,nointr,rsize=4194304,wsize=4194304,tcp,vers=3,timeo=600,noac 11.11.11.11:/home/nfs_dir /home/mysql/nfs_from_db1000
写入/etc/rc.local的原因是希望在系统启动时挂载。
rsize、wsize参数的默认值都比较小,可以适当加大。
注意要使用sync的方式,不要使用async的方式进行挂载
需要留意到是,使用NFS的方式可能不够稳定,而且客户端是一个串行的机制,无法提高吞吐,使用NFS的方式,还有潜在的安全风险,但由于NFS简单方便,所以还是有许多人在使用它。
我们应该制定完善的数据保留策略,有日备份、周备份、月备份、季备份,原则上,最近的备份应该每天都保留,随着时间跨度的增长,我们可以保留更少的备份。
一般我们使用热备份,而不使用冷备份。“Hot”的本意是不用关闭MySQL服务,不影响服务。
由于InnoDB支持在线热备份,所以建议都使用InnoDB引擎。而MyISAM引擎进行备份的时候必须锁表,这点很可能会影响到服务的可用性。
13.4.2 备份建议
如下是一些备份的建议。
对于很大的数据库,物理备份更适合。 对于非常大的数据库,逻辑备份恢复得太慢,可能会出错,建议选择物理备份。
对于小数据库,用逻辑备份mysqldump就可以了,这样也简单。
由于大数据库每天全备成本太高,使用增量备份或保留副本也许是更好的选择。
mysqldump进行远程备份的时候,需要确保网络的稳定性,如果备份的时间比较长,而网络又不太稳定,则可能会由于网络波动而导致备份失败,
增加备份的重试机制或先备份到本地,再上传或同步到其他服务器会更好。
我们应该按重要程度保留多个备份。
我们应定期提取备份验证,衡量恢复所需要的资源,以及恢复的速度和效果。
主库应该启用二进制日志。 主库应该启用二进制日志,以便搭建从库,做时间点恢复。expire_logs_days参数至少要跨越2~3个备份;
在从库中启用log_slave_updates,如果没有启用,则应考虑是否备份主库上的二进制日志。
监视你的备份和备份过程。
应该考虑备份文件的安全。
13.5 常用备份方式和恢复方法
MySQL的备份方式可以分为物理备份和逻辑备份两种,物理备份主要是通过备份数据文件,以快照的方式进行备份,
如果我们使用了LVM或一些存储系统,那么快照将是最方便的方式。
备份数据文件或快照往往可以更快地备份和恢复。
本节主要讲述在操作系统下备份数据文件或逻辑备份,对于快照方式不进行叙述,大家可以参考LVM或存储系统做快照的一些技术。
常用的备份工具有mysqldump和Percona XtraBackup。
mysqldump是官方自带的一种逻辑备份工具,它的兼容性很好,与版本无关,恢复起来更方便,没有理由不使用它。
一般小公司,生产环境大都是用mysqldump进行备份的。
Percona XtraBackup是Percona公司提供的工具,对于备份大数据很有效。
13.5.1 使用dd备份和恢复数据
使用dd备份数据是传统的办法,虽然现在已经用得很少。 如下是一些备份的例子。
1)将本地的/dev/hdx整盘备份到/dev/hdy。
dd if=/dev/hdx of=/dev/hdy
2)备份/dev/hdx全盘数据,并利用gzip工具进行压缩,保存到指定路径。
dd if=/dev/hdx | gzip >/path/to/image.gz
3)将备份文件恢复到指定盘。
dd if=/path/to/image of=/dev/hdx
4)将压缩的备份文件恢复到指定盘。
gzip -dc /path/to/image.gz | dd of=/dev/hdx
5)将光盘数据复制到root文件夹下,并保存为cd.iso文件。
dd if=/dev/cdrom of=/root/cd.iso
13.5.2 使用mysqldump备份和恢复数据
mysqldump这个命令在之前的章节里已经有过许多讲述,对于普通数据的备份,这里将不再赘述。
我们一般使用如下命令备份整库。 mysqldump --databases db_name > db_name.sql
使用如下命令恢复数据。 mysql db_name < db_name
或者可以使用source命令来执行。 mysql > source /path/to/db_name.sql
生产环境中一般为主从配置,那么我们一般会在从库上配置备份脚本,进行定时备份。
如下是一个使用mysqldump备份的示例。 mysqldump --flush-logs --master-data=2 --hex-blob -R -E -f --all-databases 2>> /path/to/log | gzip > sql.name.gz
对于InnoDB备份,我们可以加上–single-transaction,实现无阻塞备份。
生产环境一般在从库中进行备份,那么我们还可以把复制SQL线程临时关闭以进行备份。
有时我们需要指定字符集参数进行备份,如在MySQL 5.5及以上的版本中,如果你使用了utf8mb4字符集,那么需要添加参数–default-character-set=utf8mb4。
在MySQL 5.6中,由于安全性的需要,你需要把备份账号的密码保存在配置文件中或MYSQL_PWD环境变量内,比如,你可以在脚本里执行export MYSQL_PWD=your_password。
我们需要留意其他一些数据的备份,比如视图、存储过程、触发器和事件。
由于视图有依赖,如果基础表不存在或没有权限,那么视图的导出将会失败,而且会导致mysqldump命令的退出,
为了避免无效视图导致备份库失败,我们可以在导出的时候,添加一个参数-f强制导出数据而不是中途退出。
对于mysqldump的备份,需要检查其输出,检查是否有错误或警告,正常备份结束后,应该有“Dump completed on”字样,我们可以使用–result-file参数保存mysqldump结果。
对于报警或错误的信息,我们需要及时处理,比如视图中引用了不存在的表。在我们导入视图之前,需要处理好基表不存在的问题。
存储过程、视图、触发器的导出信息里可能带有DEFINER信息,在导入的时候,因为目的库中并不存在相应的用户信息或缺少权限,因此我们需要把DEFINER信息批量替换成合适的用户。
如果不指定DEFINER信息,那么系统会自动使用默认的用户。
如下是一个导出存储过程的例子。
mysqldump -uroot -S /path/to/tmp//3306/mysql.sock -p -td -R --triggers=false db_name > db_name_procedure.sql
如下是一个导出触发器的例子。
mysqldump -uroot -S /path/to/tmp//3306/mysql.sock -p -td db_name > db_name_trigger.sql
如下例子将仅导出数据,而不包括存储和触发器。
mysqldump -uroot -S /path/to/tmp//3306/mysql.sock -p --triggers=false db_name > db_name_data.sql
导入视图、导入触发器和导入数据类似。
但导入触发器时,需要先删除数据库中原有的触发器。
由于导出触发器的转储文件里没有DROP TRIGGIER语句,因此 我们需要手动生成DROP TRIGGER的语句,命令如下。
SELECT TRIGGER_SCHEMA,TRIGGER_NAME,DEFINER FROM information_schema.triggers;
select concat(‘drop trigger ‘,TRIGGER_NAME,’;’) into outfile ‘/tmp/drop_trigger.sql’ from information_schema.triggers where TRIGGER_SCHEMA=‘db_name’;
在MySQL 5.1版本中,如果运行FLUSH LOGS命令,会把我们的MySQL错误日志清除掉,并备份到一个文件,
但是如果多次FLUSH LOGS,就难以追踪错误信息了,因为有用的信息都被过滤掉了。
如果是mysqldump带–all-database选项,那么每备份一个数据库,就会切换一次日志(FLUSH LOGS)。
如果是带–lock-all-tables选项,或者是–master-data选项,那么仅需要切换一次日志,而且在这个时刻,所有表都会被锁住。
另外,对于二进制日志的导出,需要添加一个hex-blob选项。
13.5.3 使用Percona XtraBackup备份和恢复数据
1.概述
Percona XtraBackup是一个免费的MySQL热备份软件,支持在线热备份InnoDB和XtraDB,也可以支持MyISAM表的备份,不过MyISAM表的备份需要在锁定表的情况下进行。
本书对于Percona XtraBackup的叙述是基于2.2版本的。读者实际使用此工具时,请参考相关版本的官方帮助文档。
Percona XtraBackup有3个主要的工具:xtrabackup、innobackupex、xbstream。它们的特点分别如下。
1)xtrabackup:是一个编译了的C二进制文件,只能备份InnoDB/XtraDB数据。
2)innobackupex:是一个封装了xtrabackup的Perl脚本,除了可以备份InnoDB/XtraDB之外,还可以备份MyISAM。
3)xbstream:是一个新的组件,能够允许将文件转成xbstream格式或从xbstream转到文件格式。
你可以单独使用xtrabackup工具,但是我们推荐用innobackupex来进行备份,因为innobackupex本身就已经包含了xtrabackup的所有功能。
xtrabackup是基于InnoDB的灾难恢复功能进行设计的,
备份工具复制InnoDB的数据文件(datafile),但是,由于不锁表,这样复制出来的数据就会不一致。
InnoDB维护了一个重做日志,包含InnoDB数据的所有改动情况。
在xtrabackup备份InnoDB的数据同时,xtrabackup还有另外一个线程监视着重做日志,一旦日志发生变化,就把发生了变化的日志块复制走。
这样就可以利用此重做日志做灾难恢复了。
以上是备份过程,如果我们需要恢复数据,则在准备(prepare)阶段,
xtrabackup就需要使用之前复制的重做日志对备份出来的InnoDB数据文件进行灾难恢复, 此阶段完成之后,数据库就可以进行重建还原了。
Percona XtraBackup对MyISAM的复制,是按这样的一个顺序进行的:先锁定表,然后复制,再解锁表。
2.Percona XtraBackup的安装和部署
在http://www.percona.com/downloads/XtraBackup/LATEST/ 上可以下载最新的Percona XtraBackup二进制包。
直接解压可以看到有两个目录,其中,bin目录就是存放之前说过的备份工具,share目录存放着Percona XtraBackup的测试脚本。
这里解释bin目录中各个文件的意义。
除了之前说过的3个工具innobackupex、xtrabackup、xbstream之外,我们还可以看到几个之前没有提到过的文件,它们分别是xtrabackup_51、xtrabackup_55、 xtrabackup_56。
这是Percona XtraBackup为了保证对InnoDB发行版的有效兼容而采取的一种人性化的做法。
下面来看看这些命令的作用范围,如表13-1所示。
innobackupex的备份过程中,会生成一些文件,如下是一些生成的文件。
xtrabackup_checkpoints:此文件包含了LSN号与备份类型。此文件被用于增量备份恢复。
xtrabackup_binlog_info:此文件记录了备份时刻二进制日志的位置,即SHOW MASTE RSTATUS的结果。
backup-my.cnf:此文件仅仅记录了备份所需的my.cnf中的选项,它并不是my.cnf的备份。恢复的时候,需要确认目的地的配置文件也要与这个文件记录的一致。
xtrabackup_binlog_pos_innodb:此文件记录了备份时刻InnoDB的二进制日志的位置。
xtrabackup_slave_info:当使用–slave-info选项在从库进行备份时,将会记录CHANGE MASTER语句,以便日后用于搭建新的从库。
也就是说它记录了我们正在备份的从库的SHOW SLAVE STATUS\G里的Relay_Master_Log_File和Exec_Master_Log_Pos的值。
以便于我们在这个从库的基础上,为主库搭建其他从库。
其他文件略。
3.如何全备
以下是一个全备的例子,命令中,
由于数据量很大,因此我们最好使用管道输出到pigz 压缩命令,进行压缩。
pigz是一个开源的压缩工具,可以并行压缩文件,如果你的Linux系统没有安装,那么请下载并安装它。
innobackupex-1.5.1 --defaults-file=
d
e
f
m
y
c
o
n
f
−
−
s
l
a
v
e
−
i
n
f
o
−
−
u
s
e
r
=
{def_myconf} --slave-info --user=
defmyconf−−slave−info−−user=user --password=
p
a
s
s
w
o
r
d
−
−
t
m
p
d
i
r
=
password --tmpdir=
password−−tmpdir={tmp_dir} --stream=tar
d
a
y
b
a
c
k
u
p
d
i
r
2
>
>
day_backup_dir 2>>
daybackupdir2>>xtrabackup_log |pigz -p 8 >
b
a
k
f
i
l
e
2
>
>
bak_file 2>>
bakfile2>>xtrabackup_log
一些参数介绍如下:
–defaults-file=[my.cnf]:默认的配置文件,注意放在所有参数列表中的第一个。
–slave-info:在备份一个复制架构中的从库时,这个选项非常有用。
它记录了备份时刻正在应用的主库的二进制日志名和位置,这些信息被记录到了 xtrabackup_slave_info文件中,这个有点像mysqldump中的CHANGE MASTER标志。
当你需要为主库搭建新的从库时,可以通过对这个从库的备份加上 xtrabackup_slave_info文件中的二进制位置来恢复同步。
–tmpdir:设置这个参数是为了避免在主机上对多个实例进行备份的冲突,因为可能都要向同一个临时目录写入同样的文件。
备份过程中可能将大量数据写入到tmpdir的默认值/tmp中,所以需要将这个值设置到非/tmp目录中,以免/tmp目录占满影响备份及系统的其他正常服务。
–stream=tar:使用这个流备份选项,我们可以使用tar进行打包。
$day_backup_dir是我们保存备份的目录。
$bak_file是我们的最终备份文件。
实际应用中,还有其他一些选项需要留意。
–databases:指定备份的数据库,若没有指定则默认备份所有数据库。
–export:导出个别表,以便于导入到其他服务器上。
具体的innobackupex选项说明可以参照官方文档: http://www.percona.com/doc/percona-xtrabackup/innobackupex/innobackupex_option_reference.html。
4.如何增量备份
增量备份的原理如下:
1)首先完成一个完全备份,并记录此时的检查点LSN,你需要一个全备才能恢复一个增量的改变,若没有一个全备作为一个基准,那么你的增量备份就是没有意义的。
2)然后进行增量备份时,比较表空间中每个页的LSN是否大于上次备份的LSN,若是则备份该页并记录当前检查点的LSN。
相关的选项如下:
–incremental:建立增量备份。
–incremental-basedir=DIRECTORY:全备目录,主要用于作为增量备份的基准。
–incremental-dir=DIRECTORY:增量备份目录。
–incremental-lsn:用于增量备份的日志序列号。
增量备份的步骤具体如下:
步骤1:全备。
innobackupex /data/backups
这样的全备,会在全备目录下生成一个带有时间标记的目录,即BASEDIR,我们假定BASEDIR是/data/backups/2013-03-31_23-01-18,该目录即为备份的目录,
你也可以通过innobackupex-no-timestamp覆盖这种行为,备份文件将放在给定的目录下。
我们可以看到在BASEDIR目录下有一个文件xtrabackup-checkpoints,里面记录了备份的类型和起始点的位置,如下所示。
backup_type = full-backuped
from_lsn = 0
to_lsn = 1291135
步骤2:第一次增备。
innobackupex --incremental /data/backups --incremental-basedir=BASEDIR
这样就有了一个增量备份,存放在/data/backups目录下一个带时间戳的目录中,假定是/data/backups/2013-04-01_23-01-18,称之为INCREMENTAL-DIR-1,
如果此时还想要再进行一次增量备份的话,那么类似地,也需要一个基准,现在的基准就变成了刚刚完成的增量备份INCREMENTAL-DIR-1了,
我们检查INCREMENTAL-DIR-1目录下的xtrabackup-checkpoints文件,可以看到如下信息。
backup_type = incremental
from_lsn = 1291135
to_lsn = 1352113
步骤3:第二次增备。
innobackupex --incremental /data/backups --incremental-basedir=INCREMENTAL-DIR-1
这次增备是在/data/backups下创建了目录/data/backups/2013-04-02_23-01-18用于保存增量备份,称之为INCREMENTAL-DIR-2,
检查INCREMENTAL-DIR-2目录下 的xtrabackup-checkpoints文件,内容如下。
backup_type = incremental
from_lsn = 1352113
to_lsn = 1358967
你会发现在每一个备份中,不管是全备,还是增备,它们的目录中都有这样一个文件:xtrabackup-checkpoints。
我们也可以通过这些位置点来备份。例如如下语句。
innobackupex --incremental /data/backups --incremental-lsn=1291135
innobackupex --incremental /data/backups --incremental-lsn=1358967
5.如何恢复全备
全备后的文件,不能直接用于恢复数据,因为还存在数据不一致的情况,需要应用事务日志,来确保数据文件的一致性。这也是准备阶段的一个目的。
一旦这些操作完成了,数据就可以被用作恢复还原了。
相关选项及其说明如下:
–apply-log:实际恢复数据时,我们需要先对备份的数据应用事务日志,即在恢复的第一阶段应用日志,
如果你不指定–defaults-file参数,那么这里将默认使用backup-my.cnf文件里参数应用日志。
–copy-back:将之前所做的备份复制到原来的数据目录中。
–redo-only:在进行增量备份恢复时将会用到。
1)准备阶段。
例如,运行如下的命令。 innobackupex --apply-log /path/to/BACKUP-DIR
这里还可以加入–use-memory选项来确保内存,因为这个准备阶段的进程会消耗很多内存。
innobackupex --apply-log --use-memory=4G /path/to/BACKUP-DIR
2)恢复还原数据。
在准备阶段完成之后,通过–copy-back选项来完成把备份恢复到服务器的datadir目录下的操作。
注意:先要备份然后删除数据目录(datadir)下原有的文件,可以保留配置文件my.cnf。
innobackupex --defaults-file=/path/to/datadir/my.cnf --copy-back /path/to/BACKUP-DIR
3)在启动mysql服务器之前,要先确认文件的参数文件、文件属主等信息是正确的。可能还需要将文件的所有者信息更改一下。
chown -R mysql:mysql /var/lib/mysql
4)启动MySQL,确认服务正常。
实际生产环境中,我们一般会压缩备份文件,所以,在恢复重建数据库之前,我们需要先解压文件。
注意:解压tar文件时要加参数-i,如,tar-ixf 2013-02-19_12-20-49.tar.gz
6.如何恢复增量备份
增量备份的恢复类似于全量备份的恢复,也有两个阶段,准备阶段和恢复数据阶段。
(1)准备阶段
与全量备份的准备阶段有所不同,这个阶段需要注意的问题更多。
对于每一个增量备份,只有已经提交了的事务才能被重做。这个过程是将全备的内容与增量备份的内容合并到一起。
那些没有被提交的事务必须被回滚掉,以得到一份可以用来恢复的数据。
具体步骤如下。
1)对基本备份进行准备。
innobackupex–apply-log–redo-only BASE-DIR
BASE-DIR即之前全备的那个目录,运行完毕后,你会看到类似如下的输出。
120103 22:00:12 InnoDB: Shutdown completed; log sequence number
1291135 120103 22:00:12 innobackupex: completed OK!
2)合并第一次的增量备份。
innobackupex --apply-log --redo-only BASE-DIR --incremental-dir=INCREMENTAL-DIR-1
3)合并第二次的增量备份。
innobackupex --apply-log BASE-DIR --incremental-dir=INCREMENTAL-DIR-2
如果有“completed OK!”字样,则表示应用准备成功。
注意–redo-only选项,对最后一个增量备份不要使用–redo-only选项。
4)合并完所有的增量备份之后,我们运行如下命令来准备好整个数据库文件。
innobackupex --apply-log BASE-DIR
现在我们的备份文件可以用来进行恢复还原了。
(2)数据恢复(restore)阶段
在完成了增量备份的准备阶段后,现在的基准目录(base+incremental=full)就像是做了一个全备的目录,可以直接进行重建。
innobackupex --copy-back BASE-DIR
7.时间点恢复
通过innobackupex和MySQL服务的二进制日志文件可以进行基于时间点的恢复,将数据库恢复到历史的某个状态。
二进制日志中保存着对数据库的操作细节,你可以用一个历史备份再加上二进制日志来将数据库恢复到某个时刻。
时间点恢复的过程大致如下:
我们先通过innobackupex做一次全备。 innobackupex /path/to/backup --no-timestamp
接下来,就准备恢复日志应用。 innobackupex --apply-log /path/to/backup
假设某个时刻已经过去了,想恢复数据库到该时刻,那么应该首先知道当前的二进制日志情况。
mysql> SHOW BINARY LOGS; 第一个查询将会告诉你包含了哪些二进制日志文件,
mysql> SHOW MASTER STATUS; 第二个查询将会告诉你哪个二进制日志文件当前正在使用,以及当前的日志位置点。
之后,你可以通过之前所做的备份中的xtrabackup_binlog_info文件,找到备份到的日志编号及日志位置。
cat /path/to/backup/xtrabackup_binlog_info
通过之前所做的备份对数据库进行恢复。 innobackupex --copy-back /path/to/backup
此时,数据已经达到了某个时刻,可以应用之前得到的信息,再使用mysqlbinlog工具进行基于时间点的恢复。
如下是基于时间点恢复的一个案例。我们需要在一台测试机器上将生产环境的数据库恢复到某个时间点。
1)为生产环境数据库建立一个全备,然后把所有文件传输到测试机器上。
innobackupex /path/to/backup --no-timestamp
2)在测试机器上准备恢复,应用日志。
innobackupex --apply-log /home/backup/full/
3)在生产环境中查询当前数据库的日志位置。
mysql> SHOW BINARY LOGS;
±------------------------±----------+
| Log_name | File_size |
±------------------------±----------+
| mysql-bin.000001 | 126 |
| mysql-bin.000002 | 1306 |
| mysql-bin.000003 | 126 |
| mysql-bin.000004 | 497 |
±------------------------±----------+
mysql> SHOW MASTER STATUS;
±-------------------±----------------±-------------±-----------------+
| File | Position | Binlog_Do_DB | Binlog_Ignore_DB |
±-------------------±----------------±-------------±-----------------+
| mysql-bin.000004 | 497 | | |
±-------------------±----------------±-------------±-----------------+
4)到备份目录中去查看我们备份时刻的日志位置。
$ cat /home/backup/full/xtrabackup_binlog_info
mysql-bin.000003 57
5)在测试机器上进行恢复。
innobackupex --copy-back /home/backup/full/
此时,数据库已经恢复到mysql-bin.00000357这个点的数据了。
6)传输最新的日志文件到测试机器上,检查需要应用的日志记录。
$ mysqlbinlog /home/backup/full/mysql-bin.000003 /home/backup/full/mysql-bin.000004 --start-position=357 > mybinlog.sql
此时,会生成一个mybinlog.sql文件,这个文件就是mysql-bin.00000357之后的所有操作的日志。
我们可以打开来查看下,以确认是不是我们需要的日志。
7)如果我们希望恢复到11-12-2501:00:00的数据,那么可以执行如下的语句。
$ mysqlbinlog /home/backup/full/mysql-bin.000003 /home/backup/full/mysql-bin.000004 --start-position=57 --stop-datetime=” 11-12-25 01:00:00” | mysql -u root -p
8.其他注意事项
使用xtrabackup进行备份的一些注意事项如下。
可以使用–parallel参数并行复制文件,但如果你只有一个数据文件(ibdata文件),那将不会有太大的好处,使用独立表空间有利于改善I/O,但是也要注意如果文件碎片很多,可能会导致严重的I/O瓶颈。
对于I/O资源比较紧缺的服务,或者为了减少对生产的影响,可以采用–throttle选项限制I/O。
对于从库的备份,建议加-slave-info选项。xtrabackup_slave_info文件记录了主库(Master)的位置(Position)信息,可以用此信息来搭建从库。
可以加–safe-slave-backup这个选项,这个选项将使得从库在备份的时候会关闭SQL线程。
对于流备份的tar包,我们可以考虑压缩,或者传输到远程服务器上,命令如下。
innobackupex --stream=tar ./ > backup.tar
innobackupex --stream=tar ./ | gzip - > backup.tar.gz
innobackupex --stream=tar ./ | ssh user@desthost "cat - > /data/backups/backup.tar”
解包的操作必须加-i参数,否则会出错,如tar-ixvf backup.tar。
对于恢复操作,一定要确认是否成功,下面的命令 $ innobackupex --apply-log /path/to/BACKUP-DIR 如果执行成功,则应该输出有类似于“11122501:01:57 innobackupex:completed OK!”的字样。
建议备份和恢复所使用的xtrabackup版本是一致的。
13.5.4 使用mysqlbinlog进行时间点恢复
mysqlbinlog是一个从二进制日志读取语句的工具。
当我们使用mysqldump对主库进行备份时,我们需要添加参数–master-data=2–single-transaction,
生成的备份转储文件会存储备份时刻的二进制日志位置信息,我们可以从这个点开始,进行时间点恢复。
当我们在从库上进行备份时,可以关闭从库的SQL线程,然后进行备份,并记录SHOW SLAVE STATUS\G的输出到备份文件,
SHOW SLAVE STATUS\G的输出中记录了当前应用到了主库的哪个位置点的信息。
Relay_Master_Log_File: mysql-bin.000013
Exec_Master_Log_Pos: 18761441
我们可以从这个点出发,进行时间点恢复。
如下的例子说明了如何利用mysqlbinlog进行时间点恢复。 假设要恢复到2010年8月12日下午15:00。
首先,我们将备份文件导入一个临时测试库。
然后,我们查询备份文件,确认备份时刻的主库二进制文件的位置。
我们把包含这个位置点及之后的所有日志文件都传输到临时测试库主机上,假设我们只需要应用一个日志文件。
接下来,我们就可以应用日志了,例如如下语句中:
mysqlbinlog --start-position=18761441 --stop-datetime=” 2010-8-12 15:00:00” mysql-bin.000013 | mysql -uroot -p
18761441这个位置,是我们从备份文件里查询到的。
1)为了保险,你也可以mysqlbinlog输出到文件,然后检查此文件,再用mysql执行。
mysqlbinlog – start-position=18761441 – stop-datetime=” 2010-8-12 15:00:00″ mysql-bin.000013 > /tmp/bin.txt mysql -uroot -p < /tmp/bin.txt
2)如果有多个mysql二进制日志,最安全的方式是所有的二进制日志都顺序应用一个连接,如果将多个连接同时导入数据,可能会导致错误。
如果应用多个二进制日志文件,我们可以使用如下的方式来匹配文件。
mysqlbinlog binlog.[0-9]* | mysql
或者按顺序列出所有需要执行的日志文件。
mysqlbinlog binlog.000001 binlog.000002 binlog.000003 | mysql
小结:
本章介绍了DBA的一些日常维护工作:迁移、升级、备份、恢复。
升级不会是一个轻松的工作,特别是在频繁发布升级的公司。
DBA除了要熟练地掌握基本功之外,还需要规范各种升级操作,减少过多的升级和误操作的可能性。
数据是公司的生命,DBA应该仔细检查备份策略并保护好数据的安全。
DBA应该熟悉各种备份和恢复方式,因为这决定了你能够快速恢复服务的能力。