在国内不论是使用阿里云、腾讯云还是华为云的云平台版本的 MySQL 数据库,在遇到数据备份恢复的场景,都会遇到需要使用 Percona XtraBackup 工具进行备份还原的需求。

看着网上一堆既啰嗦又落后的备份恢复方案,不免厌烦,借着再次帮朋友做数据迁移的机会,整理分享之前的实战笔记,希望能够帮助到有需求的同学。

写在前面

国内云平台从业者不多,加上成熟的方案相对固定,所以我们不难看到“御三家”的产品备份恢复策略甚至文档都非常“相似”。

本文将基于容器工具的方式进行数据恢复处理,避免折腾不必要的软件依赖。

编写数据库恢复实例配置文件

容器时代,如果你不是容器环境的运维工作者,不必过度纠结系统配置,我们直接使用 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 格式,容器内置了 qpressxbstream 工具,参考你的云平台提供的说明文档直接使用就是了。

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 <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 的方式快速进行数据库恢复重建。

最后

对于工程师而言,懒惰是美德,但是懒惰成立的前提是你能够正确的、简单的定位和解决问题,共勉。

–EOF