嗟乎!
一、概述
mysql数据库该怎么备份呢?
数据库备份有几个概念:全量备份、增量备份、差异备份。当然啦,数据库备份又有冷备份和热备份,即物理备份和逻辑备份之分。冷备份就是将mysql停了,然后直接拷贝它的数据文件,简单粗暴。问题是,数据库怎可轻易停止或重启?所以我们通常说的备份都是指热备份,即逻辑备份。逻辑备份包括全量备份、增量备份、差异备份。
全量备份就是整个库备份。增量备份是将上一次全量备份或增量备份后的变化备份。差异备份是将上次全量备份后的变化备份。所以增量备份和差异备份有重叠。由于mysql中,并不直接支持所谓增量备份或差异备份,所谓的加过滤条件简直就是瞎掰,根本不属于自动备份的概念,毫无意义。mysql只能通过拷贝二进制日志文件(BinLog)来实现增量备份的效果,聊胜于无。BinLog里面,记录了对mysql的增删改,而没有记录查,所以重新执行这个BinLog就可以达到增量备份的效果。有关BinLog,可以参考拙作(mysql的日志文件)
二、备份思路
将备份命令写到批处理文件,然后定期运行它们。windows的可以用操作系统的任务计划来定期执行批处理;linux可以设置定时器crontab。
另外,备份文件一般比较大,为长久计,备份之后,应将备份文件压缩。
三、windows
1、全量备份
bash
@echo off
rem 设置 MySQL 用户名和密码
set MYSQL_USER=数据库账号
set MYSQL_PASSWORD=密码
set DATABASE=待备份的数据库名称
rem mysql数据文件路径。一般在mysql安装路径,可在mysql.ini里设置。
set MYSQL_BIN=e:\mysql\data\
rem 设置备份文件路径
set BACKUP_PATH=C:\temp\backup
rem 获取当前时间戳作为备份文件名
for /f "delims=" %%a in ('powershell -command "Get-Date -Format 'yyyyMMdd_HHmmss'"') do set TIMESTAMP=%%a
set FULL_BACKUP_FILE=%BACKUP_PATH%\full_backup_%TIMESTAMP%.sql
set COMPRESSED_FULL_BACKUP_FILE=%FULL_BACKUP_FILE%.zip
rem 检查是否已存在该时刻的备份文件,如果存在则不备份
if not exist %COMPRESSED_FULL_BACKUP_FILE% (
rem 执行全量备份
mysqldump -u%MYSQL_USER% -p%MYSQL_PASSWORD% %DATABASE% --single-transaction --routines --triggers > %FULL_BACKUP_FILE%
echo Full Backup completed: %FULL_BACKUP_FILE%
rem 压缩备份文件。这里使用360zip
360zip -ar %FULL_BACKUP_FILE% %COMPRESSED_FULL_BACKUP_FILE%
rem 删除备份文件
del %FULL_BACKUP_FILE%
) else (
echo Full Backup file already exists: %COMPRESSED_FULL_BACKUP_FILE%
)
2、增量备份
bash
rem 设置 MySQL 用户名和密码
set MYSQL_USER=数据库账号
set MYSQL_PASSWORD=密码
set DATABASE=待备份的数据库名称
rem mysql数据文件路径。一般在mysql安装路径,可在mysql.ini里设置。
set MYSQL_BIN=e:\mysql\data\
rem 设置备份文件路径
set BACKUP_PATH=C:\temp\backup
rem 获取当前时间戳作为备份文件名
for /f "delims=" %%a in ('powershell -command "Get-Date -Format 'yyyyMMdd_HHmmss'"') do set TIMESTAMP=%%a
rem 生成的备份文件名称
set BINLOG_FILE=%BACKUP_PATH%\mysql-bin.%TIMESTAMP%
rem 压缩后的备份文件名称
set COMPRESSED_BINLOG_FILE=%BINLOG_FILE%.zip
rem 增量备份对应的position
set BINLOG_POSITION_FILE=%BACKUP_PATH%\binlog_position.txt
rem 检查是否已存在该时刻的二进制日志文件,如果存在则不备份
if not exist %COMPRESSED_BINLOG_FILE% (
rem 获取当前二进制日志文件名和位置
for /f "tokens=1,2" %%i in ('mysql -u%MYSQL_USER% -p%MYSQL_PASSWORD% -e "SHOW MASTER STATUS" ^| find " " /v') do (
set CURRENT_BINLOG_FILE=%%i
set CURRENT_BINLOG_POSITION=%%j
)
rem 拷贝二进制日志文件到备份目录
copy /Y %MYSQL_BIN%%CURRENT_BINLOG_FILE% %BINLOG_FILE%
rem 压缩
360zip -ar %BINLOG_FILE% %COMPRESSED_BINLOG_FILE%
rem 删除备份文件
del %BINLOG_FILE%
rem 将二进制日志信息保存到文件,增量备份恢复时使用
echo %COMPRESSED_BINLOG_FILE% %BINLOG_POSITION% > %BINLOG_POSITION_FILE%
) else (
echo Compressed Binary log file already exists: %COMPRESSED_BINLOG_FILE%
)
四、linux
1、全量备份
bash
#!/bin/bash
# 设置 MySQL 用户名和密码
MYSQL_USER=数据库账号
MYSQL_PASSWORD=密码
DATABASE=待备份的数据库名称
MYSQL_PORT=mysql端口
MYSQL_HOST=mysqlIP地址
# 设置备份文件路径
BACKUP_PATH="/home/admin/db-backup/files"
# 获取当前时间戳作为备份文件名
TIMESTAMP=$(date +"%Y%m%d_%H%M%S")
# 备份文件名
FULL_BACKUP_FILE="$BACKUP_PATH/full_backup_$TIMESTAMP.sql"
# 检查是否已存在备份文件,如果存在则不再创建
if [ ! -f "$FULL_BACKUP_FILE" ]; then
# 执行全量备份
mysqldump -h"$MYSQL_HOST" -P"$MYSQL_PORT" -u"$MYSQL_USER" -p"$MYSQL_PASSWORD" "$DATABASE" --single-transaction --routines --triggers > "$FULL_BACKUP_FILE"
# 压缩全量备份文件
gzip "$FULL_BACKUP_FILE"
echo "Full Backup completed: $FULL_BACKUP_FILE"
else
echo "Full Backup file already exists: $FULL_BACKUP_FILE"
fi
2、增量备份
获取当前二进制日志文件名和位置的时候,要使用mysql命令。由于该命令在bash文件中执行,可能系统会找不到mysql,提示未知命令,所以要指定mysql路径。如果不清楚mysql安装在什么地方,可以敲入:
bash
which mysql
这样可以得到mysql所在路径,如:/usr/local/mysql/mysql-8.0/bin/mysql,
然后据此修改bash文件。
bash
#!/bin/bash
# 设置 MySQL 用户名和密码
MYSQL_USER=数据库账号
MYSQL_PASSWORD=密码
DATABASE=待备份的数据库名称
MYSQL_PORT=mysql端口
MYSQL_HOST=mysqlIP地址
# MySQL 数据文件路径
MYSQL_BIN="/home/admin/mysql/data/"
# 设置备份文件路径
BACKUP_PATH="/home/admin/db-backup/files"
# 获取当前时间戳作为备份文件名
TIMESTAMP=$(date +"%Y%m%d_%H%M%S")
BINLOG_FILE="$BACKUP_PATH/mysql-bin.$TIMESTAMP"
COMPRESSED_BINLOG_FILE="$BINLOG_FILE.gz"
BINLOG_POSITION_FILE="$BACKUP_PATH/binlog_position.txt"
# 检查是否已存在二进制日志文件,如果存在则不再创建
if [ ! -f "$COMPRESSED_BINLOG_FILE" ]; then
# 获取当前二进制日志文件名和位置
read -r CURRENT_BINLOG_FILE CURRENT_BINLOG_POSITION <<<$(/usr/local/mysql/mysql-8.0/bin/mysql -h"$MYSQL_HOST" -P"$MYSQL_PORT" -u"$MYSQL_USER" -p"$MYSQL_PASSWORD" -e "SHOW MASTER STATUS" | awk 'NR==2{print $1, $2}')
# 拷贝并压缩二进制日志文件到备份目录
cp "$MYSQL_BIN$CURRENT_BINLOG_FILE" "$BINLOG_FILE"
gzip "$BINLOG_FILE"
# 将二进制日志信息保存到文件,以备增量备份时使用
echo "$COMPRESSED_BINLOG_FILE $BINLOG_POSITION" > "$BINLOG_POSITION_FILE"
else
echo "Compressed Binary log file already exists: $COMPRESSED_BINLOG_FILE"
fi
3、定时执行
1)首先将shell文件赋权为可执行文件。这一步好像不是必要的。
bash
chmod 777 backup.sh
2)切换为超级管理员
bash
su
3)设置定时器
输入命令
bash
crontab -e
在打开的界面中输入
bash
0 3 * * 6 sh /home/admin/db-backup/backup.sh
意思是每周六凌晨3点执行。
五、小结
mysql并不天然支持增量备份,这是我没想到的。之前sql server不论是全量、差异备份,都有直接的命令,可以交替执行。mysql吹得天上有,地上无,感觉有些基本的配套功能都没有。另外,mysql应该是国内最流行的数据库了,按说相关教程、方案都非常完备了,稍微搜一下,资料就会一大把,但事实上好像并非如此。尤其这个差异备份、增量备份,我还真没看到多少。这里面,原因可能是多方面的,一是mysql多用于互联网,互联网的特点就是迭代快,赶工厉害,很少有时间停下来总结一下。二是国内互联网日益封闭,质量越来越差,搜索引擎都没什么好搜的,也搜不到什么有价值的东西。如果不是chatGPT的指导,还真不容易写出上面的批处理。