Mysql-Linux安装与备份

今天在检索MySQL时,看到了MySQL一种比较优秀的一种数据备份恢复方案,特此小计一下。

#!/bin/bash

#函数返回非零,程序立即终止
set -e

script_name=$(basename "$0")

# 函数:询问用户输入,附带默认值提示
# 使用示例:
# 用户输入的名字,没有默认值
#name=$(ask_for_input "Please enter your name")
#
# 用户输入的年龄,带有默认值
#age=$(ask_for_input "Please enter your age" "30")
user_input() {
    # $1 是提示信息
    # $2 是默认值
    local prompt="$1"
    local default_value="$2"
    local response

    # 打印提示信息,如果提供了默认值,则显示在提示之后
    if [ -n "$default_value" ]; then
        read -p "$prompt [$default_value]: " response
    else
        read -p "$prompt: " response
    fi

    # 如果用户没有输入任何内容,并且提供了默认值,则使用默认值
    if [ -z "$response" ] && [ -n "$default_value" ]; then
        response="$default_value"
    fi

    # 输出用户的输入或默认值
    echo "$response"
}

# 确保脚本以root权限运行
is_root() {
	if [ "$(id -u)" -ne 0 ]; then
		echo "This script must be run as root. Please use sudo."
		return 1 #需要Root用户权限
	fi
}


# 函数:下载MySQL
download_mysql() {
	# 配置
	MYSQL_VERSION=$(user_input "Please enter MySQL version" "8.0.36")
	DOWNLOAD_URL="https://dev.mysql.com/get/Downloads/MySQL-${MYSQL_VERSION%.*}/mysql-${MYSQL_VERSION}-linux-glibc2.12-x86_64.tar.gz"

    echo "Downloading MySQL version $MYSQL_VERSION..."
    wget "$DOWNLOAD_URL" -O /tmp/mysql-${MYSQL_VERSION}.tar.gz
    if [ $? -ne 0 ]; then
        echo "Failed to download MySQL."
        return -1 #MySQL下载失败
    fi
}

# 函数:安装MySQL
install_mysql() {

	download_mysql

    echo "Installing MySQL version $MYSQL_VERSION..."

    # 解压tar.gz包
    tar -xzf /tmp/mysql-${MYSQL_VERSION}.tar.gz -C /usr/local/src

    # 移动到合适的目录
    mv /usr/local/src/mysql-${MYSQL_VERSION} /usr/local/mysql

    # 创建软链接
    ln -s /usr/local/mysql/bin/* /usr/bin/

    # 配置环境变量(示例:添加到当前用户的.bashrc)
    echo 'export PATH=$PATH:/usr/local/mysql/bin' >> ~/.bashrc
    source ~/.bashrc

    # 初始化MySQL
    /usr/local/mysql/bin/mysqld --initialize --user=mysql --basedir=/usr/local/mysql --datadir=/usr/local/mysql/data

    # 配置MySQL服务器
    /usr/local/mysql/bin/mysqld --daemonize --user=mysql --basedir=/usr/local/mysql --datadir=/usr/local/mysql/data --pid-file=/usr/local/mysql/mysql.pid

    # 安全配置
    /usr/local/mysql/bin/mysql_secure_installation

    echo "MySQL installation successful."
}

# 函数:更新MySQL
update_mysql() {
    echo "Updating MySQL..."

    # 停止MySQL服务
    service mysql stop

    # 重复安装步骤
    install_mysql

    # 启动MySQL服务
    service mysql start

    echo "MySQL updated successfully."
}

ENV_PATH="~/.mysql.env"

set_env() {
	# 配置
	MYSQL_USER=$(user_input "Please enter your user" "mysql")
	MYSQL_PASS=$(user_input "Please enter your password" "root")
	RESTORE_DB=$(user_input "Please enter default database" "")
	BACKUP_BASE_DIR=$(user_input "Please enter backup base dir" "/backup")
	FULL_BACKUP_DIR="$BACKUP_BASE_DIR/full"
	INCREMENTAL_BACKUP_DIR="$BACKUP_BASE_DIR/incremental"
	LAST_POSITION_FILE="$INCREMENTAL_BACKUP_DIR/last_position.txt"
	save_env > $ENV_PATH
}

#保存环境变量
save_env() {
	cat <<EOF
MYSQL_USER="$MYSQL_USER"
MYSQL_PASS="$MYSQL_PASS"
RESTORE_DB="$RESTORE_DB"
BACKUP_BASE_DIR="$BACKUP_BASE_DIR"
FULL_BACKUP_DIR="$FULL_BACKUP_DIR"
INCREMENTAL_BACKUP_DIR="$INCREMENTAL_BACKUP_DIR"
LAST_POSITION_FILE="$LAST_POSITION_FILE"
EOF
}

#加载.env文件中的环境变量
reload_env () {
	# 加载.env文件中的环境变量
	if [ -f $ENV_PATH ]; then
		source ./.env
	else
		set_env
	fi
}

# 创建备份目录
create_backup_directories() {
    echo "Creating backup directories if not exist..."
    mkdir -p "$FULL_BACKUP_DIR"
    mkdir -p "$INCREMENTAL_BACKUP_DIR"
}

# 全量备份函数
full_backup() {
    create_backup_directories
    local backup_filename="$RESTORE_DB_$(date +%Y%m%d%H%M%S).sql.gz"
    echo "Starting full backup..."
    mysqldump -u "$MYSQL_USER" -p"$MYSQL_PASS" --all-databases --single-transaction | gzip > "$FULL_BACKUP_DIR/$backup_filename"
    if [ $? -eq 0 ]; then
        echo "Full backup successful: $backup_filename"
    else
        echo "Full backup failed."
        exit 1
    fi
}

# 增量备份函数
incremental_backup() {
    create_backup_directories
    local current_binlog_file
    local current_binlog_pos

    if [ -f "$LAST_POSITION_FILE" ]; then
        current_binlog_file=$(head -n 1 "$LAST_POSITION_FILE")
        current_binlog_pos=$(tail -n 1 "$LAST_POSITION_FILE")
    else
        current_binlog_file=$(mysql -u "$MYSQL_USER" -p"$MYSQL_PASS" -e "SHOW MASTER STATUS;" | grep -m 1 file | awk '{print $2}')
        current_binlog_pos=4
    fi

    echo "Starting incremental backup from position $current_binlog_pos in file $current_binlog_file..."
    mysqlbinlog --start-position="$current_binlog_pos" "$current_binlog_file" | mysql -u "$MYSQL_USER" -p"$MYSQL_PASS"

    local new_binlog_pos=$(mysql -u "$MYSQL_USER" -p"$MYSQL_PASS" -e "SHOW MASTER STATUS\G" | grep -m 1 'Position' | awk '{print $3}')
    echo "$current_binlog_file:$new_binlog_pos" > "$LAST_POSITION_FILE"
}

# 数据恢复函数
restore_data() {
    local restore_time=$1
    local full_backup_file
    local incremental_files=($(ls -t "$FULL_BACKUP_DIR"/*.sql.gz))

    if [ -z "$restore_time" ]; then
        echo "Error: No restore time provided."
        exit 1
    fi

    full_backup_file=${incremental_files[0]}
    if [ ! -f "$FULL_BACKUP_DIR/$full_backup_file" ]; then
        echo "Error: Full backup file does not exist."
        exit 1
    fi

    echo "Restoring from full backup: $full_backup_file"
    gzip -cd "$FULL_BACKUP_DIR/$full_backup_file" | mysql -u "$MYSQL_USER" -p"$MYSQL_PASS" "$RESTORE_DB"

    echo "Applying incremental backups up to $restore_time..."
    local last_file=""
    for file in $(ls -t "$INCREMENTAL_BACKUP_DIR"/*); do
        file_name=$(basename "$file")
        if [[ $file_name < "$restore_time" ]]; then
            mysqlbinlog "$file" | mysql -u "$MYSQL_USER" -p"$MYSQL_PASS" "$RESTORE_DB"
            last_file="$file"
        else
            break
        fi
    done

    if [ -n "$last_file" ]; then
        echo "Updating last binlog position to $(basename "$last_file")."
        echo "$(basename "$last_file")" > "$LAST_POSITION_FILE"
    fi

    echo "Restore complete."
}

# 函数:检查是否已设置定时任务
check_cron_jobs() {
	script_name
    local full_cron_exists=$(crontab -l | grep -F "$script_name full" | wc -l)
    local incremental_cron_exists=$(crontab -l | grep -F "$script_name incremental" | wc -l)

    if [ "$full_cron_exists" -gt 0 ] && [ "$incremental_cron_exists" -gt 0 ]; then
        echo "Cron jobs for full and incremental backups already exist."
        return 0
    else
        return 1
    fi
}

# 函数:设置定时任务
setup_cron_jobs() {
    # 询问用户备份频率
    local full_freq=$(ask_for_input "Please enter full backup frequency (days, e.g., '1' for daily)" "1")
    local incremental_freq=$(ask_for_input "Please enter incremental backup frequency (hours, e.g., '1' for hourly)" "1")

    # 删除现有的备份相关的cron任务
    crontab -l | grep -v "$0" | crontab -

    # 添加新的备份任务
    # 假设full_backup.sh和incremental_backup.sh是备份脚本的文件名
    (crontab -l 2>/dev/null; echo "0 */${full_freq} * * * $0 full") | crontab -
    (crontab -l 2>/dev/null; echo "0 * * * * $0 incremental") | crontab -

    echo "Cron jobs for full and incremental backups have been set."
}

# 
init_mysql() {
    # 保存环境变量到.mysql.env
    save_env > "$ENV_PATH"

    # 设置定时任务
    if ! check_cron_jobs; then
        setup_cron_jobs
    else
        echo "Existing cron jobs found. No changes made."
    fi

}

# 主函数,根据命令行参数调用相应的备份或恢复函数
main() {
    if [ $# -eq 0 ]; then
        echo "Usage: $0 {install|update|initialize|full|incremental|restore}"
        exit 1
    fi
	
	reload_env

    case "$1" in
		install)
            install_mysql
            ;;
		update)
            update_mysql
            ;;
		initialize)
            init_mysql
            ;;
        full)
            full_backup
            ;;
        incremental)
            if [ -z "$2" ]; then
                echo "Cron job mode: running incremental backup."
                incremental_backup
            else
                echo "Error: Unexpected argument for incremental."
                exit 1
            fi
            ;;
        restore)
            if [ -z "$2" ]; then
                echo "Error: Restore time not provided."
                exit 1
            else
                restore_data "$2"
            fi
            ;;
        *)
            echo "Error: Invalid command. Use 'full', 'incremental', or 'restore'."
            exit 1
            ;;
    esac
}

# 执行主函数,并传递所有命令行参数
main "$@"

注: 上述脚本仍未测试,请使用需谨慎!谨慎!再谨慎!
有问题请留言说明,谢谢了~


Mysql-Linux安装与备份
https://blog.cikaros.top/doc/ecdc8312.html
作者
Cikaros
发布于
2024年6月19日
许可协议