阿里云RDS mysql8数据本地恢复,与本地主从同步(容器中)
背景
线上业务的数据库采用RDS,可以将运维,可用性,监控等一些繁琐的工作交给云服务商来做。
但是对于一些内部的业务可能又不想占用线上的RDS资源,或者低成本的异地灾备,这时可以选择本地冗余的资源。
方案
这里有多种方案可以选择
- DTS(数据传输服务): 操作简单,需要承担一定的费用;
- 数据订阅(日志订阅): 操作简单,需要接入SDK, 也需要一定的费用;
- Canal: 类似上面的日志订阅,自建订阅服务,然后可以用于多处消费;
- 主从:本地运行一个从实例,链接到RDS主实例,缺点就是一份数据仅从实例消费了,不能直接用于其他的服务,如es, kafka等;
本文选用的方案4
因为本地运行有mariadb, 此时直接在装一个mysql,会有不少问题需要处理,毕竟前者是后者的某个版本(5还是多少)上分化 出来的,虽然独立演化,但仍旧有很多相同之处,不如系统服务管理,sock文件路径等。为了避免这些问题,因此使用容器单独运行一个mysql服务,作为RDS的从实例。
环境准备
-
docker 安装这里就略过了,安装时可能会遇到一些问题,可以参考这个公众号文章: 国内如何安装docker? docker安装源,gpg key, 镜像源如何突破访问限制?。
-
因为本地使用的ECS, 下载mysql镜像时可能会遇到问题,可以参考这里的文章:docker 打包离线镜像,使用离线镜像, 使用代理下载镜像
说明,本文使用的mysql:8.x.x容器,最好不要低于RDS的版本,测试发现使用了几个比RDS版本新的都可以正常工作。 -
工具安装
RDS备份使用的XtraBackup, qpress 因此恢复也需要此工具。可以参考阿里云文档: RDS MySQL物理备份文件恢复到自建数据库
-
3.1: 按照文档工具安装(mysql8容器不推荐)
直接按照文档来,qpress没问题,但是xtrabackup虽然安装没问题,但是使用时会报一些动态库缺失的问题。
这里需要说明的是,文档提供的是linux6,linux7环境下的安装方案,但是oracle 的mysyql:8xx容器却是linux4内核的基础上构建的,因此会缺少不少动态库(印象中是4,5个吧),需要解决动态库的安装,安装后可以正常使用。
这是测试时,某个版本的mysql容器信息。
uname -a
Linux 841c775cba5d 4.19.0-21-amd64cat /etc/os-release
NAME="Oracle Linux Server"
VERSION="9.6"
ID="ol"
ID_LIKE="fedora"
VARIANT="Server"
VARIANT_ID="server"
VERSION_ID="9.6"
PLATFORM_ID="platform:el9"
PRETTY_NAME="Oracle Linux Server 9.6"
ANSI_COLOR="0;31"
CPE_NAME="cpe:/o:oracle:linux:9:6:server"
HOME_URL="https://linux.oracle.com/"
BUG_REPORT_URL="https://github.com/oracle/oracle-linux"
这是按文档安装后直接执行命令时报的动态库问题
#/u01/xtrabackup80/bin/xtrabackup --decompress --remove-original --target-dir=/var/mysql_bkdata/
# 这里按阿里云文档,上面的指令会报动态库不存在问题,可能与前面的安装有关, 毕竟容器内核与文档相差比较大
error while loading shared libraries: libnuma.so.1: cannot open shared object file# 可以采用类似下面的方案解决:
# microdnf update
# microdnf install yum
# yum -y install numactl.x86_64# 类似的还有几个其他的动态库,大概的流程就是搜索,然后根据环境安装,全部安装完成也是可以的,已验证。这里只是示例,详细流程忘记记录了,流程太繁琐,不想再走一遍来记录了。
# yum provides */libgcrypt.so.11 # 查找哪个包提供这个库
# yum install -y libgcrypt # 或者安装它提示的特定包名
- 3.2 使用容器的包管理工具安装
这里直接使用容器中的microdnf包管理工具来安装xtrabackup,
microdnf update
#这里使用dnf安装:
microdnf install dnf
# 1. 安装 Percona 发布包
dnf install https://repo.percona.com/yum/percona-release-latest.noarch.rpm
# 2. 启用工具仓库
percona-release enable tools release
# 3. 安装 XtraBackup
dnf install percona-xtrabackup-80
# 或者安装最新版本
dnf install percona-xtrabackup-84# 安装qpress
dnf install qpress
- 3.3 docker 使用技巧
安装工具前后,容器的大小发生了很大的变化,但是运行服务的容器并不需要这些工具,因此可以把这个容器保存为工具镜像,用户数据的恢复。可以看到安装工具前后镜像的大小变化:573M -> 2.18GB
# 保存为镜像 hash为运行的容器的hash
docker commit 7c167f053509 mysql-with-xtrabackup:8.0.xx
# 查看镜像大小
docker images | grep mysql
mysql-with-xtrabackup 8.0.xx 27de73804e0b About a minute ago 2.18GB
mysql 8.0.xx f5da8fc4b539 14 months ago 573MB
恢复RDS备份到本地
解压备份文件
参考文档: RDS MySQL物理备份文件恢复到自建数据库使用工具curl, 或者wget下载备份到工具容器中,工具缺失的话可以直接安装就行,另外下载时可以加上限流参数,防止触发监控告警。
如果恢复数据后,还要配置主从的话,一定要下载最新的备份,最好重新生成一个备份下载,否则配置主从时,发现RDS已经purge了binlog, 前面的操作就浪费了,尤其数据大的时候很费时间的。细节可以参考下文
# 当然可以宿主机下载,映射到容器,或者cp到容器内就行。
microdnf install dnf
dnf install curl, wget, vim ......# 运行工具容器
# 这里挂在一个备份目录可数据目录到工具容器中, 数据目录存储的恢复的数据,后面可以脱离工具容器直接使用
docker run -it -v ./mysql_bkdata:/var/mysql_bkdata -v ./mysql_newdata:/var/lib/msyql mysql-with-xtrabackup:8.0.xx sh# 假设下载的文件为test_qb.xb , 注意不同文件后缀有不同的解压方法,参考阿里云文档,这里以_qb.xb示例:
## 步骤一:解包
cat test_qp.xb | xbstream -x -v -C /var/mysql_bkdata/
## 步骤二:解压
### MySQL 5.5/5.6/5.7
innobackupex --decompress --remove-original /var/mysql_bkdata/
### MySQL 8.0
# dnf 安装的xtrabackup
xtrabackup --decompress --remove-original --target-dir=/var/mysql_bkdata/
# 依照阿里云文档安装的
/u01/xtrabackup80/bin/xtrabackup --decompress --remove-original --target-dir=/var/mysql_bkdata/
恢复数据
- 恢复前准备
xtrabackup --defaults-file=/var/mysql_bkdata/backup-my.cnf --prepare --target-dir=/var/mysql_bkdata/
# 或
/u01/xtrabackup80/bin/xtrabackup --defaults-file=/var/mysql_bkdata/backup-my.cnf --prepare --target-dir=/var/mysql_bkdata/
2. 根据需要修改数据目录,因为上面直接映射到mysyql的默认数据目录/var/lib/mysql, 如果自己的不一样可以修改。
# /etc/my.cnf
datadir = /var/lib/mysql# 此外需要保证数据目录的权限,示例:
# chown -R mysql:mysql /var/lib/mysql
- 恢复数据
xtrabackup --defaults-file=/etc/my.cnf --copy-back --target-dir=/var/lib/mysql
# 或
/u01/xtrabackup80/bin/xtrabackup --defaults-file=/etc/my.cnf --copy-back --target-dir=/var/lib/mysql
至此数据已经恢复完,工具容器就可以不用了。下面就可以启动数据库,检查看看。如要在上面运行中的工具容器中的mysql来查看话,需要启动mysqld, 然后使用mysql 命令来查看(也可以使用下面的,直接运行一个mysyql容器来测试)。账号与rds中的账号一致。如果链接有问题,参考末尾常见问题部分。
- 启动数据库
因为上面已经恢复数据到宿主机的 ./msyql_newdata 中了,这时可以直接使用一个清爽的mysql官方容器来运行。
# 准备一份my.cnf,可以运行一个mysql容器,或者拷贝上面容器中的my.cnf
docker cp container_name:/etc/my.cnf ./
# 在my.cnf中加入:
#如果不是默认目录,需要修改
#datadir = /var/mysql_newdata
#(可选)在RDS MySQL管理控制台中查看实例参数lower_case_table_names的取值,如果取值为1,则需要修改自建数据库配置文件my.cnf。
#lower_case_table_names=1
# 运行容器
docker run --name rds-replicator -p 4407:3306 -v ./my.cnf:/etc/my.cnf -v ./mysql_newdata:/var/lib/msyql mysql:8.0.xx
# 进入容器查看
docker exec -it rds-replicator sh
mysql -u xxxxx -p
# 或者通过宿主机直接访问,需要宿主机上装有mysql
mysql -h xx.xx.xx.xx -P 4407 -u xxx -p # 一定要加上-h, 否侧 -P参数无效,至少我测试的时候是的
如果,不需要配置主从的话,到此已经结束了。
主从配置
在上面的my.cnf中加上如下配置,
# slave 配置
server-id=1234342 # 每个mysql的唯一标识,不能重复(与其他主从),可以使用show slave hosts查看
gtid-mode = ON
enforce-gtid-consistency = ON
relay-log = relay-log
read_only = ON
log-bin = mysql-bin
log-slave-updates = ON
重启容器使配置生效
docker restart rds-replicator
然后使用上面的方式,链接容器中的mysql(需要权限用户来配置主从)
首先查看binlog位置,xxxxxxx:1-20251851冒号前是示例的uuid, 后是transaction id范围,可能发现有多个(比如主备切换,就会有不同的主示例的,rds毕竟是高可用的,已包含主备的),第一列是已经执行的,第二列是purged, purged的范围一般小于等于第一列的,差集部分还主从复制还可以订阅到的,下面的示例只能订阅1xxxxxxx:19942438-20251851部分的,了解下可以排查下面的问题。
# rds主示例上查看当前binlog的位置,
select @@global.gtid_executed,@@global.gtid_purged;
@@global.gtid_executed @@global.gtid_purged
1xxxxxxx:1-20251851, 1xxxxxxx:1-19942438,
2xxxxxxx:1-349895606, 2xxxxxxx:1-349895606,
3xxxxxxx:1-218703687, 3xxxxxxx:1-218703687
查看恢复的容器示例中的binlog的位置,
cat mysql_bkdata/xtrabackup_slave_info
SET GLOBAL gtid_purged='1xxxxxxx:1-19776680,2xxxxxxx:1-349895606,3xxxxxxx:1-218703687';
CHANGE MASTER TO MASTER_AUTO_POSITION=1;
这里显示的是已经执行的transaction, 对比上面可以发现需要,1xxxxxxx:19776680- 之后的,可是主示例只有1xxxxxxx:19942438-20251851, 明显不满足。虽然查看rds配置,msyql 的参数 将binlog保留一个月,但是测试发现一天前的备份就不能用
不满足的话,重新下载最新的备份,否则,主从配置不会成功的,会报下面的错误。
这里是从库中看到的日志:
2025-xxxxxxx [ERROR] [MY-013114] [Repl] Replica I/O for channel '': Got fatal error1236 from source when reading data from binary log: 'Cannot replicate because the source purged required binary logs. Replicate the missing transactions from elsewhere, or provision a new replica from
backup. Consider increasing the source's binary log expiration period. The GTID sets and the missing
purged transactions are too long to print in this message. For more information, please see the sour$e's error log or the manual for GTID_SUBTRACT', Error_code: MY-013114
这里是源库上看到的日志,
2025-xxxxxxxxx 1362505 [Warning] [MY-011809] [Server] Cannot replicate to server with server_uuid='xxxxxx' because the present server has purged require
d binary logs. The connecting server needs to replicate the missing transactions from elsewhere, or be replaced by a new server created from a more recent backup. To prevent this error in the future,
consider increasing the binary log expiration period on the present server. The missing transactions are 'xxxxx:1-62416240, xxxxxx:1-249672
44, xxxxxx:1-58942982,xxxxx:1-129352'.
满足的话,才能继续下文。
权限用户链接从示例:
# 重置master信息,因为备份中含有master信息,因为rds是高可用配置,里面已有配置
RESET MASTER;
# 设置从库事务的执行位置,用于告知主库,然后主库就可以将新增的推到从库
# 位置信息从上面的xtrabackup_slave_info文件中查看
SET GLOBAL gtid_purged='1xxxxxxx:1-19776680,2xxxxxxx:1-349895606,3xxxxxxx:1-218703687';# 设置主库链接信息
CHANGE MASTER TOMASTER_HOST='your-rds-instance.rds.aliyuncs.com', -- 替换为你的RDS内网地址MASTER_USER='repl_user',MASTER_PASSWORD='YourStrongPassword123!', -- 替换为第一步设置的密码MASTER_PORT=3306,MASTER_AUTO_POSITION = 1; -- 启用GTID自动定位,这是最关键的一步# 重置复制信息,并启动slave
RESET SLAVE
START SLAVE# 查看slave复制状态
show slave status\G;
# 如有错误,根据日志排查
主实例上也可以看到多了一个slave:
show slave hosts;
常见问题
mysql 访问数据库时,提示 xxxx socket不存在
通常时mysqld没运行
文件不存在
查看文件是否存在,权限是否正确,比如mysql:mysql
链接时报不能访问
可以使用mysqld --skip-grant-tables 不校验用户权限方式启动数据库,直接使用mysql -u root 访问数据库,查看数据库数据是否正确。如mysql.user表中的用户是否存在等。
mysqld --defaults-file=/etc/my.cnf --user=mysql --datadir=/var/lib/mysql/newdata --skip-grant-tables &