本文使用「署名 4.0 国际 (CC BY 4.0)」许可协议,欢迎转载、或重新修改使用,但需要注明来源。 [署名 4.0 国际 (CC BY 4.0)](https://creativecommons.org/licenses/by/4.0/deed.zh) 本文作者: 苏洋 创建时间: 2021年10月13日 统计字数: 4398字 阅读时间: 9分钟阅读 本文链接: https://soulteary.com/2021/10/13/mysql-cloud-database-physical-backup-local-recovery-solution.html ----- # MySQL 云数据库物理备份本地恢复方案 在国内不论是使用阿里云、腾讯云还是华为云的云平台版本的 MySQL 数据库,在遇到数据备份恢复的场景,都会遇到需要使用 Percona XtraBackup 工具进行备份还原的需求。 看着网上一堆既啰嗦又落后的备份恢复方案,不免厌烦,借着再次帮朋友做数据迁移的机会,整理分享之前的实战笔记,希望能够帮助到有需求的同学。 ## 写在前面 国内云平台从业者不多,加上成熟的方案相对固定,所以我们不难看到“御三家”的产品备份恢复策略甚至文档都非常“相似”。 - 阿里云:[《RDS MySQL物理备份文件恢复到自建数据库》](https://help.aliyun.com/knowledge_detail/41817.html) - 腾讯云: [《云数据库 MySQL - 使用物理备份恢复数据库》](https://cloud.tencent.com/document/product/236/33363) - 华为云:[《通过备份文件恢复到自建数据库(MySQL)》](https://support.huaweicloud.com/usermanual-rds/rds_08_0044.html) 本文将基于容器工具的方式进行数据恢复处理,避免折腾不必要的软件依赖。 ## 编写数据库恢复实例配置文件 容器时代,如果你不是容器环境的运维工作者,不必过度纠结系统配置,我们直接使用 Percona 官方提供的镜像即可,下面以 MySQL 5.7 为例,你可以根据自己的需求自行修改版本号。 ```yaml # 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`,稍后使用。 接着,编写一个可以用于还原的数据库配置文件: ```yaml [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` 将用于数据还原的数据库实例启动起来。 ```yaml ... 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` 命令直接向容器复制,不过对于大文件来说,体验并不友好。 ### 数据“解压缩” 在准备好数据备份文件之后,我们进入容器进行后续操作: ```bash docker exec -it percona bash ``` 进入容器之后,先切换工作目录: ```bash cd /var/lib/mysql-files/ ``` 假设我们的备份文件格式为 `tar` 格式的存储文件,需要先进行解压缩。如果是其他格式,比如 `.xb` 格式,容器内置了 `qpress` 和 `xbstream` 工具,参考你的云平台提供的说明文档直接使用就是了。 ```bash tar zxvf *.tar ``` 在备份文件解压缩之后,我们就可以正式开始进行数据恢复操作了。 ```bash innobackupex --defaults-file=/etc/mysql/node.cnf --apply-log /var/lib/mysql-files/ ``` 数据恢复时间,根据你的备份文件大小而定。 ```bash 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` 目录进行解压缩处理。 为了能够正确导出数据,我们需要让数据库实例能够读取我们恢复的数据,所以我们将解压缩后的数据对数据库实例数据进行完整的覆盖。 ```bash 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` 再次进入容器: ```bash docker exec -it percona bash ``` 使用默认的用户名进入 MySQL 交互终端中: ```bash mysql -u xtrabackup ``` 尝试列举一下当前能够读取的数据库: ```bash mysql> show databases; +--------------------+ | Database | +--------------------+ | information_schema | | YOUR_DATABASE | | mysql | | performance_schema | | sys | +--------------------+ 5 rows in set (0.01 sec) ``` 会发现云端的 MySQL 数据库已经被正确的还原在了本地。 然而,如果你尝试使用 `mysqldump` 直接进行数据导出的话,可能会收到 “PXC” 报错。 ```bash 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 交互终端里进行全局设置: ```bash mysql> set global pxc_strict_mode=DISABLED ; Query OK, 0 rows affected (0.00 sec) ``` 接着再进行数据库导出便不会再出现问题了: ```bash mysqldump -u xtrabackup YOUR_DATABASE > backup.sql ``` 因为我们导出的是标准的数据库备份,所以继续进行迁移也很简单,可以使用诸如: ```bash mysql -u USER -p DATABSE_NAME < backup.sql ``` 或者 `file load` 的方式快速进行数据库恢复重建。 ## 最后 对于工程师而言,懒惰是美德,但是懒惰成立的前提是你能够正确的、简单的定位和解决问题,共勉。 --EOF