MySQL 全量 + 增量备份脚本(RPM 安装)实践与问题解析
前言
一、备份方案概述
二、最终备份脚本
三、遇到的问题与解决方案
1. 增量备份只备份了 mysql-bin.index
2. 增量备份为空或不完整
3. 新增 binlog 文件数量增加
4. crontab 日志记录
四、总结
五、附录
rpm安装mysql步骤
1.下载RPM以及依赖包
2.下载MYSQL所需的依赖包
3.安装RPM包
4.启动mysql
5.修改初始密码
6.修改配置文件
7.修改密码
8.测试登录
六、脚本参数详解
脚本逐行解析
配置区
创建备份目录
全量备份(每周日执行)
增量备份(每天执行)
自动删除过期备份
脚本结束
前言
在实际生产环境中,数据库备份是保障数据安全的重要环节。本文总结了基于 RPM 安装的 MySQL 5.7 的全量 + 增量备份方案,结合遇到的问题和解决方法,为大家提供一个完整参考。
一、备份方案概述
-
全量备份:每周日使用
mysqldump
备份所有数据库到 SQL 文件 -
增量备份:每天基于 MySQL 二进制日志(binlog) 进行备份
-
自动清理:保留最近 7 天的备份文件
-
目录结构:
/var/lib/mysql/mysql_backup/ ├── full/ # 全量备份目录 └── increment/ # 增量备份目录
二、最终备份脚本
#!/bin/bash # MySQL 全量+增量备份脚本 # 配置区 BACKUP_ROOT=/var/lib/mysql/mysql_backup FULL_DIR=$BACKUP_ROOT/full INCR_DIR=$BACKUP_ROOT/increment MYSQL_USER=root MYSQL_PASS='123456' DATE=$(date +%F) WEEKDAY=$(date +%u) BINLOG_DIR=/var/lib/mysql RETENTION_DAYS=7 # 创建备份目录 mkdir -p $FULL_DIR mkdir -p $INCR_DIR # 每周日执行全量备份 if [ "$WEEKDAY" -eq 7 ]; thenecho "[`date`] 开始全量备份..."FULL_FILE=$FULL_DIR/all_$DATE.sqlmysqldump -u$MYSQL_USER -p$MYSQL_PASS --all-databases --single-transaction --flush-logs > $FULL_FILEif [ $? -eq 0 ]; thenecho "[`date`] 全量备份完成:$FULL_FILE"elseecho "[`date`] 全量备份失败!"fi fi # 每日增量备份(基于 binlog) echo "[`date`] 开始增量备份..." mysql -u$MYSQL_USER -p$MYSQL_PASS -e "FLUSH LOGS;" # 获取倒数第二个完整 binlog 文件 PREV_BINLOG=$(ls -tr $BINLOG_DIR/mysql-bin.[0-9]* | tail -2 | head -1) if [ -f "$PREV_BINLOG" ]; thencp $PREV_BINLOG $INCR_DIR/$(basename $PREV_BINLOG).$DATEif [ $? -eq 0 ]; thenecho "[`date`] 增量备份完成:$INCR_DIR/$(basename $PREV_BINLOG).$DATE"elseecho "[`date`] 增量备份失败!"fi elseecho "[`date`] 没找到可用的 binlog 文件" fi # 自动删除 7 天前备份 echo "[`date`] 开始清理7天前的备份..." find $FULL_DIR -type f -mtime +$RETENTION_DAYS -name "*.sql" -exec rm -f {} \; find $INCR_DIR -type f -mtime +$RETENTION_DAYS -name "mysql-bin.*" -exec rm -f {} \; echo "[`date`] 清理完成" echo "[`date`] 备份任务完成"
测试截图
三、遇到的问题与解决方案
1. 增量备份只备份了 mysql-bin.index
现象:执行脚本后,增量备份目录中出现了 mysql-bin.index.日期
文件,而不是实际的 binlog 文件(如 mysql-bin.000002
)。
原因:
-
原脚本中使用了:
PREV_BINLOG=$(ls -tr $BINLOG_DIR/mysql-bin.* | tail -2 | head -1)
-
mysql-bin.*
会匹配所有文件,包括.index
文件 -
如果目录中有
mysql-bin.index
,shell 排序可能取到了索引文件,导致备份文件不包含实际事务数据
解决方案:
PREV_BINLOG=$(ls -tr $BINLOG_DIR/mysql-bin.[0-9]* | tail -2 | head -1)
-
使用
mysql-bin.[0-9]*
只匹配数字序号文件 -
排除索引文件,保证增量备份内容完整
2. 增量备份为空或不完整
现象:新生成的 binlog 文件可能正在写入,直接备份会导致空或未完成事务。
原因:
-
脚本使用
SHOW MASTER STATUS
获取当前 binlog 文件 -
当前文件可能刚生成,还未写入任何事务
解决方案:
-
备份倒数第二个文件,而不是最新文件:
PREV_BINLOG=$(ls -tr $BINLOG_DIR/mysql-bin.[0-9]* | tail -2 | head -1)
-
最新文件仍在写入,倒数第二个文件已经完成,可以安全备份
3. 新增 binlog 文件数量增加
现象:每次执行 FLUSH LOGS;
后,binlog 文件会生成新的序号,如 mysql-bin.000002
。
原因:
-
MySQL
FLUSH LOGS;
会滚动当前 binlog,生成新的文件 -
是 MySQL 的标准行为,不是脚本错误
注意:
-
每次增量备份都应复制倒数第二个文件
-
保证备份完整、不会备份正在写入的文件
4. crontab 日志记录
-
脚本可以加入定时任务:
0 1 * * * /bin/bash /var/lib/mysql/mysql_backup/mysql_backup.sh >> /var/log/mysql_backup.log 2>&1
-
注意:
/var/log/mysql_backup.log
路径不存在时,>>
会自动创建文件,但父目录必须存在
四、总结
-
全量备份使用
mysqldump
每周一次 -
增量备份基于 binlog,注意只备份已完成的 binlog 文件
-
清理机制保证备份目录不无限膨胀
-
脚本问题排查要点:
-
增量备份误备份索引文件 → 用数字匹配避免
-
空增量备份 → 复制倒数第二个文件
-
binlog 文件不断增加 → FLUSH LOGS 导致,正常
日志管理:
-
全量备份使用
.sql
文件 -
增量备份使用
mysql-bin
文件 -
自动保留 7 天备份
脚本中常用参数:
-
ls -tr
:按时间排序文件 -
basename
:去掉路径,只取文件名 -
[ -f "$file" ]
:判断普通文件是否存在 -
$?
:判断上一条命令是否成功
通过这套方案,可以在 MySQL RPM 安装环境下实现 安全、稳定、可自动化的全量 + 增量备份。
五、附录
rpm安装mysql步骤
1.下载RPM以及依赖包
# 下载 MySQL 5.7 的 YUM 仓库配置包 wget https://dev.mysql.com/get/mysql57-community-release-el7-11.noarch.rpm # 安装 repo 配置包 sudo rpm -ivh mysql57-community-release-el7-11.noarch.rpm
2.下载MYSQL所需的依赖包
cd /opt mkdir mysql5720_rpms #--resolve 自动下载依赖,--destdir 指定保存目录 yumdownloader --resolve --destdir=/opt/mysql5720_rpms mysql-community-server-5.7.20
3.安装RPM包
cd /opt/mysql5720_rpms yum localinstall -y *.rpm
4.启动mysql
systemctl start mysqld
5.修改初始密码
mysql -uroot -p$(grep "password" /var/log/mysqld.log | awk '{print $NF}') --connect-expired-password -e "ALTER USER 'root'@'localhost' IDENTIFIED BY 'Admin@123';"
6.修改配置文件
vim /etc/my.cnf [mysqld] # join_buffer_size = 128M # sort_buffer_size = 2M # read_rnd_buffer_size = 2M datadir=/var/lib/mysql socket=/var/lib/mysql/mysql.sock symbolic-links=0 port = 3306 bind-address = 0.0.0.0 default-storage-engine=INNODB character-set-server=utf8 log-error=/var/log/mysqld.log pid-file=/var/run/mysqld/mysqld.pid validate_password_policy=LOW # 降低强度策略(仅检查长度) validate_password_length=6 # 最小密码长度设为6位 #log-bin=mysql-bin (可选:开启二进制日志) #binlog_format=MIXED (可选:指定二进制日志的记录格式) server-id=1 systemctl restart mysqld
7.修改密码
mysql -uroot -pAdmin@123 -e "ALTER USER 'root'@'localhost' IDENTIFIED BY '123456';"
8.测试登录
mysql -uroot -p123456
六、脚本参数详解
脚本逐行解析
#!/bin/bash
-
指定脚本解释器为
bash
,保证脚本在 Linux 系统下用 Bash 执行。
配置区
BACKUP_ROOT=/var/lib/mysql/mysql_backup
-
备份根目录,所有备份文件都存放在这里。
FULL_DIR=$BACKUP_ROOT/full INCR_DIR=$BACKUP_ROOT/increment
-
全量备份目录和增量备份目录,便于分类管理备份。
MYSQL_USER=root MYSQL_PASS='123456'
-
MySQL 登录用户名和密码,用于执行
mysqldump
和mysql
命令。 -
注意:命令行中使用密码会有安全提示,可使用
.my.cnf
文件避免明文密码。
DATE=$(date +%F)
-
获取当前日期,格式为
YYYY-MM-DD
,用于给备份文件命名。 -
示例:
2025-10-01
WEEKDAY=$(date +%u)
-
获取当前星期几,1 = 星期一,7 = 星期日。用于判断是否执行全量备份。
BINLOG_DIR=/var/lib/mysql
-
MySQL 二进制日志目录(RPM 安装默认
/var/lib/mysql
),用于增量备份。
RETENTION_DAYS=7
-
自动清理多少天前的备份文件,这里设置为 7 天。
创建备份目录
mkdir -p $FULL_DIR mkdir -p $INCR_DIR
-
-p
参数表示递归创建目录,如果目录已存在不会报错。 -
保证备份目录存在,避免
cp
或mysqldump
写入失败。
全量备份(每周日执行)
if [ "$WEEKDAY" -eq 7 ]; thenecho "[`date`] 开始全量备份..."FULL_FILE=$FULL_DIR/all_$DATE.sql
-
判断今天是否是星期日,如果是则执行全量备份。
-
全量备份文件命名为
all_YYYY-MM-DD.sql
。
mysqldump -u$MYSQL_USER -p$MYSQL_PASS --all-databases --single-transaction --flush-logs > $FULL_FILE
-
mysqldump
:MySQL 官方备份工具。 -
参数解释:
-
-u$MYSQL_USER
:登录用户名。 -
-p$MYSQL_PASS
:登录密码。 -
--all-databases
:备份所有数据库。 -
--single-transaction
:对 InnoDB 表启用一致性快照,避免锁表。 -
--flush-logs
:备份时刷新日志,生成新的二进制日志文件,便于增量备份。
-
-
> $FULL_FILE
:将输出保存到全量备份文件。
if [ $? -eq 0 ]; thenecho "[`date`] 全量备份完成:$FULL_FILE" elseecho "[`date`] 全量备份失败!" fi
-
$?
表示上一条命令执行状态码:-
0
表示成功 -
非 0 表示失败
-
-
根据状态输出备份结果。
增量备份(每天执行)
echo "[`date`] 开始增量备份..." mysql -u$MYSQL_USER -p$MYSQL_PASS -e "FLUSH LOGS;"
-
每次增量备份前执行
FLUSH LOGS;
:-
MySQL 生成一个新的二进制日志文件(如
mysql-bin.000003
)。 -
保证增量备份文件完整。
-
PREV_BINLOG=$(ls -tr $BINLOG_DIR/mysql-bin.[0-9]* | tail -2 | head -1)
-
获取最新两个 binlog 文件中倒数第二个(完整的上一个 binlog)。
-
参数解释:
-
ls -tr
:-
-t
:按修改时间排序(最新的在前) -
-r
:反转顺序(最旧在前)
-
-
$BINLOG_DIR/mysql-bin.[0-9]*
:匹配所有数字编号的 binlog 文件。 -
tail -2 | head -1
:取倒数第二个文件(上一次的 binlog,用于增量备份)。
-
if [ -f "$PREV_BINLOG" ]; thencp $PREV_BINLOG $INCR_DIR/$(basename $PREV_BINLOG).$DATE
-
-f
:判断文件是否存在且为普通文件。 -
basename $PREV_BINLOG
:获取文件名(去掉路径),避免复制时路径问题。 -
cp ... $INCR_DIR/....$DATE
:复制 binlog 到增量目录,并加日期后缀。
if [ $? -eq 0 ]; thenecho "[`date`] 增量备份完成:$INCR_DIR/$(basename $PREV_BINLOG).$DATE" elseecho "[`date`] 增量备份失败!" fi
-
判断复制是否成功,输出结果。
elseecho "[`date`] 没找到可用的 binlog 文件" fi
-
如果
$PREV_BINLOG
不存在,则输出警告。
自动删除过期备份
echo "[`date`] 开始清理7天前的备份..." find $FULL_DIR -type f -mtime +$RETENTION_DAYS -name "*.sql" -exec rm -f {} \; find $INCR_DIR -type f -mtime +$RETENTION_DAYS -name "mysql-bin.*" -exec rm -f {} \;
-
find
:查找符合条件的文件并删除。 -
参数解释:
-
$FULL_DIR
/$INCR_DIR
:查找路径。 -
-type f
:只查找普通文件。 -
-mtime +$RETENTION_DAYS
:修改时间超过$RETENTION_DAYS
天。 -
-name "*.sql"
/"mysql-bin.*"
:匹配文件名。 -
-exec rm -f {} \;
:删除匹配文件。
-
echo "[`date`] 清理完成"
-
输出清理完成信息。
脚本结束
echo "[`date`] 备份任务完成"
-
输出最终备份完成的提示。