国内不论是使用阿里云、腾讯云还是华为云的云平台版本的 MySQL 数据库,在遇到数据备份恢复的场景,都会遇到需要使用 Percona XtraBackup 工具进行备份还原的需求。
看着网上一堆既啰嗦又落后的备份恢复方案,不免厌烦,借着再次帮朋友做数据迁移的机会,整理分享之前的实战笔记,希望能够帮助到有需求的同学。
写在前面
国内云平台从业者不多,加上成熟的方案相对固定,所以我们不难看到“御三家”的产品备份恢复策略甚至文档都非常“相似”。
- 阿里云:《RDS MySQL物理备份文件恢复到自建数据库》
- 腾讯云: 《云数据库 MySQL - 使用物理备份恢复数据库》
- 华为云:《通过备份文件恢复到自建数据库(MySQL)》
本文将基于容器工具的方式进行数据恢复处理,避免折腾不必要的软件依赖。
编写数据库恢复实例配置文件
容器时代,如果你不是容器环境的运维工作者,不必过度纠结系统配置,我们直接使用 Percona 官方提供的镜像即可,下面以 MySQL 5.7 为例,你可以根据自己的需求自行修改版本号。
# https://hub.docker.com/r/percona/percona-xtradb-cluster/
version: "3"
services:
percona:
image: percona/percona-xtradb-cluster:5.7
container_name: percona
restart: always
# 根据你的需要,声明暴露端口
# ports:
# - 3306:3306
environment:
- MYSQL_ALLOW_EMPTY_PASSWORD=1
volumes:
- ./node.cnf:/etc/mysql/node.cnf
- ./data:/var/lib/mysql:rw
- ./restore:/var/lib/mysql-files:rw
上面的配置中,我声明了两个目录用于保存数据,首先是用于放置云数据库备份的 restore
目录,其次是用于暂存还原后的数据库文件的 data
目录。将上面的内容保存为 docker-compose.yml
,稍后使用。
接着,编写一个可以用于还原的数据库配置文件:
[mysqld]
skip-grant-tables
ignore-db-dir=lost+found
datadir=/var/lib/mysql
socket=/tmp/mysql.sock
skip-host-cache
#coredumper
#server_id=0
binlog_format=ROW
default_storage_engine=InnoDB
innodb_flush_log_at_trx_commit = 0
innodb_flush_method = O_DIRECT
innodb_file_per_table = 1
innodb_autoinc_lock_mode=2
bind_address = 0.0.0.0
wsrep_slave_threads=2
wsrep_cluster_address=gcomm://
wsrep_provider=/usr/lib64/galera3/libgalera_smm.so
wsrep_cluster_name=noname
wsrep_node_address=172.20.12.2
wsrep_node_incoming_address=0cdb19fc56e4:3306
wsrep_sst_method=xtrabackup-v2
wsrep_sst_auth='xtrabackup:xtrabackup'
[client]
socket=/tmp/mysql.sock
[sst]
progress=/var/lib/mysql/sst_in_progresss
将上面的配置保存为 node.cnf
,然后和之前的 docker-compose.yml
放置相同目录,使用我们熟悉的 docker-compose up -d
将用于数据还原的数据库实例启动起来。
...
2021-10-12T06:08:37.329788Z 0 [Note] Server socket created on IP: '0.0.0.0'.
2021-10-12T06:08:37.385234Z 0 [Note] InnoDB: Buffer pool(s) load completed at 211012 6:08:37
2021-10-12T06:08:37.665867Z 0 [Note] mysqld: ready for connections.
Version: '5.7.33-36-57' socket: '/tmp/mysql.sock' port: 3306 Percona XtraDB Cluster (GPL), Release rel36, Revision a1ed9c3, WSREP version 31.49, wsrep_31.49
2021-10-12T06:08:37.666282Z 2 [Note] WSREP: Initialized wsrep sidno 2
...
使用 docker-compose logs -f
查看运行日志,稍等片刻,看到类似上面的日志,包含 “ready for connections” 就可以开始进行数据恢复操作啦。
进行数据恢复
将你需要恢复的数据复制到本地的 restore
目录中(对应容器内 /var/lib/mysql-files/
目录),也可以使用 docker cp
命令直接向容器复制,不过对于大文件来说,体验并不友好。
数据“解压缩”
在准备好数据备份文件之后,我们进入容器进行后续操作:
docker exec -it percona bash
进入容器之后,先切换工作目录:
cd /var/lib/mysql-files/
假设我们的备份文件格式为 tar
格式的存储文件,需要先进行解压缩。如果是其他格式,比如 .xb
格式,容器内置了 qpress
和 xbstream
工具,参考你的云平台提供的说明文档直接使用就是了。
tar zxvf *.tar
在备份文件解压缩之后,我们就可以正式开始进行数据恢复操作了。
innobackupex --defaults-file=/etc/mysql/node.cnf --apply-log /var/lib/mysql-files/
数据恢复时间,根据你的备份文件大小而定。
InnoDB: 5.7.32 started; log sequence number 3006781461
xtrabackup: starting shutdown with innodb_fast_shutdown = 1
InnoDB: FTS optimize thread exiting.
InnoDB: Starting shutdown...
InnoDB: Shutdown completed; log sequence number 3006781480
211013 07:57:02 completed OK!
当你看到上面的日志输出后,正常的 MySQL 实例正常运行的数据文件就都就绪了。
但是为了进行完整数据导出,我们还需要进行一些额外操作。
导出数据文件
在上文的操作过程中,考虑数据库实例需要稳定运行,所以并没有直接将数据恢复到 /var/lib/mysql
目录,而是在 mysql-files
目录进行解压缩处理。
为了能够正确导出数据,我们需要让数据库实例能够读取我们恢复的数据,所以我们将解压缩后的数据对数据库实例数据进行完整的覆盖。
cp -r /var/lib/mysql-files/* /var/lib/mysql/
rm -rf /var/lib/mysql-files/*
在执行过后,我们切换到容器外面,执行 docker-compose down && docker-compose up -d
删除掉之前的容器,并重新创建一个干净的新容器,来继续进行数据恢复。使用 docker exec -it
再次进入容器:
docker exec -it percona bash
使用默认的用户名进入 MySQL 交互终端中:
mysql -u xtrabackup
尝试列举一下当前能够读取的数据库:
mysql> show databases;
+--------------------+
| Database |
+--------------------+
| information_schema |
| YOUR_DATABASE |
| mysql |
| performance_schema |
| sys |
+--------------------+
5 rows in set (0.01 sec)
会发现云端的 MySQL 数据库已经被正确的还原在了本地。
然而,如果你尝试使用 mysqldump
直接进行数据导出的话,可能会收到 “PXC” 报错。
mysqldump: Got error: 1105: Percona-XtraDB-Cluster prohibits use of LOCK TABLE/FLUSH TABLE WITH READ LOCK/FOR EXPORT with pxc_strict_mode = ENFORCING when using LOCK TABLES
为了解决这个文件,我们需要在 MySQL 交互终端里进行全局设置:
mysql> set global pxc_strict_mode=DISABLED ;
Query OK, 0 rows affected (0.00 sec)
接着再进行数据库导出便不会再出现问题了:
mysqldump -u xtrabackup YOUR_DATABASE > backup.sql
因为我们导出的是标准的数据库备份,所以继续进行迁移也很简单,可以使用诸如:
mysql -u USER -p DATABSE_NAME < backup.sql
或者 file load
的方式快速进行数据库恢复重建。
最后
对于工程师而言,懒惰是美德,但是懒惰成立的前提是你能够正确的、简单的定位和解决问题,共勉。
作者:苏洋