前言
一、备份方案概述
二、最终备份脚本
三、遇到的问题与解决方案
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 ]; then echo "[`date`] 开始全量备份..." FULL_FILE=$FULL_DIR/all_$DATE.sql mysqldump -u$MYSQL_USER -p$MYSQL_PASS --all-databases --single-transaction --flush-logs > $FULL_FILE if [ $? -eq 0 ]; then echo "[`date`] 全量备份完成:$FULL_FILE" else echo "[`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" ]; then cp $PREV_BINLOG $INCR_DIR/$(basename $PREV_BINLOG).$DATE if [ $? -eq 0 ]; then echo "[`date`] 增量备份完成:$INCR_DIR/$(basename $PREV_BINLOG).$DATE" else echo "[`date`] 增量备份失败!" fi
else echo "[`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 ]; then echo "[`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 ]; then echo "[`date`] 全量备份完成:$FULL_FILE"
else echo "[`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" ]; then cp $PREV_BINLOG $INCR_DIR/$(basename $PREV_BINLOG).$DATE
-f
:判断文件是否存在且为普通文件。basename $PREV_BINLOG
:获取文件名(去掉路径),避免复制时路径问题。cp ... $INCR_DIR/....$DATE
:复制 binlog 到增量目录,并加日期后缀。
if [ $? -eq 0 ]; then echo "[`date`] 增量备份完成:$INCR_DIR/$(basename $PREV_BINLOG).$DATE"
else echo "[`date`] 增量备份失败!"
fi
判断复制是否成功,输出结果。
else echo "[`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`] 备份任务完成"
输出最终备份完成的提示。