## 引言

在生产环境中,对数据库进行定期备份是确保数据安全与系统稳定运行的关键步骤之一。本文将介绍一种基于 Shell 脚本的 MySQL 数据库备份方案,并结合 mysql_config_editor 工具实现安全性优化,以避免敏感信息的暴露。

## 目标

本文档旨在提供一个可靠的 MySQL 数据库备份解决方案,涵盖以下几个关键功能:

1. 自动化备份 MySQL 数据库,包括数据结构和数据内容。

2. 使用 gzip 压缩备份文件以节省存储空间。

3. 设置备份文件的保留时间,并自动清理过期备份。

4. 通过 mysql_config_editor 工具配置登录路径,提升数据库访问的安全性,避免在脚本中暴露数据库密码。

## 备份脚本

### 原始备份脚本:mysql_backup.sh

```bash

#!/bin/sh

# 数据库信息

DB_HOST=<db_host_ip>

DB_USER=<username>

DB_PASS=<password>

# 备份文件保留天数

retention_days=7

# 备份文件存储路径

BACKUP_BASE_DIR="/backup"

BACKUP_TABLE_STRUCTURE_DIR="${BACKUP_BASE_DIR}/table_structure"

BACKUP_DATA_DIR="${BACKUP_BASE_DIR}/data"

# 备份日期

DATE=$(date +%Y%m%d_%H%M%S)

# 判断备份文件存储路径是否存在

if [ ! -d ${BACKUP_BASE_DIR} ];then

# 若不存在,则创建目录

mkdir -p ${BACKUP_TABLE_STRUCTURE_DIR} ${BACKUP_DATA_DIR}

if [ $? -ne 0 ];then

echo "Error: Failed to create backup directories."

exit 1

fi

fi

# 获取所有数据库实例

DATABASES=$(mysql -h"${DB_HOST}" -u"${DB_USER}" -p"${DB_PASS}" -e "SHOW DATABASES;" | grep -Ev "(Database|information_schema|performance_schema|mysql|sys)")

echo "============ Start backup database ============" "${DATE}"

# 逐一备份数据库实例

for DB in ${DATABASES};do

if [[ -n "$DB" ]];then

echo "Start backup database: ${DB}"

# 备份数据库结构

mysqldump -h"${DB_HOST}" -u"${DB_USER}" -p"${DB_PASS}" --databases "${DB}" --opt --no-data --single-transaction | gzip > ${BACKUP_TABLE_STRUCTURE_DIR}/${DB}_${DATE}.nodata.sql.gz

if [ $? -ne 0 ]; then

echo "Backup database structure for ${DB} failed."

continue

fi

# 备份数据库结构和数据

mysqldump -h"${DB_HOST}" -u"${DB_USER}" -p"${DB_PASS}" --databases "${DB}" --single-transaction | gzip > ${BACKUP_DATA_DIR}/${DB}_${DATE}.sql.gz

if [ $? -ne 0 ];then

echo "Backup database: ${DB} failed."

else

echo "Backup database: ${DB} success."

fi

fi

done

echo "============ End backup database ============" "${DATE}"

# 删除过期的备份文件

echo "Delete ${retention_days}-day-old backups."

find "${BACKUP_TABLE_STRUCTURE_DIR}" -name "*.nodata.sql.gz" -type f -mtime +${retention_days} -exec rm -rf {} \; > /dev/null 2>&1

find "${BACKUP_DATA_DIR}" -name "*.sql.gz" -type f -mtime +${retention_days} -exec rm -rf {} \; > /dev/null 2>&1

echo "Delete ${retention_days}-day-old backups success."

```

> 参数解释:

> - --single-transaction: 由于 Percona-XtraDB-Cluster 的严格模式 (`pxc_strict_mode = ENFORCING`),它不允许使用 LOCK TABLES 语句进行备份。这导致 mysqldump 在执行过程中出现错误。此参数是为避免使用锁定表的操作,确保在集群环境中备份操作的顺利进行,这是在针对 Percona-XtraDB-Cluster 时的最佳实践。

> - grep -Ev "(Database|information_schema|performance_schema|mysql|sys)": 该命令用于过滤掉不需要备份的系统数据库,仅备份用户创建的数据库。

### 安全优化后的备份脚本

为提高数据库访问的安全性,我们可以使用 mysql_config_editor 工具配置登录路径,以避免在脚本中直接暴露数据库的用户名和密码。

- 详细操作参考:[提升数据库安全性:使用mysql_config_editor配置MySQL访问](https://www.xuefei.me/docs/mysql/security/mysql_config_editor)

优化之后的脚本如下:

```bash

#!/bin/sh

# 数据库登录路径

LOGIN_PATH="xxx"

# 备份文件保留天数

retention_days=7

# 备份文件存储路径

BACKUP_BASE_DIR="/dtd_bak/wejoy_demo/01-mysql-pxc"

BACKUP_TABLE_STRUCTURE_DIR="${BACKUP_BASE_DIR}/table_structure"

BACKUP_DATA_DIR="${BACKUP_BASE_DIR}/data"

# 备份日期

DATE=$(date +%Y%m%d_%H%M%S)

# 判断备份文件存储路径是否存在

if [ ! -d ${BACKUP_BASE_DIR} ];then

# Create it if it doesn't exist.

mkdir -p ${BACKUP_TABLE_STRUCTURE_DIR} ${BACKUP_DATA_DIR}

if [ $? -ne 0 ];then

echo "Error: Failed to create backup directories."

exit 1

fi

fi

# 获取所有数据库实例

DATABASES=$(mysql --login-path="${LOGIN_PATH}" -e "SHOW DATABASES;" | grep -Ev "(Database|information_schema|performance_schema|mysql|sys)")

echo "============ Start backup database ============" "${DATE}"

# 逐一备份数据库实例

for DB in ${DATABASES};do

if [[ -n "$DB" ]];then

echo "Start backup database: ${DB}"

# 备份数据库结构

mysqldump --login-path="${LOGIN_PATH}" --databases "${DB}" --opt --no-data --single-transaction | gzip > ${BACKUP_TABLE_STRUCTURE_DIR}/${DB}_${DATE}.nodata.sql.gz

if [ $? -ne 0 ]; then

echo "Backup database structure for ${DB} failed."

continue

fi

# 备份数据库结构和数据

mysqldump --login-path="${LOGIN_PATH}" --databases "${DB}" --single-transaction | gzip > ${BACKUP_DATA_DIR}/${DB}_${DATE}.sql.gz

if [ $? -ne 0 ];then

echo "Backup database: ${DB} failed."

else

echo "Backup database: ${DB} success."

fi

fi

done

echo "============ End backup database ============" "${DATE}"

# 删除过期的备份文件

echo "Delete ${retention_days}-day-old backups."

find "${BACKUP_TABLE_STRUCTURE_DIR}" -name "*.nodata.sql.gz" -type f -mtime +${retention_days} -exec rm -rf {} \; > /dev/null 2>&1

find "${BACKUP_DATA_DIR}" -name "*.sql.gz" -type f -mtime +${retention_days} -exec rm -rf {} \; > /dev/null 2>&1

echo "Delete ${retention_days}-day-old backups success."

```

> 参数解释:

> - 将脚本中原先使用的 -u${DB_USER} -p${DB_PASS} 替换为 --login-path="${LOGIN_PATH}"。

### 使用 mysql_config_editor 配置 MySQL 访问

使用 mysql_config_editor 工具可以将数据库的访问信息存储在加密文件中,避免直接在脚本中暴露密码。以下是配置方法:

运行以下命令来创建一个名为 backup_login 的登录路径:

```bash

mysql_config_editor set --login-path=backup_login --host=<db_host_ip> --user=<username> --password

```

输入密码后,登录信息将被加密存储。

在备份脚本中,替换数据库连接部分为:

```bash

mysql --login-path=backup_login

```

这样,您就可以在不暴露密码的情况下,安全地执行数据库备份操作。