找回密码
立即注册
搜索
热搜: Java Python Linux Go
发回帖 发新帖

290

积分

0

好友

38

主题
发表于 3 天前 | 查看: 5| 回复: 0

本文提供了一个专为数据库/中间件 MySQL 8.0设计的逻辑备份Shell脚本,它使用MySQL Shell的util.dumpInstance工具执行实例级全量备份,是替代传统mysqldump的现代化方案。脚本集成了错误处理、日志记录、空间检查和自动清理等生产级功能。

脚本功能

此脚本用于MySQL 8.0的逻辑备份,通过MySQL Shell备份数据库实例的所有对象,实现实例级别的完整备份。

脚本内容

脚本名称为 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
  • 关键参数说明

    备份命令中的核心参数构建如下:

    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 选项。

    准备工作

    MySQL数据库软件本身不包含MySQL Shell,需要单独下载安装。您可以从 MySQL官网 下载对应版本,解压后即可使用。

    MySQL Shell下载页面

    使用方法

    1. 保存脚本并赋予执行权限
    chmod +x mysqlshell_full_backup.sh
    2. 手动执行备份
    ./mysqlshell_full_backup.sh

    手动执行备份

    执行后可以查看日志:

    tail -100 /data/backup/backup.log

    查看备份日志

    3. 配置定时任务(例如每日凌晨1点执行)

    编辑crontab (crontab -e),添加以下内容:

    0 1 * * * /path/to/mysqlshell_full_backup.sh

    数据恢复指南

    使用MySQL Shell进行的备份,恢复时也必须使用MySQL Shell工具。

    1. 确认备份文件完整性

    恢复前,请检查备份目录是否包含 @.done.json 文件及各数据库的 .tsv.zst.sql 等文件。

    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
    ...(其他文件列表)
    2. 准备恢复环境
    • 目标实例:确保MySQL服务已启动且版本兼容。
    • 权限:恢复账户需具备足够权限(如CREATE, DROP, INSERT等)。
    • 空间:确保目标磁盘有足够空间。
    • 参数设置:建议开启 local_infile 参数。
      SET GLOBAL local_infile=1;
    3. 执行恢复操作

    恢复方式一(交互式)

    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,查看正在创建的对象。 恢复过程监控

    总结

    本脚本提供了一个用于生产环境的、完整的MySQL 8.0逻辑备份与恢复运维/DevOps解决方案。它基于MySQL Shell的 util.dumpInstance 工具,具备错误处理、日志记录、自动清理和耗时统计等实用功能。数据库管理员可根据实际环境灵活调整备份路径、保留天数及并行度等参数,并通过详细的恢复步骤确保数据可可靠回迁。




    上一篇:Qt QPainter 实战指南:巧用 QPen+QBrush 实现渐变边框与炫彩文字
    下一篇:货拉拉RAG知识库优化实战:基于LLM的意图清洗与避坑指南
    您需要登录后才可以回帖 登录 | 立即注册

    手机版|小黑屋|网站地图|云栈社区(YunPan.Plus) ( 苏ICP备2022046150号-2 )

    GMT+8, 2025-12-7 01:53 , Processed in 0.121101 second(s), 38 queries , Gzip On.

    Powered by Discuz! X3.5

    © 2025-2025 CloudStack.

    快速回复 返回顶部 返回列表