0x00前言
好久没有写新文章同步了。一来最近项目很忙很少有时间,二来写文章好像也没有多少流量和可能的收益,个人动力也就有限了。
近些年来科技发展的很快,从最早的生成式图片到现在的生成式大模型,世界越来越变成了我想象不到的样子。从2023年openai的gpt3出现到目前的国产百花齐放,国外几只独秀,再到国内的deepseek独占鳌头风头一时无两。真的是时间瞬息万变慢慢的超过了我的进度。
国内的各种模型都有自己独到的特色,我尝试过自建GLM3-13B,他的在线生成代码效果让我感觉很是新奇。不过在长久的使用下我也是慢慢了了解了其局限性和使用能力边界。很长时间我都在使用ChatGLM系列并且完成了很多的原本不熟悉的工作(比如写一个脚本、写一个basic之类的)基本上能节省这些时间大概提升了我10~30倍的效率。
直到最近的deepseek出现。
0x01 缘起
最早我接触deepseek是在v3刚出来的时候,那时候我很喜欢他的coder,他的coder让我得到了现在最强的编码能力(至少是我现在的使用下最强)。我使用了coder模型基本上完成两个小程序的90%以上开发。一个是go语言一个是vue。我对这两个代码基本上是不咋懂的,但是跟着模型生成的代码简单做一些边角料的字符串替代,让我得到了一个近乎完整的程序。也算是蛮不错的。
那个时候我也使用过他的R1模型,但是估计是内测阶段,所以识别速度和幻觉都很强。有时候给他中文的任务中有部分英文他也会完全英文输出。
事情到了年终,突然deepseek似乎引爆了某些舆论定点。然后大家不约而同的开始疯狂使用,直到联网模式崩掉(联网模式也是很强但是我个人感觉比glm差一点)。
在此之前我也是用过推理模型,glm一直有内测自己的zero模型,但是目前还是beta的阶段,估计还是有一定的bug要解决。但是zero模型感觉更加理性,没有R1这么口语化的输出。
如下附上最近一次的脚本开发记录:
DeepSeek - 根据 mariadb-backup 的帮助信息,备份的基本用法如 (Total Tokens: 11637)
Human
2025-02-03T14:18:18.839Z
根据 mariadb-backup 的帮助信息,备份的基本用法如下:
- 全量备份:
mariadb-backup --backup --target-dir=/path/to/backup/dir
该命令会将整个 MariaDB 数据库备份到指定的目录。其中:
- --backup 表示执行备份操作
- --target-dir 指定备份文件存放的目录
- 准备备份:
mariadb-backup --prepare --target-dir=/path/to/backup/dir
在恢复备份之前,需要先准备备份,应用日志等。其中:
- --prepare 表示准备一个备份
- --target-dir 指定之前的备份目录
- 恢复备份:
mariadb-backup --copy-back --target-dir=/path/to/backup/dir
该命令会将准备好的备份数据恢复到 MariaDB 的数据目录。其中:
- --copy-back 表示恢复一个备份
- --target-dir 指定准备好的备份目录
- 增量备份:
mariadb-backup --backup --incremental-basedir=/path/to/base/backup --target-dir=/path/to/incremental/backup
在一个全量备份的基础上执行增量备份。其中:
- --incremental-basedir 指定基础全量备份的目录
- --target-dir 指定新的增量备份目录
- 准备增量备份:
mariadb-backup --prepare --incremental-dir=/path/to/incremental/backup --target-dir=/path/to/base/backup
准备增量备份时,需要同时指定全量备份目录和增量备份目录。其中:
- --incremental-dir 指定增量备份目录
总结起来,一般的备份流程是:
- 全量备份
- 准备全量备份
- 增量备份
- 准备增量备份
- 恢复备份到数据库
在使用时,根据实际情况,可以灵活选择备份选项,如压缩、加密、并行等,来优化备份性能和安全性。建议定期全量备份,中间执行增量备份,以达到备份与恢复的最佳平衡。
请给我准备一个脚本,在指定位置为空时自动选择全量备份,而如果指定位置文件夹下有文件,则选择增量备份在指定目录下生成的日期-时间的文件夹内。如果是恢复,则先检查备份文件夹的目录下是否有日期-时间格式的文件夹,如果有就依次选择准备增量备份,没有则选择选择准备全量备份,随后恢复备份到数据库
Assistant
2025-02-03T14:18:18.839Z
根据需求,编写以下脚本实现自动全量/增量备份与恢复:
#!/bin/bash
# MariaDB 自动备份恢复脚本
# 用法:script.sh [backup|restore] /path/to/backup/dir
# 检查参数
if [ $# -ne 2 ]; then
echo "用法:$0 [backup|restore] /path/to/backup/dir"
exit 1
fi
MODE=$1
TARGET_DIR=$2
# 备份模式
backup() {
# 创建目录如果不存在
mkdir -p "$TARGET_DIR"
# 检查目录是否为空
if [ -z "$(ls -A "$TARGET_DIR")" ]; then
echo "[$(date +'%Y-%m-%d %H:%M:%S')] 执行全量备份到 $TARGET_DIR"
mariadb-backup --backup --target-dir="$TARGET_DIR"
else
# 查找最新备份目录(全量或增量)
LATEST_BACKUP=$(find "$TARGET_DIR" -maxdepth 1 -type d \( -name '20[0-9][0-9]-[0-9][0-9]-[0-9][0-9]_[0-9][0-9]-[0-9][0-9]-[0-9][0-9]' -o -path "$TARGET_DIR" \) | sort | tail -n 1)
# 生成增量目录名
INCREMENTAL_DIR="$TARGET_DIR/$(date +'%Y-%m-%d_%H-%M-%S')"
echo "[$(date +'%Y-%m-%d %H:%M:%S')] 执行增量备份到 $INCREMENTAL_DIR 基于 $LATEST_BACKUP"
mariadb-backup --backup --incremental-basedir="$LATEST_BACKUP" --target-dir="$INCREMENTAL_DIR"
fi
}
# 恢复模式
restore() {
if [ ! -d "$TARGET_DIR" ]; then
echo "错误:备份目录不存在"
exit 1
fi
echo "[$(date +'%Y-%m-%d %H:%M:%S')] 停止 MariaDB 服务..."
systemctl stop mariadb
# 准备全量备份
echo "[$(date +'%Y-%m-%d %H:%M:%S')] 准备全量备份..."
mariadb-backup --prepare --target-dir="$TARGET_DIR"
# 准备增量备份(按时间排序)
INCREMENTAL_DIRS=$(find "$TARGET_DIR" -maxdepth 1 -type d -name '20[0-9][0-9]-[0-9][0-9]-[0-9][0-9]_[0-9][0-9]-[0-9][0-9]-[0-9][0-9]' | sort)
for dir in $INCREMENTAL_DIRS; do
echo "[$(date +'%Y-%m-%d %H:%M:%S')] 准备增量备份:$dir"
mariadb-backup --prepare --incremental-dir="$dir" --target-dir="$TARGET_DIR"
done
# 恢复备份
echo "[$(date +'%Y-%m-%d %H:%M:%S')] 恢复数据库..."
mariadb-backup --copy-back --target-dir="$TARGET_DIR"
# 修复权限(根据实际情况调整路径)
echo "[$(date +'%Y-%m-%d %H:%M:%S')] 修复数据目录权限..."
chown -R mysql:mysql /var/lib/mysql
echo "[$(date +'%Y-%m-%d %H:%M:%S')] 启动 MariaDB 服务..."
systemctl start mariadb
}
# 主逻辑
case "$MODE" in
backup)
backup
;;
restore)
restore
;;
*)
echo "错误:未知模式 '$MODE'"
echo "可用模式:backup | restore"
exit 1
;;
esac
echo "[$(date +'%Y-%m-%d %H:%M:%S')] 操作完成!"
使用说明:
-
备份数据库:
sudo ./script.sh backup /path/to/backups
- 首次执行时自动执行全量备份
- 后续执行会自动检测已有备份并执行增量备份
- 增量备份会生成日期时间格式的子目录(如
2024-06-01_12-30-45
)
-
恢复数据库:
sudo ./script.sh restore /path/to/backups
- 自动准备所有备份(包括增量)
- 自动停止/启动 MariaDB 服务
- 自动修复数据目录权限
功能特性:
-
智能备份检测:
- 自动识别空目录执行全量备份
- 非空目录自动执行增量备份
- 增量备份基于最新的备份(全量或增量)
-
自动化恢复流程:
- 自动停止数据库服务
- 按时间顺序准备所有增量备份
- 自动修复文件权限
- 自动启动数据库服务
-
日志跟踪:
- 每个步骤都带有时间戳输出
- 清晰的错误提示信息
注意事项:
- 需要 root 权限运行(用于服务管理和文件操作)
- 默认数据目录为
/var/lib/mysql
,如果使用自定义路径需要修改脚本 - 建议定期清理旧备份(脚本未包含自动清理功能)
- 确保备份目录有足够存储空间
- 恢复前请确认数据库已停止且数据目录可写
Thinking Process (408s):
嗯,用户需要的是一个自动化的备份脚本,能够根据目标目录是否为空来决定执行全量备份还是增量备份。此外,恢复的时候需要检查备份目录下是否有日期-时间格式的文件夹,依次准备增量备份,然后恢复。让我仔细想想怎么实现这些需求。
首先,备份部分。如果目标目录为空,就做全量备份,否则增量备份到日期-时间的子目录。那如何判断目标目录是否为空呢?可以用find
命令检查目录下的文件数量,或者直接判断是否有内容。可能需要处理目标目录不存在的情况,先创建它。
然后增量备份需要基于最新的全量或增量备份。但用户提到如果指定位置下有文件就增量备份到日期-时间文件夹。这里可能需要确认增量备份的基目录应该是上一次的备份目录,不管是全量还是增量。不过根据用户给的例子,增量备份是基于全量的,可能需要找到最近的全量或增量备份作为基础。不过用户给出的参数是--incremental-basedir
,所以必须指定基目录。所以每次增量备份需要基于最新的备份,无论是全量还是之前的增量?
不过根据用户提供的增量备份命令,全量之后增量,所以可能需要每次增量都基于上一次备份。但用户的需求是当目标目录不为空时,增量备份到子目录。可能需要每次增量备份都基于上一次备份,无论是全量还是增量。不过这可能不太符合常规做法,通常增量是基于全量的,然后可能再基于之前的增量。但具体要看用户的需求。
这里用户可能希望每次增量都基于最新的备份,不管类型。或者可能每次全量备份后,增量都是基于全量,而后续的增量可能基于之前的增量。不过根据用户提供的增量备份命令示例,全量备份后增量备份基于全量,然后在准备的时候需要合并增量到全量。所以可能需要增量备份都是基于全量的,或者基于最新的全量或增量?
可能用户希望每次全量备份放在主目录下,而增量备份放在子目录中。例如,全量备份在/path/to/backup,而增量备份在/path/to/backup/2024-06-01_12-30这样的子目录。或者,用户的主备份目录可能有多个全量和增量,但根据问题描述,用户希望当目标目录非空时,执行增量备份到日期-时间的子目录。这可能意味着全量备份直接放在目标目录下,而增量备份则在目标目录下的子目录里。
比如,目标目录/path/to/backup,全量备份时,所有文件直接放在这个目录下。当执行增量时,创建子目录如2024-06-01_12-30,并将增量备份放在里面。这样,当用户再次运行脚本时,发现目标目录下已经有文件(比如全量备份),则执行增量备份到新的子目录。
那判断目标目录是否为空的方法是,检查目录是否存在,并且是否有内容。如果目标目录不存在或者存在但为空,则执行全量备份,否则执行增量备份到子目录。
那脚本需要处理两种情况:
备份模式:
- 如果目标目录不存在或者存在但为空(即没有文件或子目录),则执行全量备份到目标目录。
- 如果目标目录非空,则执行增量备份到目标目录下的日期-时间子目录。
恢复模式:
恢复时需要检查备份目录下是否有日期-时间格式的子目录(即增量备份),如果有的话,按顺序准备这些增量备份,然后恢复全量备份加上所有增量备份。但根据mariadb-backup的流程,准备增量备份时需要先准备全量备份,然后依次应用每个增量备份到全量备份目录。最后恢复全量备份目录。
所以恢复流程应该是:
- 准备全量备份:mariadb-backup --prepare --target-dir=全量目录
- 对于每个增量备份目录(按时间顺序),执行:mariadb-backup --prepare --incremental-dir=增量目录 --target-dir=全量目录
- 最后执行copy-back恢复全量目录。
但用户的备份结构是全量备份在目标目录下,而增量备份在目标目录下的子目录中。那么全量备份的目录是用户指定的目标目录,而增量备份的子目录是按日期时间创建的。
例如:
/path/to/backup/ (全量备份的文件在此)
/path/to/backup/2024-06-01_10-00/ (增量备份1)
/path/to/backup/2024-06-02_11-00/ (增量备份2)
这样,恢复时需要先准备全量备份目录,然后按时间顺序准备每个增量备份目录,最后执行copy-back。
所以在脚本中,恢复部分需要:
- 检查备份目录是否存在全量备份(即目标目录是否有效)
- 然后找到所有增量备份的子目录(按名称排序,假设名称是日期时间格式,可以按名称排序)
- 先准备全量备份:--prepare --target-dir=目标目录
- 然后循环每个增量目录,执行:--prepare --incremental-dir=增量目录 --target-dir=目标目录
- 最后执行copy-back
所以,恢复流程的大致步骤是:
- 停止MariaDB服务(可能需要,否则恢复时数据目录被占用)
但用户提供的命令中没有提到停止服务,可能mariadb-backup需要数据库处于运行状态?或者是否需要停止服务?这部分可能需要处理。例如,在恢复前停止MariaDB,恢复后启动。
但用户可能没有在脚本中处理这个,需要确认。或者用户希望脚本处理服务的停止和启动?
假设用户知道在恢复前停止数据库,或者在脚本中加入停止和启动的步骤。但原问题中没有提到,所以可能脚本中需要处理。
或者,mariadb-backup的恢复命令在运行时是否需要数据库停止?根据文档,恢复时需要datadir是空的,并且数据库服务没有运行。所以,在恢复之前,需要停止服务,清空数据目录(或者由copy-back处理?)
根据mariadb-backup的文档,执行--copy-back时,会覆盖数据目录,但可能需要确保数据库服务已停止,否则数据目录可能被占用。
所以,在恢复前,可能需要停止MariaDB服务,然后执行copy-back,再启动服务。
这部分需要在脚本中处理吗?用户可能希望脚本自动处理这些步骤,但原问题中没有说明,所以可能需要添加。
但现在用户的需求中没有提到这一点,可能用户希望脚本只处理备份和恢复命令,而服务的停止和启动由用户自己处理,或者需要脚本处理。这可能需要明确。
假设在恢复前需要停止服务,恢复后启动。所以在脚本的恢复部分,需要停止服务,执行copy-back,然后启动服务。这部分可能需要sudo权限,或者用户有权限管理服务。
但考虑到脚本可能需要以root权限运行,或者在脚本中使用systemctl命令。需要根据具体情况处理。但用户可能希望脚本中包含这些步骤,所以应该在脚本中加入。
现在回到问题,用户希望脚本能根据目录情况自动选择备份类型,恢复时自动处理增量备份。
现在,编写脚本的大纲:
脚本接受两个参数:模式(backup或restore)和目标目录。
例如:script.sh backup /backup 或者 script.sh restore /backup
在备份模式下:
- 检查目标目录是否存在,是否为空。
- 如果空,执行全量备份到目标目录。
- 否则,创建日期-时间子目录,执行增量备份到该子目录,基目录是目标目录中的最新备份(可能是全量或之前的增量?)
这里有个问题,增量备份的基目录应该是什么?
根据用户提供的增量备份命令,全量备份作为基目录。但根据用户的需求描述,当目标目录非空时,增量备份基于该目录下的文件,即全量备份。或者,是否应该基于最新的备份(无论是全量还是之前的增量)?
根据用户给出的增量备份命令示例,增量是基于全量备份目录。例如:
增量备份命令中的--incremental-basedir指向全量备份目录。但如果在目标目录下已经存在增量备份的子目录,那么新的增量备份应该基于最新的那个增量备份吗?或者还是基于全量?
这可能取决于备份策略。如果是全量之后每次增量都基于全量,那么会导致每个增量都是基于全量的,这样恢复时需要合并所有增量。但通常增量备份是基于上一次备份(无论是全量还是增量)。
不过,在用户提供的示例中,增量备份是基于全量备份,而准备增量备份时,需要将增量应用到全量备份目录。这可能意味着每个增量都是基于全量备份的,而不是之前的增量。
这可能不太对,因为通常增量备份可以基于全量或之前的增量。例如,全量备份后,第一次增量基于全量,第二次增量基于第一次增量,以此类推。这时,在恢复时需要应用所有增量备份到全量备份。
但根据用户提供的增量备份命令,增量的基目录是全量备份,这可能说明每次增量都是基于全量的,这样每个增量只包含自全量备份后的变化,而多个增量备份之间可能有重叠。这会导致备份数据量较大,因为每个增量都是相对于全量的。这可能不是最佳实践。
正确的增量备份应该是基于上一次备份(无论是全量还是增量),这样每个增量备份只包含自上次备份后的变化。这样恢复时需要按顺序应用所有增量备份。
所以,用户提供的示例可能有误,或者需要进一步确认。
但根据用户的问题描述中的增量备份命令:
增量备份命令是:
mariadb-backup --backup --incremental-basedir=/path/to/base/backup --target-dir=/path/to/incremental/backup
其中,base backup是全量备份的目录。所以增量备份是基于全量的,而不是之前的增量。
这可能意味着用户的增量备份策略是全量备份后,每次增量都基于全量备份。这可能不适用于多次增量备份的情况,因为每个增量都是相对于全量的,而不是累积的。
这种情况下,如果有多个增量备份,恢复时需要将每个增量备份单独应用到全量备份中,这可能不正确,因为每个增量备份的数据可能相互覆盖。
这显然不符合常规的增量备份策略。所以,可能存在误解,或者用户提供的示例不正确。
正确的增量备份流程应该是:
- 全量备份
- 增量备份1(基于全量)
- 增量备份2(基于增量备份1)
- 准备时,先准备全量,然后应用增量1到全量,再应用增量2到全量(或者按顺序合并)
但根据mariadb-backup的文档,增量备份是基于LSN的,每次增量备份的基目录应该是上一次备份(全量或增量)的目录。所以,当执行增量备份时,必须指定--incremental-basedir为上一次备份的目录,无论是全量还是增量。
因此,在用户的问题中,增量备份的基目录应该是上一次备份的目录,而不仅仅是全量备份的目录。这可能意味着用户的增量备份命令中的--incremental-basedir参数应该指向最近一次的备份目录,可能是全量或增量。
例如,第一次增量备份基于全量,第二次增量备份基于第一次增量备份,依此类推。
因此,在用户的脚本中,当执行增量备份时,需要找到最新的备份目录作为基目录。这可能包括全量备份目录或者最近的增量备份子目录。
但根据用户的需求,全量备份直接放在目标目录下,而增量备份放在目标目录的子目录中,按日期-时间命名。例如:
目标目录结构:
/path/to/backup/ (全量备份)
/path/to/backup/2024-06-01_10-00/ (增量备份1)
/path/to/backup/2024-06-01_12-00/ (增量备份2)
在这种情况下,每个增量备份的基目录应该是上一次备份的目录。例如,增量备份1的基目录是全量备份目录,增量备份2的基目录是增量备份1的目录。
但这样会导致增量备份的基目录是另一个增量备份目录,这在mariadb-backup中是允许的吗?根据文档,是的。每个增量备份必须基于一个完整的备份(全量或已准备的增量)。
所以,在这种情况下,增量备份的基目录需要是最近一次的备份目录,无论是全量还是增量。
所以在备份脚本中,当需要执行增量备份时,必须找到最近的备份目录作为基目录。这可能包括全量目录或最新的增量子目录。
但用户的备份目录结构是全量备份文件直接存放在目标目录,而增量备份存放在子目录中。因此,当执行增量备份时,基目录可以是目标目录(全量备份)或者最新的子目录(增量备份)。
所以,在备份脚本中,当目标目录非空时,需要找到最新的备份目录作为基目录。如果存在子目录,则选择最新的子目录作为基目录;否则,基目录是目标目录本身(全量备份)。
例如:
如果目标目录下有一个全量备份,没有子目录,则增量备份的基目录是目标目录。
如果目标目录下有全量备份和一个或多个增量子目录,则基目录是最近创建的增量子目录。
但如何确定哪个是最近的增量子目录?因为子目录是按日期-时间命名的,可以按名称排序,取最新的。
所以,在备份模式下,当目标目录非空时:
- 检查是否存在任何子目录(增量备份)。
- 如果有,找到最新的子目录作为基目录。
- 否则,基目录是目标目录本身(全量备份)。
然后执行增量备份到新的子目录。
但用户的问题中,增量备份命令的基目录是全量备份目录。所以,可能用户的意图是每次增量都基于全量备份,而不是之前的增量。这可能不符合常规做法,但可能用户的需求如此。
这时候,增量备份的基目录始终是全量备份目录,而不管之前是否有增量备份。这样,每次增量都是相对于全量备份的,这样多个增量备份之间可能会有重叠,恢复时需要将所有增量备份应用到全量备份中。这可能可行,但会导致备份数据量较大。
或者,用户可能希望每次增量备份都基于上一次的备份,无论是全量还是增量。这样,每个增量备份只包含自上次备份后的更改,恢复时需要按顺序应用所有增量备份。
现在回到用户的原始问题:
用户的需求是,当执行备份时,如果目标目录为空,则全量备份;否则增量备份到日期-时间子目录。恢复时,检查备份目录是否有日期-时间子目录(增量),然后依次准备增量备份,最后恢复。
但根据用户的增量备份命令,基目录是全量备份,所以每个增量备份都是基于全量的。这可能意味着,在恢复时,每个增量备份都需要单独应用到全量备份,这可能不正确,因为如果有多个增量备份,每个都是基于全量备份的,那么他们的LSN范围可能重叠,导致数据不一致。
正确的做法应该是,增量备份基于上一次备份(全量或增量),而恢复时按顺序应用所有增量备份到全量备份。
因此,用户提供的示例可能有误,正确的增量备份应基于最近的备份目录。
因此,在脚本中,当执行增量备份时,必须找到最近的备份目录作为基目录,无论它是全量还是增量。
因此,在备份脚本的逻辑中:
当需要执行增量备份时:
- 检查目标目录是否非空。
- 找到最新的备份目录作为基目录。这可能是目标目录本身(全量备份)或最新的增量子目录(按名称排序)。
例如,子目录的命名格式是YYYY-MM-DD_HH-MM-SS,按名称排序即可得到最新的。
所以,在备份模式下:
如果目标目录为空,执行全量备份到目标目录。
否则:
创建新的子目录(日期-时间格式),执行增量备份,基目录是最近一次的备份目录(可能是全量或增量)。
这样,每次增量都基于最近一次的备份,无论是全量还是增量。
但用户提供的命令示例中,增量备份的基目录是全量备份,所以可能需要调整。
现在回到用户的问题,用户可能希望每次增量都基于全量备份,这样每次增量备份都是独立于其他增量备份的。这可能适用于某些场景,但恢复时需要将所有增量备份应用到全量备份中。
或者,用户可能希望增量备份基于上一次备份,无论是全量还是增量。这需要根据具体情况调整。
可能用户的真实需求是,当目标目录为空时做全量,否则做增量,而增量备份基于全量备份。这样,每次增量都是基于全量备份,如果有多个增量备份,每个都是基于全量备份的独立增量,这样恢复时需要应用所有增量备份到全量备份。
这种情况下,恢复时每个增量备份都要单独应用到全量备份目录。这可能有效,但需要确保每个增量备份的LSN范围不重叠,或者在应用时能正确处理。
这可能比较复杂,所以正确的做法应该是增量备份基于最近的备份。
现在,回到脚本编写:
备份逻辑:
- 如果目标目录不存在或为空,创建目标目录,执行全量备份。
- 否则,创建子目录(日期-时间格式),执行增量备份,基目录是最近一次的备份目录(可能是全量或增量)。
恢复逻辑:
- 准备全量备份目录。
- 按时间顺序准备每个增量备份子目录到全量目录。
- 执行copy-back.
所以,现在需要确定如何找到基目录和增量目录。
在备份时:
当执行增量备份时,基目录(--incremental-basedir)需要是最近一次的备份目录。如果目标目录下存在全量备份(即目标目录本身有备份文件),并且没有子目录,则基目录是目标目录。如果存在子目录,则基目录是最近的一个子目录。
所以,在备份脚本中:
检查目标目录是否存在,并且是否有内容:
if [ ! -d "$target_dir" ] || [ -z "$(ls -A "$target_dir")" ]; then
# 全量备份
else
# 增量备份
# 查找最新的备份目录
latest_backup=$(find "$target_dir" -maxdepth 1 -type d -name '[0-9][0-9][0-9][0-9]-[0-9][0-9]-[0-9][0-9]_[0-9][0-9]-[0-9][0-9]-[0-9][0-9]' | sort | tail -n 1)
if [ -z "$latest_backup" ]; then
# 没有增量子目录,基目录是目标目录
incremental_base="$target_dir"
else
# 基目录是最近的增量子目录
incremental_base="$latest_backup"
fi
# 创建新的增量子目录
new_incremental_dir="$target_dir/$(date +'%Y-%m-%d_%H-%M-%S')"
mariadb-backup --backup --incremental-basedir="$incremental_base" --target-dir="$new_incremental_dir"
fi
这样,每次增量备份的基目录是目标目录(全量备份)或者最新的增量子目录。
这样,备份链会是全量 -> 增量1(基于全量) -> 增量2(基于增量1) -> 增量3(基于增量2)等。
在恢复时,需要准备全量备份,然后按顺序应用每个增量备份:
- 准备全量备份:--prepare --target-dir=全量目录
- 对于每个增量备份子目录(按时间顺序),执行:--prepare --incremental-dir=增量目录 --target-dir=全量目录
- 最后执行copy-back.
这样,恢复时会合并所有增量备份到全量备份目录中。
所以,在恢复脚本部分:
首先检查备份目录是否存在:
if [ ! -d "$target_dir" ]; then
echo "错误:备份目录不存在"
exit 1
fi
然后准备全量备份:
mariadb-backup --prepare --target-dir="$target_dir"
然后查找所有增量备份子目录(按名称排序):
incremental_dirs=$(find "$target_dir" -maxdepth 1 -type d -name '[0-9][0-9][0-9][0-9]-[0-9][0-9]-[0-9][0-9]_[0-9][0-9]-[0-9][0-9]-[0-9][0-9]' | sort)
for dir in $incremental_dirs; do
mariadb-backup --prepare --incremental-dir="$dir" --target-dir="$target_dir"
done
最后执行copy-back:
mariadb-backup --copy-back --target-dir="$target_dir"
此外,在恢复前需要确保MariaDB服务已停止,并且数据目录为空或已被清理。所以脚本可能需要停止服务,执行copy-back,然后启动服务。
所以,在恢复部分的脚本可能需要:
停止MariaDB服务
systemctl stop mariadb
执行copy-back
mariadb-backup --copy-back --target-dir="$target_dir"
修改数据目录权限
chown -R mysql:mysql /var/lib/mysql
启动MariaDB服务
systemctl start mariadb
但这一步可能需要根据实际的数据目录路径调整,或者判断数据目录的位置。比如,假设数据目录是/var/lib/mysql,可能需要chown。
此外,用户可能希望脚本处理这些步骤,但原问题中没有说明,可能需要询问用户。不过根据用户的问题描述,恢复命令是直接执行copy-back,可能用户希望脚本处理服务停止和启动,所以最好包含这些步骤,并添加注释,让用户根据需要调整。
综上,脚本的大致结构如下:
备份部分:
- 检查目标目录是否为空,是则全量备份,否则增量备份到子目录。
恢复部分:
- 准备全量备份,然后按顺序准备所有增量备份子目录,最后执行copy-back,并处理服务停止和启动。
现在,处理日期-时间格式的子目录名称。使用date命令生成,格式为%Y-%m-%d_%H-%M-%S,比如2024-06-01_12-30-45。
在备份时,创建这样的子目录名。
在恢复时,查找所有匹配该格式的子目录,并按名称排序(因为名称是按时间升序排列的)。
另外,在恢复时,需要确保全量备份目录是有效的,即包含备份文件。否则,脚本应报错。
现在,编写具体的脚本代码:
脚本接受两个参数:模式(backup或restore)和目标目录。
首先,参数检查:
if [ $# -ne 2 ]; then
echo "用法:$0 [backup|restore] /path/to/backup/dir"
exit 1
fi
mode=$1
target_dir=$2
然后,备份模式:
if [ "$mode" = "backup" ]; then
# 创建目标目录如果不存在
mkdir -p "$target_dir"
# 检查是否为空
if [ -z "$(ls -A "$target_dir")" ]; then
# 全量备份
echo "执行全量备份到 $target_dir"
mariadb-backup --backup --target-dir="$target_dir"
else
# 查找最新的备份目录作为基目录
latest_backup=$(find "$target_dir" -maxdepth 1 -type d -name '20[0-9][0-9]-[0-9][0-9]-[0-9][0-9]_[0-9][0-9]-[0-9][0-9]-[0-9][0-9]' | sort | tail -n 1)
if [ -z "$latest_backup" ]; then
# 没有增量子目录,基目录是目标目录本身(全量备份)
incremental_base="$target_dir"
else
incremental_base="$latest_backup"
fi
# 创建新的增量目录
new_incremental_dir="$target_dir/$(date +'%Y-%m-%d_%H-%M-%S')"
echo "执行增量备份到 $new_incremental_dir,基于 $incremental_base"
mariadb-backup --backup --incremental-basedir="$incremental_base" --target-dir="$new_incremental_dir"
fi
elif [ "$mode" = "restore" ]; then
# 恢复逻辑
# 检查备份目录是否存在
if [ ! -d "$target_dir" ]; then
echo "错误:备份目录 $target_dir 不存在"
exit 1
fi
# 停止MariaDB服务
echo "停止MariaDB服务..."
systemctl stop mariadb
# 准备全量备份
echo "准备全量备份..."
mariadb-backup --prepare --target-dir="$target_dir"
# 查找所有增量备份子目录并按时间排序
incremental_dirs=$(find "$target_dir" -maxdepth 1 -type d -name '20[0-9][0-9]-[0-9][0-9]-[0-9][0-9]_[0-9][0-9]-[0-9][0-9]-[0-9][0-9]' | sort)
for dir in $incremental_dirs; do
echo "准备增量备份 $dir..."
mariadb-backup --prepare --incremental-dir="$dir" --target-dir="$target_dir"
done
# 执行copy-back
echo "恢复备份到数据库..."
mariadb-backup --copy-back --target-dir="$target_dir"
# 修改数据目录权限
echo "修改数据目录权限..."
chown -R mysql:mysql /var/lib/mysql
# 启动MariaDB服务
echo "启动MariaDB服务..."
systemctl start mariadb
else
echo "错误:未知模式 $mode"
exit 1
fi
但需要注意以下几点:
- 在备份模式中,如果目标目录不存在,则创建它,并执行全量备份。
- 在增量备份时,基目录可能是目标目录(全量备份)或最新的增量子目录。
- 在恢复模式中,假设数据目录是/var/lib/mysql,可能需要根据实际情况调整chown的路径。
- 在停止和启动服务时,使用systemctl,可能需要sudo权限。如果脚本没有以root运行,可能需要添加sudo,但这样可能需要用户配置免密码sudo,或者在脚本中提示输入密码。或者,用户可能以root身份运行脚本。
- 查找增量备份子目录时,使用find命令,名称匹配20[0-9][0-9]-开头,符合日期格式的正则表达式。
- 在恢复前,确保MariaDB服务已停止,否则copy-back可能失败。
- 在应用增量备份时,按名称排序,即按时间顺序,从最早到最晚应用。
现在,测试这个脚本的逻辑:
备份流程:
第一次运行备份模式,目标目录为空:执行全量备份到目标目录。
第二次运行备份模式,目标目录非空,但无增量子目录:执行增量备份到子目录,基目录是目标目录(全量备份)。
第三次运行备份模式,目标目录非空,存在一个增量子目录:查找最新的备份目录(即上次的增量子目录),执行新的增量备份到新的子目录,基目录是上次的增量子目录。
恢复流程:
执行恢复模式,目标目录包含全量备份和一个或多个增量子目录。按时间顺序应用所有增量备份,然后恢复。
这样,备份链正确,恢复时能合并所有增量。
可能存在的问题:
- 如果用户在两次增量备份之间进行了全量备份,这可能导致备份链断裂。但根据脚本的逻辑,全量备份只在目标目录为空时执行,所以用户需要定期清理目标目录或管理全量备份的生成。
- 增量备份的基目录是否正确?每次增量备份都基于最近的备份目录,这样能保证正确的增量链。
综上,这个脚本应该能满足用户的需求。
Human
2025-02-03T14:47:05.515Z
如果入参为restore 则直接备份,但是如果传入rrestore则将当前目录内全部清空,重新执行全量备份。
restore还是按照之前的逻辑,在文件夹内没有文件则全量备份,有文件则检查日期-时间目录,并且删除这种目录后重建目录,将增量备份建立在这个目录下。
Assistant
2025-02-03T14:47:05.515Z
Thinking Process :
好的,用户之前让我写一个自动备份和恢复MariaDB的脚本,现在他们提出了新的需求。需要仔细分析他们的具体要求,确保理解正确。
首先,用户提到如果入参是restore,则按之前的逻辑处理,但如果传入rrestore(注意可能是个拼写错误,可能是restore的变体,比如强制恢复或完全恢复),则要清空当前目录并执行全量备份。不过根据后续描述,可能用户的意思是当使用rrestore参数时,清空备份目录,重新进行全量备份。而原来的restore参数逻辑不变,即在恢复时检查备份目录的结构,准备并恢复数据。
不过用户接下来的描述有点矛盾。用户说:“restore还是按照之前的逻辑,在文件夹内没有文件则全量备份,有文件则检查日期-时间目录,并且删除这种目录后重建目录,将增量备份建立在这个目录下。” 这里提到的restore逻辑似乎和备份相关,但restore本应是恢复操作,而不是备份。可能是用户表述有误,需要仔细确认。
可能的正确理解是,当执行备份时(backup模式),如果目标目录为空,则全量备份;如果非空,且有日期-时间格式的子目录,则删除这些子目录,然后进行全量备份?或者是在备份时,如果目录非空,则删除旧的增量备份目录,然后创建新的增量备份?
或者,用户可能在说,当使用restore参数时,如果备份目录中没有日期-时间文件夹,则执行全量备份;如果有,则处理增量。但恢复操作应该是基于已有的备份进行恢复,而不是执行备份。因此这里可能存在误解,需要进一步分析。
根据用户当前的问题描述:
- 当传入restore参数时,保持原来的逻辑:即恢复备份,停止服务,准备备份,恢复数据。
- 当传入rrestore参数时(可能是一个新的模式),则清空当前备份目录,并执行全量备份。
- 对于备份操作(backup模式),如果目录为空则全量,否则增量备份到日期-时间子目录。但用户提到“restore还是按照之前的逻辑,在文件夹内没有文件则全量备份,有文件则检查日期-时间目录,并且删除这种目录后重建目录,将增量备份建立在这个目录下。” 这里可能存在混淆,可能用户希望备份时,如果目录非空且有日期目录,则删除这些目录,然后进行全量备份?或者是在备份时,如果目录非空,则删除旧的增量备份目录,再创建新的增量备份?
这可能不太合理,因为增量备份通常是基于之前的全量或增量备份,如果删除旧的增量目录,会导致后续的增量无法正确应用。因此,用户的需求可能需要重新梳理。
可能的正确需求是:
- 当执行备份(backup模式)时:
- 如果目标目录为空,执行全量备份到该目录(不创建子目录)。
- 如果目标目录非空,检查是否有全量备份,然后执行增量备份到新的日期-时间子目录。
- 当执行restore模式时,按原逻辑处理,即准备所有备份并恢复。
- 当执行rrestore模式时,清空备份目录,并执行全量备份(这可能更像是强制全量备份,覆盖之前的备份)。
但用户提到“restore还是按照之前的逻辑,在文件夹内没有文件则全量备份,有文件则检查日期-时间目录,并且删除这种目录后重建目录,将增量备份建立在这个目录下。” 这里可能混淆了备份和恢复的操作。例如,用户可能在说,在备份时,如果目录非空且有日期目录,则删除这些目录,然后创建新的增量备份?这可能不太合理,因为增量备份需要基于之前的备份。
可能用户的实际需求是:
- 新增一个参数rrestore,用于强制全量备份,即清空备份目录后执行全量备份。
- 原来的backup模式逻辑不变:空目录则全量,非空则增量到子目录。
- restore模式保持原来的恢复逻辑。
但用户的原问题描述有些混乱,需要进一步确认。例如,用户提到“如果入参为restore 则直接备份”,这似乎有矛盾,因为restore本应恢复,而不是备份。可能用户在这里打错了,可能原本想表达的是当参数为rrestore时,清空目录并执行全量备份,而原来的restore参数保持恢复逻辑。
结合用户的问题和之前的脚本,可能的正确需求是:
- 当运行脚本时,参数为backup时,按之前的逻辑处理:目录空则全量备份,否则增量备份到日期子目录。
- 参数为restore时,按之前的逻辑恢复备份。
- 新增参数rrestore(可能用户拼写错误,应为restore-force或类似),当使用此参数时,清空备份目录并执行全量备份。
但用户的问题描述中提到:“如果传入rrestore则将当前目录内全部清空,重新执行全量备份。” 这里的“当前目录”可能指备份目标目录。因此,当参数是rrestore时,备份目录会被清空,然后执行全量备份。这可能是一个强制全量备份的操作,覆盖之前的备份。
但用户还提到:“restore还是按照之前的逻辑,在文件夹内没有文件则全量备份,有文件则检查日期-时间目录,并且删除这种目录后重建目录,将增量备份建立在这个目录下。” 这里可能需要重新理解。或许用户希望,当使用restore参数时,进行备份操作?这显然不符合常理,可能用户在这里有误。因此,需要重新整理用户的需求:
用户可能的真实需求:
- 当运行脚本时,参数为backup:按原有逻辑,目录空则全量,否则增量。
- 参数为restore:按原有逻辑恢复。
- 新增参数rrestore(可能是restore的变体),当使用此参数时,执行以下操作:
- 清空备份目录。
- 执行全量备份。
或者,可能用户希望restore参数在恢复时,根据备份目录的情况,自动判断是否全量或增量恢复,而rrestore则是强制全量恢复,但原恢复逻辑已经处理了全量和增量备份的准备。因此,可能用户的描述存在混乱,需要进一步澄清。
根据用户的问题,可能的正确修改是:
在原有脚本的基础上,增加一个rrestore参数的处理,当使用rrestore时,清空备份目录并执行全量备份,而restore参数保持原来的恢复逻辑。但用户的问题中提到:“如果入参为restore 则直接备份”,这可能是一个笔误,可能用户想表达的是当参数为rrestore时,执行全量备份并清
Human
2025-02-03T14:49:21.371Z
如果入参为backup 则直接备份,但是如果传入force-backup则将当前目录内全部清空,重新执行全量备份。
backup 还是按照之前的逻辑,在文件夹内没有文件则全量备份,有文件则检查日期-时间目录,并且删除这种目录后重建目录,将增量备份建立在这个目录下。刚才说的错误,现在改正了。至于restore目前逻辑不变
Assistant
2025-02-03T14:49:21.371Z
根据您的需求调整后的脚本如下:
#!/bin/bash
# MariaDB 智能备份恢复脚本
# 功能:支持智能全量/增量备份、强制全量备份、自动恢复
# 用法:script.sh [backup|force-backup|restore] /path/to/backup/dir
# 检查参数
if [ $# -ne 2 ]; then
echo "用法:$0 [backup|force-backup|restore] /path/to/backup/dir"
exit 1
fi
MODE=$1
TARGET_DIR=$2
# 日志输出函数
log() {
echo "[$(date +'%Y-%m-%d %H:%M:%S')] $1"
}
#-----------------------------------------
# 备份功能实现
#-----------------------------------------
# 普通备份模式
regular_backup() {
mkdir -p "$TARGET_DIR"
if [ -z "$(ls -A "$TARGET_DIR")" ]; then
log "执行全量备份到:$TARGET_DIR"
mariadb-backup --backup --target-dir="$TARGET_DIR"
else
log "清理历史增量备份..."
find "$TARGET_DIR" -maxdepth 1 -type d -name '20[0-9][0-9]-[0-9][0-9]-[0-9][0-9]_[0-9][0-9]-[0-9][0-9]-[0-9][0-9]' -exec rm -rf {} +
local incremental_dir="$TARGET_DIR/$(date +'%Y-%m-%d_%H-%M-%S')"
mkdir -p "$incremental_dir"
log "执行增量备份到:$incremental_dir"
mariadb-backup --backup \
--incremental-basedir="$TARGET_DIR" \
--target-dir="$incremental_dir"
fi
}
# 强制全量备份模式
force_full_backup() {
log "强制清空备份目录..."
rm -rf "${TARGET_DIR:?}/"* # 安全删除操作
log "执行全新全量备份..."
mariadb-backup --backup --target-dir="$TARGET_DIR"
}
#-----------------------------------------
# 恢复功能实现
#-----------------------------------------
restore_backup() {
# 验证备份目录
if [ ! -d "$TARGET_DIR" ]; then
log "错误:备份目录不存在"
exit 1
fi
# 停止数据库服务
log "停止 MariaDB 服务..."
systemctl stop mariadb
# 准备基础备份
log "准备基础备份..."
mariadb-backup --prepare --target-dir="$TARGET_DIR"
# 准备增量备份(按时间排序)
log "处理增量备份..."
find "$TARGET_DIR" -maxdepth 1 -type d -name '20[0-9][0-9]-[0-9][0-9]-[0-9][0-9]_[0-9][0-9]-[0-9][0-9]-[0-9][0-9]' | sort | while read -r dir; do
log "准备增量备份:$dir"
mariadb-backup --prepare \
--incremental-dir="$dir" \
--target-dir="$TARGET_DIR"
done
# 执行恢复
log "恢复数据库文件..."
mariadb-backup --copy-back --target-dir="$TARGET_DIR"
# 修复权限
log "修复文件权限..."
chown -R mysql:mysql /var/lib/mysql
# 启动服务
log "启动 MariaDB 服务..."
systemctl start mariadb
}
#-----------------------------------------
# 主控制逻辑
#-----------------------------------------
case "$MODE" in
backup)
regular_backup
;;
force-backup)
force_full_backup
;;
restore)
restore_backup
;;
*)
echo "错误:未知模式 '$MODE'"
echo "可用模式:backup | force-backup | restore"
exit 1
;;
esac
log "操作成功完成!"
主要改进说明:
-
模式扩展:
backup
:智能模式- 首次执行时创建全量备份
- 后续执行自动清理旧增量备份并创建新增量
force-backup
:强制模式- 清空目标目录后执行全新全量备份
restore
:恢复模式(保持不变)
-
备份逻辑优化:
# 清理命令示例: find /backup -maxdepth 1 -type d -name '2024-*-*_*-*-*' -exec rm -rf {} + # 增量备份命令示例: mariadb-backup --backup --incremental-basedir=/backup --target-dir=/backup/2024-06-01_12-30-45
-
安全增强:
- 使用
${TARGET_DIR:?}
防止误删根目录 - 增加操作日志跟踪
- 严格的参数检查
- 使用
-
使用建议:
# 常规备份(智能模式) sudo ./script.sh backup /data/mariadb_backups # 强制全量备份(清理目录后执行) sudo ./script.sh force-backup /data/mariadb_backups # 恢复备份(自动处理增量) sudo ./script.sh restore /data/mariadb_backups
-
目录结构示例:
/data/mariadb_backups/ ├── ibdata1 ├── xtrabackup_checkpoints └── 2024-06-01_15-30-00/ ├── incremental.signal └── xtrabackup_logfile
注意事项:
-
备份目录结构:
- 全量备份直接存储在目标目录根下
- 增量备份存储在日期-时间格式的子目录中
-
恢复工作原理:
graph TD A[停止数据库服务] --> B[准备基础备份] B --> C{是否有增量备份?} C -- 是 --> D[按时间顺序准备所有增量备份] C -- 否 --> E[执行恢复操作] D --> E E --> F[修复文件权限] F --> G[启动数据库服务]
-
推荐设置:
# 添加到crontab的示例(每天2点执行) 0 2 * * * /opt/scripts/mariadb_backup.sh backup /backup/mariadb # 每周日凌晨3点强制全量备份 0 3 * * 0 /opt/scripts/mariadb_backup.sh force-backup /backup/mariadb
该脚本通过智能清理机制确保备份目录整洁,同时保留完整的恢复能力。强制备份模式适用于需要基线备份的场景,常规备份模式适合日常增量保护。
Thinking Process (230s):
好的,用户希望我根据之前的对话和新的需求调整脚本来满足他们的要求。首先,用户提到之前提供的脚本有一个错误,需要修正。具体来说,当使用backup参数时,如果目标目录下已经有文件,应该检查是否存在日期-时间格式的子目录,如果有的话,删除这些目录,然后重新创建,并在其中进行增量备份。此外,新增了一个force-backup参数,用于清空目标目录并执行全量备份。
首先,我需要回顾之前的脚本逻辑。原来的备份函数中,当目标目录不为空时,会查找最新的备份目录(全量或增量),然后在该基础上进行增量备份。但用户现在指出,如果有日期-时间目录,应该删除这些目录,然后重新创建并执行增量备份。这可能需要调整逻辑,确保在备份时,如果存在旧的增量目录,先清理它们,再进行新的增量备份。
另外,用户新增了force-backup模式,需要清空目标目录并执行全量备份。这需要在脚本中增加一个新的参数处理,当模式是force-backup时,删除目标目录下的所有内容,然后执行全量备份。
接下来,我需要检查原来的备份逻辑是否正确处理了用户的需求。用户提到之前的逻辑有一个错误,即在有文件的情况下,应该检查并删除日期-时间目录,然后重新创建。这可能意味着原来的脚本没有正确处理这种情况,导致增量备份可能基于不正确的基准目录。
现在需要修改备份函数,分为两个部分:普通backup模式和force-backup模式。在普通模式下,如果目标目录为空,执行全量备份;如果非空,检查是否存在日期-时间目录,如果有,删除这些目录,然后创建新的日期-时间目录进行增量备份。但用户可能希望保留全量备份的基础目录,而只删除增量目录。需要澄清这一点。
根据用户的最新描述,当使用backup参数时,在目标目录存在文件的情况下,应该检查是否有日期-时间的子目录。如果有,则删除这些目录,然后创建新的目录进行增量备份。这可能意味着用户希望每次增量备份都基于原始的全量备份,而不是基于之前的增量备份。但根据MariaDB的增量备份机制,增量备份应该基于前一次备份(无论是全量还是增量)。因此,用户的需求可能需要调整,或者可能存在误解。
用户的需求可能存在矛盾:如果每次增量备份都删除之前的增量目录,那么增量备份链将无法正确应用,因为每个增量备份都基于全量备份,而不是之前的增量。这会导致恢复时只能应用最后一次增量备份,而无法累积所有增量更改。这显然不符合增量备份的设计初衷。因此,用户可能需要重新考虑他们的需求,或者我可能误解了他们的描述。
再仔细阅读用户的问题:“backup 还是按照之前的逻辑,在文件夹内没有文件则全量备份,有文件则检查日期-时间目录,并且删除这种目录后重建目录,将增量备份建立在这个目录下。” 这里的“这种目录”指的是日期-时间格式的子目录。用户希望当执行普通backup时,如果目录非空,则删除所有日期-时间子目录,然后创建新的日期-时间子目录进行增量备份。但全量备份可能位于目标目录的根,而不是子目录中。例如,全量备份直接在/path/to/backup/dir,而增量备份在/path/to/backup/dir/2024-06-01_12-30-45这样的子目录中。
在这种情况下,当执行普通backup时,如果目标目录非空,首先检查是否存在日期-时间子目录,如果有,删除这些子目录,然后创建新的子目录进行增量备份。而全量备份的基础目录仍然是目标目录本身。这可能意味着用户希望每次增量备份都基于最初的全量备份,而不是累积的增量,这可能不符合增量备份的最佳实践,但需要按用户要求实现。
因此,修改备份逻辑如下:
在backup模式下:
- 如果目标目录为空,执行全量备份到目标目录(根目录)。
- 如果目标目录非空:
- 删除所有日期-时间格式的子目录。
- 创建新的日期-时间子目录。
- 执行增量备份,基于目标目录(全量备份)到新的子目录。
这样,每次增量备份都基于全量备份,而不是之前的增量,这可能不是标准的做法,但用户的需求如此。这可能意味着用户希望每次增量都是基于最新的全量备份,而之前的所有增量都被删除,这可能用于简化备份管理,但会丢失中间的增量备份点。
或者,用户可能希望每次增量备份都基于最新的备份,无论是全量还是增量。但根据用户的最新指示,当执行backup时,如果有文件存在,则删除所有日期-时间目录,然后创建新的进行增量备份。这可能意味着用户希望全量备份在目标目录根,而增量备份在子目录中,但每次备份时,之前的增量都被删除,只保留全量和一个最新的增量。这可能是为了节省空间,但会限制恢复点。
不过,这样的设计可能存在问题,因为增量备份需要基于之前的备份点。如果每次备份都删除之前的增量目录,那么恢复时只能使用全量备份和最新的增量,而中间的增量将丢失。这可能导致数据丢失,因为增量备份通常需要按顺序应用。
但用户的需求明确,需要按照其指示进行调整。因此,在backup模式下,当目录非空时,删除所有日期-时间子目录,然后执行增量备份到新的子目录,基于目标目录中的全量备份。
此外,force-backup模式需要清空目标目录,执行全量备份。这相对简单,只需删除目标目录下的所有内容,然后执行全量备份。
现在需要调整脚本的备份函数:
在backup函数中:
- 如果目标目录为空,执行全量备份到目标目录。
- 如果非空:
- 查找所有日期-时间子目录并删除。
- 创建新的日期-时间子目录。
- 执行增量备份,基于目标目录(全量)到新的子目录。
同时,处理force-backup模式:
- 清空目标目录(删除所有内容)。
- 执行全量备份到目标目录。
此外,需要修改参数处理,允许模式为backup或force-backup,并调整主逻辑。
在脚本的参数检查部分,需要允许三个参数,但实际上用户提到入参为backup或force-backup,所以可能参数数量还是两个,模式可以是backup或force-backup,第二个参数是目标目录。
因此,修改参数检查部分,允许模式为backup、force-backup或restore,参数数量为2。
接下来,修改备份函数,处理backup和force-backup模式:
在backup函数中,可能需要接收一个参数,是否是强制全量备份。或者,将backup和force-backup作为不同的模式处理。
例如:
case "$MODE" in
backup)
backup false
;;
force-backup)
backup true
;;
restore)
restore
;;
*)
...
esac
然后,backup函数根据是否强制全量来决定是否清空目录。
或者,将force-backup作为独立函数处理。
但根据用户的需求,当模式是force-backup时,需要清空目标目录并执行全量备份。因此,可以在备份函数中处理:
backup() {
local force=$1
if [ "$force" = true ]; then
echo "强制全量备份:清空目标目录"
rm -rf "$TARGET_DIR"/*
# 执行全量备份
mariadb-backup --backup --target-dir="$TARGET_DIR"
else
# 原来的逻辑,但需要修改:删除日期-时间子目录,然后增量备份
# 检查目录是否为空
if [ -z "$(ls -A "$TARGET_DIR")" ]; then
# 全量备份
else
# 删除所有日期-时间子目录
# 创建新的子目录
# 增量备份
fi
fi
}
但需要具体实现。
此外,用户提到在backup模式下,如果目标目录有文件,则检查日期-时间目录,并删除这些目录后重建,将增量备份放在新的目录下。因此,当执行普通backup时,如果目录非空,无论是否存在全量备份,都删除所有日期-时间子目录,然后创建新的子目录进行增量备份。这可能意味着用户希望全量备份在目标目录的根,而增量在子目录中,但每次增量备份前清理旧的增量目录。
这可能导致每次增量备份都是基于全量备份,而不是基于之前的增量,这样每次增量备份都会包含自全量备份以来的所有更改,而不是自上次增量以来的更改。这可能不符合增量备份的常规用法,但用户需求如此,需要按此处理。
因此,修改备份函数:
在普通backup模式下:
- 如果目标目录为空,全量备份到目标目录。
- 否则:
- 删除所有日期-时间子目录。
- 创建新的日期-时间子目录。
- 执行增量备份,基于目标目录(全量备份)到新的子目录。
在force-backup模式下:
- 删除目标目录下的所有内容。
- 执行全量备份到目标目录。
这样,每次普通backup都会清理之前的增量备份,只保留全量备份和最新的增量备份。这可能不是最佳实践,但符合用户要求。
现在需要调整脚本:
在backup函数中,当不是force模式时,处理逻辑如下:
if 目标目录为空:
全量备份到目标目录
else:
删除所有日期-时间子目录
创建新的子目录
增量备份到新子目录,基于目标目录(全量)
在force-backup模式时:
清空目标目录
全量备份到目标目录
此外,恢复逻辑不变,按原样处理。
现在需要实现删除所有日期-时间子目录。使用find命令查找匹配的目录并删除:
find "$TARGET_DIR" -maxdepth 1 -type d -regex ".*/[0-9]{4}-[0-9]{2}-[0-9]{2}_[0-9]{2}-[0-9]{2}-[0-9]{2}" -exec rm -rf {} +
但正则表达式在find中的-regex选项可能因系统而异,需要测试。或者使用通配符模式:
find "$TARGET_DIR" -maxdepth 1 -type d -name '20[0-9][0-9]-[0-9][0-9]-[0-9][0-9]_[0-9][0-9]-[0-9][0-9]-[0-9][0-9]' -exec rm -rf {} +
这样可以匹配以日期时间格式命名的目录。
在备份函数中,当不是force模式且目录非空时:
删除所有日期-时间子目录
find "$TARGET_DIR" -maxdepth 1 -type d -name '20[0-9][0-9]-[0-9][0-9]-[0-9][0-9]_[0-9][0-9]-[0-9][0-9]-[0-9][0-9]' -exec rm -rf {} +
# 创建新的增量目录
INCREMENTAL_DIR="$TARGET_DIR/$(date +'%Y-%m-%d_%H-%M-%S')"
mkdir -p "$INCREMENTAL_DIR"
# 执行增量备份,基于目标目录(全量)
mariadb-backup --backup --incremental-basedir="$TARGET_DIR" --target-dir="$INCREMENTAL_DIR"
这样,每次增量备份都基于目标目录的全量备份,而旧的增量目录被删除,只保留最新的。
但这样每次备份都会删除之前的增量,只保留一个增量备份,这可能不是用户想要的。或者用户可能希望保留所有增量备份,但根据用户的最新指示,当执行普通backup时,会删除日期-时间目录并创建新的,所以每次只保留一个增量备份。
这可能不符合常规的增量备份策略,但需要按照用户需求实现。
现在整合到脚本中:
修改脚本的参数检查部分,允许模式为backup、force-backup或restore:
if [ $# -ne 2 ]; then
echo "用法:$0 [backup|force-backup|restore] /path/to/backup/dir"
exit 1
fi
然后,在case语句中处理force-backup:
case "$MODE" in
backup)
backup
;;
force-backup)
force_backup
;;
restore)
restore
;;
*)
...
esac
其中,backup函数处理普通备份,force_backup函数处理强制全量备份。
或者,将force-backup作为backup函数的一个选项,传递参数。例如:
case "$MODE" in
backup)
backup false
;;
force-backup)
backup true
;;
...
esac
然后,在backup函数中根据参数决定是否强制全量:
backup() {
local force=$1
mkdir -p "$TARGET_DIR"
if [ "$force" = true ]; then
echo "[$(date +'%Y-%m-%d %H:%M:%S')] 强制全量备份:清空目标目录..."
rm -rf "${TARGET_DIR:?}/"* # 避免误删除根目录
mariadb-backup --backup --target-dir="$TARGET_DIR"
else
if [ -z "$(ls -A "$TARGET_DIR")" ]; then
echo "[$(date +'%Y-%m-%d %H:%M:%S')] 执行全量备份到 $TARGET_DIR"
mariadb-backup --backup --target-dir="$TARGET_DIR"
else
echo "[$(date +'%Y-%m-%d %H:%M:%S')] 清理旧的增量备份目录..."
find "$TARGET_DIR" -maxdepth 1 -type d -name '20[0-9][0-9]-[0-9][0-9]-[0-9][0-9]_[0-9][0-9]-[0-9][0-9]-[0-9][0-9]' -exec rm -rf {} +
INCREMENTAL_DIR="$TARGET_DIR/$(date +'%Y-%m-%d_%H-%M-%S')"
mkdir -p "$INCREMENTAL_DIR"
echo "[$(date +'%Y-%m-%d %H:%M:%S')] 执行增量备份到 $INCREMENTAL_DIR 基于全量备份 $TARGET_DIR"
mariadb-backup --backup --incremental-basedir="$TARGET_DIR" --target-dir="$INCREMENTAL_DIR"
fi
fi
}
这样,当模式是backup时,调用backup false;当模式是force-backup时,调用backup true,执行强制全量备份。
但用户可能需要force-backup时,无论目录是否为空,都执行全量备份。因此,force-backup的处理应该独立于普通backup逻辑。
或者,将force-backup作为一个独立的函数,例如:
force_backup() {
echo "[$(date +'%Y-%m-%d %H:%M:%S')] 强制全量备份:清空目标目录..."
rm -rf "${TARGET_DIR:?}/"* # 安全删除,防止误操作
mkdir -p "$TARGET_DIR"
mariadb-backup --backup --target-dir="$TARGET_DIR"
}
然后在case语句中调用。
这样,当用户执行force-backup时,无论目标目录是否为空,都会清空并执行全量备份。
而普通backup模式则按原有逻辑,但修改为删除旧的增量目录后执行增量备份。
现在,整合这些逻辑到脚本中:
修改后的脚本大致如下:
#!/bin/bash
# MariaDB 自动备份恢复脚本
# 用法:script.sh [backup|force-backup|restore] /path/to/backup/dir
# 检查参数
if [ $# -ne 2 ]; then
echo "用法:$0 [backup|force-backup|restore] /path/to/backup/dir"
exit 1
fi
MODE=$1
TARGET_DIR=$2
# 备份模式(普通)
backup() {
# 创建目录如果不存在
mkdir -p "$TARGET_DIR"
# 检查目录是否为空
if [ -z "$(ls -A "$TARGET_DIR")" ]; then
echo "[$(date +'%Y-%m-%d %H:%M:%S')] 执行全量备份到 $TARGET_DIR"
mariadb-backup --backup --target-dir="$TARGET_DIR"
else
# 删除所有增量备份目录(日期-时间格式)
echo "[$(date +'%Y-%m-%d %H:%M:%S')] 清理旧的增量备份目录..."
find "$TARGET_DIR" -maxdepth 1 -type d -name '20[0-9][0-9]-[0-9][0-9]-[0-9][0-9]_[0-9][0-9]-[0-9][0-9]-[0-9][0-9]' -exec rm -rf {} +
# 创建新的增量目录
INCREMENTAL_DIR="$TARGET_DIR/$(date +'%Y-%m-%d_%H-%M-%S')"
mkdir -p "$INCREMENTAL_DIR"
echo "[$(date +'%Y-%m-%d %H:%M:%S')] 执行增量备份到 $INCREMENTAL_DIR 基于全量备份 $TARGET_DIR"
mariadb-backup --backup --incremental-basedir="$TARGET_DIR" --target-dir="$INCREMENTAL_DIR"
fi
}
# 强制全量备份模式
force_backup() {
echo "[$(date +'%Y-%m-%d %H:%M:%S')] 强制全量备份:清空目标目录..."
# 安全删除目标目录内容(保留目录本身)
rm -rf "${TARGET_DIR:?}/"* # 使用 :? 防止误删根目录
mkdir -p "$TARGET_DIR"
mariadb-backup --backup --target-dir="$TARGET_DIR"
}
# 恢复模式(保持不变)
restore() {
# ... 原来的恢复逻辑 ...
}
# 主逻辑
case "$MODE" in
backup)
backup
;;
force-backup)
force_backup
;;
restore)
restore
;;
*)
echo "错误:未知模式 '$MODE'"
echo "可用模式:backup | force-backup | restore"
exit 1
;;
esac
# ... 后续输出完成信息 ...
这样,当执行force-backup时,会清空目标目录并执行全量备份。普通backup模式下,目录为空时全量备份,非空时删除所有增量目录,然后执行基于全量的增量备份到新的子目录。
恢复逻辑保持不变,因为用户提到restore逻辑不需要改变。恢复时会准备全量备份和所有增量备份目录。但根据新的备份策略,每次增量备份都是基于全量的,因此恢复时可能只需要应用最新的增量备份。不过,用户可能希望保留多个增量备份,但根据脚本的当前逻辑,每次普通backup会删除旧的增量目录,只保留最新的。因此,恢复时可能只有一个增量目录存在,或者用户可能手动保留多个增量目录。
不过,用户之前的回复中,恢复逻辑会准备所有增量备份目录,按时间顺序。因此,在恢复时,即使每次备份删除了旧的增量目录,只要用户没有手动删除,可能会有多个增量目录。但根据当前脚本的普通backup逻辑,每次都会删除旧的增量目录,因此恢复时可能只有一个增量目录存在。
但用户的需求是,在恢复时,检查备份目录下是否有日期-时间格式的文件夹,如果有就依次准备增量备份。因此,恢复逻辑需要遍历所有增量目录,按时间顺序准备。
然而,根据普通backup模式的逻辑,每次备份都会删除旧的增量目录,因此恢复时可能只有一个增量目录存在,或者用户可能手动保留了多个。无论如何,恢复逻辑保持不变,按原样处理。
最后,测试脚本的逻辑是否符合用户需求:
-
backup模式:
- 目标目录空 → 全量备份到目标目录根。
- 目标目录非空 → 删除所有日期-时间子目录 → 创建新的日期-时间子目录 → 增量备份到该子目录,基于目标目录根的全量备份。
-
force-backup模式:
- 清空目标目录 → 全量备份到目标目录根。
-
restore模式:
- 准备目标目录根的全量备份。
- 按时间顺序准备所有日期-时间子目录的增量备份。
- 恢复数据。
这样,用户的需求应该得到满足。
标题:杂:简单尝试了deepseek-R1的看法
作者:GreenDream
地址:HTTPS://www.greendreamer.work/articles/2025/02/04/1738679645084.html
Comments | 0 条评论