MySQL8.0逻辑备份MySQLShell全备脚本17认证网

正规官方授权
更专业・更权威

MySQL8.0逻辑备份MySQLShell全备脚本

image.png

脚本功能

此脚本是专门用于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/
image.png
MySQLShell软件下载到本地服务器后,解压即可使用非常简单方便。

使用方法

  1. 保存脚本并赋予执行权限
[root@VM-8-4-opencloudos backup]# chmod +x mysqlshell_full_backup.sh
  1. 可选手动执行备份
[root@VM-8-4-opencloudos backup]# ./mysqlshell_full_backup.sh

image.png
tail -100 /data/backup/backup.log
image.png
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模式查看正在创建的表或进程。
image.png

总结

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

想了解更多干货,可通过下方扫码关注

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

未经允许不得转载:17认证网 » MySQL8.0逻辑备份MySQLShell全备脚本
分享到:0

评论已关闭。

400-663-6632
咨询老师
咨询老师
咨询老师