
脚本功能
此脚本是专门用于MySQL8.0逻辑备份的 MySQL Shell备份脚本,它包含了备份数据库实例的所有对象,是整个实例级别的备份,也是当下取代传统mysqldump工具的最优替代方案。
脚本内容
该脚本名称为mysqlshell_full_backup.sh
#!/bin/bash
########################################
# MySQL Shell 自动备份脚本 (MySQL 8.0+)
# 功能: 全量逻辑备份 + 错误处理 + 日志记录 + 自动清理 + 时间统计
# 备份文件名格式: full_mysqlshell_backup_时间
# 使用方式: 直接修改脚本中的变量值,然后执行 ./mysqlshell_full_backup.sh
########################################
################### 配置参数 ###################
# MySQL Shell命令绝对路径(重要:请根据实际安装路径修改)
MYSQLSH_CMD="/data/soft/mysqlshell8044/bin/mysqlsh"
# 备份保留天数(默认15天)
RETAIN_DAYS=${RETAIN_DAYS:-15}
# 并行度(默认4线程)
PARALLEL=${PARALLEL:-4}
# 排除的数据库(逗号分隔,默认空)
EXCLUDE_SCHEMAS=${EXCLUDE_SCHEMAS:-""}
# 备份存储根目录
BACKUP_ROOT="/data/backup"
# 时间戳格式:YYYYMMDD_HHMMSS
TIMESTAMP=$(date +%Y%m%d_%H%M%S)
# 备份目录名称(按您要求的格式)
BACKUP_DIR_NAME="full_mysqlshell_backup_${TIMESTAMP}"
BACKUP_DIR="${BACKUP_ROOT}/${BACKUP_DIR_NAME}"
# MySQL连接参数(请根据实际情况修改)
MYSQL_USER="root"
MYSQL_PASSWORD="mysql"
MYSQL_HOST="localhost"
MYSQL_PORT="3306"
# 日志文件路径
LOG_FILE="${BACKUP_ROOT}/backup.log"
############################################
########## 函数:记录日志 ##########
log() {
local level="$1"
local message="$2"
local timestamp=$(date '+%Y-%m-%d %H:%M:%S')
local log_entry="[${timestamp}] [${level}] ${message}"
# 输出到标准输出并写入日志文件
echo "${log_entry}" | tee -a "${LOG_FILE}"
}
########## 函数:错误处理并退出 ##########
error_exit() {
log "ERROR" "$1"
end_time=$(date +%s)
total_runtime=$((end_time - start_time_global))
log "INFO" "脚本异常退出,总运行时间: $(format_duration $total_runtime)"
exit 1
}
########## 函数:计算和格式化运行时间 ##########
format_duration() {
local seconds=$1
local hours=$((seconds / 3600))
local minutes=$(( (seconds % 3600) / 60 ))
local secs=$((seconds % 60))
if [ $hours -gt 0 ]; then
echo "${hours}小时${minutes}分${secs}秒"
elif [ $minutes -gt 0 ]; then
echo "${minutes}分${secs}秒"
else
echo "${secs}秒"
fi
}
########## 函数:检查依赖工具 ##########
check_dependencies() {
# 检查MySQL Shell是否存在且可执行
if [ ! -x "$MYSQLSH_CMD" ]; then
error_exit "MySQL Shell未在指定路径找到或不可执行: $MYSQLSH_CMD"
fi
# 检查其他依赖工具
local deps=("du")
for dep in "${deps[@]}"; do
if ! command -v "$dep" &> /dev/null; then
error_exit "所需工具 $dep 未安装或未在PATH中"
fi
done
log "INFO" "依赖检查通过,MySQL Shell路径: $MYSQLSH_CMD"
}
########## 函数:检查MySQL连接 ##########
check_mysql_connection() {
log "INFO" "检查MySQL数据库连接..."
if "$MYSQLSH_CMD" --log-level=2 --uri="${MYSQL_USER}:${MYSQL_PASSWORD}@${MYSQL_HOST}:${MYSQL_PORT}" --sql --execute "select 1" >/dev/null 2>&1; then
log "INFO" "MySQL数据库连接成功"
else
error_exit "MySQL数据库连接失败,请检查连接参数"
fi
}
########## 函数:检查磁盘空间 ##########
check_disk_space() {
local available_space=$(df "$BACKUP_ROOT" | awk 'NR==2 {print $4}')
local min_space=$((1024 * 1024)) # 至少保留1GB空间
if [ "$available_space" -lt "$min_space" ]; then
error_exit "磁盘空间不足,剩余空间: ${available_space}KB,至少需要: ${min_space}KB"
fi
log "INFO" "磁盘空间检查通过,剩余空间: ${available_space}KB"
}
########## 主函数:执行备份 ##########
perform_backup() {
log "INFO" "开始执行数据库备份..."
# 构建excludeSchemas参数
local exclude_param=""
if [ -n "$EXCLUDE_SCHEMAS" ]; then
local exclude_jsons=()
IFS=',' read -ra DB_ARRAY <<< "$EXCLUDE_SCHEMAS"
for db in "${DB_ARRAY[@]}"; do
db_clean=$(echo "$db" | sed -e 's/^[[:space:]]*//' -e 's/[[:space:]]*$//' -e "s/'/\\\\'/g")
if [ -n "$db_clean" ]; then
exclude_jsons+=("'$db_clean'")
fi
done
if [ ${#exclude_jsons[@]} -gt 0 ]; then
exclude_param="excludeSchemas: [$(IFS=,; echo "${exclude_jsons[*]}")],"
log "INFO" "排除数据库: ${EXCLUDE_SCHEMAS}"
fi
fi
# 构建备份命令
local backup_cmd="util.dumpInstance('$BACKUP_DIR', {
threads: $PARALLEL,
${exclude_param}
consistent: true,
compression: 'zstd',
ocimds: true,
compatibility: ['strip_restricted_grants','strip_definers','strip_tablespaces','ignore_missing_pks']
})"
log "INFO" "执行MySQL Shell备份命令,并行度: $PARALLEL"
# 执行备份(使用变量化的MYSQLSH_CMD)
if "$MYSQLSH_CMD" --log-level=3 --uri="${MYSQL_USER}:${MYSQL_PASSWORD}@${MYSQL_HOST}:${MYSQL_PORT}" \
--execute "$backup_cmd" >> "$LOG_FILE" 2>&1; then
log "INFO" "MySQL Shell备份命令执行完成"
return 0
else
return 1
fi
}
########## 主函数:清理过期备份 ##########
cleanup_old_backups() {
log "INFO" "开始清理超过 ${RETAIN_DAYS} 天的旧备份..."
local deleted_count=0
while IFS= read -r -d '' old_backup; do
if [ -n "$old_backup" ] && [ "$old_backup" != "$BACKUP_ROOT" ]; then
log "INFO" "删除过期备份: $(basename "$old_backup")"
rm -rf "$old_backup"
((deleted_count++))
fi
done < <(find "$BACKUP_ROOT" -maxdepth 1 -type d -name "full_mysqlshell_backup_*" -mtime "+$((RETAIN_DAYS-1))" -print0 2>/dev/null)
log "INFO" "清理完成,共删除 $deleted_count 个过期备份"
}
########## 主执行流程 ##########
main() {
local start_time_global=$(date +%s)
log "INFO" "=== MySQL备份作业开始 ==="
log "INFO" "备份目录: $BACKUP_DIR"
log "INFO" "保留天数: $RETAIN_DAYS天, 并行度: $PARALLEL"
log "INFO" "排除数据库: ${EXCLUDE_SCHEMAS:-无}"
log "INFO" "MySQL Shell路径: $MYSQLSH_CMD"
# 初始化检查
check_dependencies
check_disk_space
check_mysql_connection
# 创建备份目录
if ! mkdir -p "$BACKUP_DIR"; then
error_exit "无法创建备份目录: $BACKUP_DIR"
fi
log "INFO" "备份目录创建成功: $BACKUP_DIR"
# 执行备份
local backup_start=$(date +%s)
if perform_backup; then
local backup_end=$(date +%s)
local backup_runtime=$((backup_end - backup_start))
log "INFO" "数据库备份成功完成"
log "INFO" "备份耗时: $(format_duration $backup_runtime)"
else
error_exit "数据库备份执行失败,详情请查看日志: $LOG_FILE"
fi
# 清理过期备份
local cleanup_start=$(date +%s)
cleanup_old_backups
local cleanup_end=$(date +%s)
local cleanup_runtime=$((cleanup_end - cleanup_start))
# 最终统计
local end_time_global=$(date +%s)
local total_runtime=$((end_time_global - start_time_global))
log "INFO" "=== 备份作业统计 ==="
log "INFO" "备份文件位置: $BACKUP_DIR"
log "INFO" "备份大小: $(du -sh "$BACKUP_DIR" 2>/dev/null | cut -f1 || echo "未知")"
log "INFO" "各阶段耗时详情:"
log "INFO" " - 备份阶段: $(format_duration $backup_runtime)"
log "INFO" " - 清理阶段: $(format_duration $cleanup_runtime)"
log "INFO" " - 总计耗时: $(format_duration $total_runtime)"
log "INFO" "日志文件: $LOG_FILE"
log "INFO" "=== MySQL备份作业完成 ==="
}
########## 脚本执行入口 - 直接执行主函数 ##########
main
重点说明
1. 关于备份时的参数说明
# 构建备份命令
local backup_cmd="util.dumpInstance('$BACKUP_DIR', {
threads: $PARALLEL,
${exclude_param}
consistent: true,
compression: 'zstd',
ocimds: true,
compatibility: ['strip_restricted_grants','strip_definers','strip_tablespaces','ignore_missing_pks']
})"
上面构建备份语句中,有一个兼容性参数设置compatibility,该参数需要额外说明:
- strip_restricted_grants 移除备份文件中,目标数据库服务不允许授予的高级权限,避免因权限问题导致导入失败
- strip_definers 从视图、存储过程等对象定义中移除 DEFINER=子句,避免因原始定义者不存在而导致的权限错误
- strip_tablespaces 从建表语句中移除 TABLESPACE=子句,此选项可防止因指定不存在的表空间而导致建表失败
- ignore_missing_pks 忽略(跳过检查)没有主键的表,而不为它们自动创建主键,用于容忍没有主键的表,但不会自动修复。如需自动添加主键,应使用 create_invisible_pks选项
2. 关于备份软件的说明
MySQL数据库软件并不自带MySQLShell功能,MySQL Shell软件需要提前下载准备好,下载链接如下:
https://dev.mysql.com/downloads/shell/

MySQLShell软件下载到本地服务器后,解压即可使用非常简单方便。
使用方法
- 保存脚本并赋予执行权限
[root@VM-8-4-opencloudos backup]# chmod +x mysqlshell_full_backup.sh
- 可选手动执行备份
[root@VM-8-4-opencloudos backup]# ./mysqlshell_full_backup.sh

tail -100 /data/backup/backup.log

3. 可配置定时任务(每日凌晨1点执行)
# 编辑crontab:crontab -e 添加如下内容并保存
0 1 * * * /path/to/mysqlshell_full_backup.sh
恢复
作为DBA,恢复工作需要严谨的操作流程。以下是基于该备份的详细恢复步骤和指南。
1. 确认备份文件的完整性
在开始恢复前,务必检查备份目录是否完整。一个成功的 util.dumpInstance备份通常会包含一个 @.done.json文件以及每个数据库对应的 .tsv.zst数据文件和 .sql元数据文件。您可以使用以下命令快速查看备份根目录下的内容:
[root@VM-8-4-opencloudos backup]# ls -l full_mysqlshell_backup_20251113_111713
total 23624
-rw-r----- 1 root root 549 Nov 13 11:17 @.done.json
-rw-r----- 1 root root 1400 Nov 13 11:17 @.json
-rw-r----- 1 root root 240 Nov 13 11:17 @.post.sql
-rw-r----- 1 root root 240 Nov 13 11:17 @.sql
-rw-r----- 1 root root 9 Nov 13 11:17 testdb@a@@0.tsv.zst
-rw-r----- 1 root root 8 Nov 13 11:17 testdb@a@@0.tsv.zst.idx
-rw-r----- 1 root root 612 Nov 13 11:17 testdb@a.json
-rw-r----- 1 root root 750 Nov 13 11:17 testdb@a.sql
-rw-r----- 1 root root 9 Nov 13 11:17 testdb@b@@0.tsv.zst
-rw-r----- 1 root root 8 Nov 13 11:17 testdb@b@@0.tsv.zst.idx
-rw-r----- 1 root root 562 Nov 13 11:17 testdb@b.json
-rw-r----- 1 root root 644 Nov 13 11:17 testdb@b.sql
-rw-r----- 1 root root 585 Nov 13 11:17 testdb.json
-rw-r----- 1 root root 23971894 Nov 13 11:17 testdb@large_table@@0.tsv.zst
-rw-r----- 1 root root 544 Nov 13 11:17 testdb@large_table@@0.tsv.zst.idx
-rw-r----- 1 root root 1036 Nov 13 11:17 testdb@large_table.json
-rw-r----- 1 root root 1418 Nov 13 11:17 testdb@large_table.sql
-rw-r----- 1 root root 92884 Nov 13 11:17 testdb@my_table@@0.tsv.zst
-rw-r----- 1 root root 8 Nov 13 11:17 testdb@my_table@@0.tsv.zst.idx
-rw-r----- 1 root root 890 Nov 13 11:17 testdb@my_table.json
-rw-r----- 1 root root 1349 Nov 13 11:17 testdb@my_table.sql
-rw-r----- 1 root root 4038 Nov 13 11:17 testdb.sql
-rw-r----- 1 root root 14 Nov 13 11:17 testdb@tt@@0.tsv.zst
-rw-r----- 1 root root 8 Nov 13 11:17 testdb@tt@@0.tsv.zst.idx
-rw-r----- 1 root root 583 Nov 13 11:17 testdb@tt.json
-rw-r----- 1 root root 19 Nov 13 11:17 testdb@tt_new@@0.tsv.zst
-rw-r----- 1 root root 8 Nov 13 11:17 testdb@tt_new@@0.tsv.zst.idx
-rw-r----- 1 root root 587 Nov 13 11:17 testdb@tt_new.json
-rw-r----- 1 root root 686 Nov 13 11:17 testdb@tt_new.sql
-rw-r----- 1 root root 674 Nov 13 11:17 testdb@tt.sql
-rw-r----- 1 root root 4344 Nov 13 11:17 @.users.sql
2. 准备恢复环境
- 目标MySQL实例:确保用于恢复的MySQL服务已启动并可以正常连接。它最好与源服务器版本一致或兼容,以避免潜在问题。
- 权限检查:用于执行恢复操作的MySQL账户需要具备足够的权限,例如 SELECT, INSERT, UPDATE, DELETE, CREATE, DROP, 甚至可能需要 RELOAD或 SUPER权限。
- 磁盘空间:确保目标实例的磁盘有足够空间容纳要恢复的数据。
- 决策:完全恢复还是部分恢复? 想清楚是需要恢复整个实例,还是只恢复其中的一个或多个特定数据库。这决定了后续使用的工具和命令。
## 说明:在导入数据之前,建议检查参数local_infile是否开启,如未开启,需要进行提前设置。
root@localhost:(none) 02:01:54 > show global variables like '%local_infile%';
+---------------+-------+
| Variable_name | Value |
+---------------+-------+
| local_infile | OFF |
+---------------+-------+
1 row in set (0.11 sec)
root@localhost:(none) 02:01:46 >set global local_infile=1;
Query OK, 0 rows affected (0.00 sec)
3. 恢复操作步骤
MySQL Shell工具软件进行备份,恢复时候也必须使用MySQL Shell进行恢复,这个是必须满足的基本条件。
恢复方式一:
在服务器上执行以下命令。请务必将 备份目录路径、用户名、密码、主机和 端口替换为您的实际信息。
mysqlsh -u root -p --host localhost --port 3306 --js
--进入 MySQL Shell 的 JavaScript 模式后,执行:
util.loadDump("/data/backup/full_mysqlshell_backup_20251113_103022", {
threads: 4, // 并行线程数,可调整
skipBinlog: false, // 如果恢复过程不想记录到二进制日志,可设为true
ignoreVersion: true, // 忽略MySQL版本差异警告(谨慎使用)
resetProgress: true // 如果重新开始一个恢复,重置进度
});
恢复方式二:
mysqlsh -u root -p -h localhost -P 3306 --js -e "util.loadDump('/data/backup/full_mysqlshell_backup_20251113_103022', {threads: 4, skipBinlog: false})"
4. 监控恢复过程
恢复过程中,util.loadDump会显示进度信息。您也可以在另一个会话中连接到MySQL,使用 sql模式查看正在创建的表或进程。

总结
该脚本提供了一个生产环境使用MySQL Shell 工具对 MySQL8.0版本进行逻辑备所需的完整步骤,包括错误处理、日志记录、自动清理和耗时统计以及最后的恢复步骤。数据库运维人员可以根据实际环境调整配置参数,特别是备份路径和保留天数设置等一些常用功能的设置。
想了解更多干货,可通过下方扫码关注

可扫码添加上智启元官方客服微信👇

17认证网








