1. 背景与需求

  • 环境:CentOS 7.9, MongoDB 6.0.16 (Replica Set)。
  • 架构
    • 主节点 (Master): 192.168.1.20
    • 副节点 (Slave): 192.168.1.21
  • 认证方式:无账号密码,采用内网 IP 白名单限制。
  • 核心需求
    1. 每天自动备份指定的业务数据库(如 testdata)。
    2. 跳过 无价值且巨大的日志库(节省空间与时间)。
    3. 实现 双机热备:备份文件既保存在本地 (1.20),也同步传输一份到副机 (1.21) 的 /data/backup 目录。

2. 环境准备工作

2.1 安装 MongoDB Database Tools (主节点)

MongoDB 6.0+ 将 mongodump 等工具剥离了 Server 包,需单独安装。在 192.168.1.20 上执行:

# 检查是否已安装,若未安装执行以下命令
sudo yum install -y mongodb-database-tools

注:如果没有配置 yum 源,需先配置 /etc/yum.repos.d/mongodb-org-6.0.repo

2.2 创建备份目录 (两台机器)

确保两台机器都有存放备份的文件夹。

# 在 192.168.1.20 执行
mkdir -p /data/backup

# 在 192.168.1.21 执行
mkdir -p /data/backup

2.3 配置 SSH 免密登录 (关键)

为了让脚本自动将文件从 20 传到 21,必须配置 SSH 互信。

步骤 1:在 1.20 上生成密钥

ssh-keygen -t rsa
# 提示 "Enter file..." -> 直接回车
# 提示 "Enter passphrase" -> 直接回车(必须留空!)
# 提示 "Enter same passphrase again" -> 直接回车

步骤 2:将公钥发给 1.21

ssh-copy-id root@192.168.1.21
# 这里需要输入一次 1.21 的 root 密码

常见问题处理
如果报错 Permission denied,请登录 1.21 修改 /etc/ssh/sshd_config,确保 PasswordAuthentication yes,然后重启 sshd 服务,再重试上面的命令。

如果1.21是密钥验证,在1.20上查看密钥内容cat /root/.ssh/id_rsa.pub,在1.21上编辑并复制密钥到这里,vi /root/.ssh/authorized_keys

步骤 3:验证连接
在 1.20 上执行以下命令,若不需要密码直接输出时间,则配置成功:

ssh root@192.168.1.21 "date"

3. 编写备份脚本

此脚本专为“指定数据库”设计,会自动循环备份你需要的库,忽略日志库。

  • 脚本路径/opt/mongo_custom_backup.sh
  • 操作节点192.168.1.20

使用 vi /opt/mongo_custom_backup.sh 创建文件并写入:

#!/bin/bash

# ================= 配置区域 =================
# MongoDB 连接信息 (本地白名单模式)
DB_HOST="127.0.0.1"
DB_PORT="27017"

# 【关键配置】在这里列出所有需要备份的数据库名,用空格隔开
# 例如: "testdata admin config"
# 坚决不写那个巨大的日志库名
TARGET_DBS="testdata admin"

# 本地备份存储路径
LOCAL_BACKUP_DIR="/data/backup"
# 时间戳
DATE_STR=$(date +%Y%m%d_%H%M%S)

# 远程备份配置 (副机信息)
REMOTE_IP="192.168.1.21"
REMOTE_USER="root"
REMOTE_DIR="/data/backup"

# 保留最近多少天的备份
RETENTION_DAYS=7
# ===========================================

# 1. 检查本地目录
if [ ! -d "$LOCAL_BACKUP_DIR" ]; then
  mkdir -p "$LOCAL_BACKUP_DIR"
fi

echo "[$(date)] ====== 开始执行多库备份任务 ======"

# 2. 循环备份指定的数据库
for DB_NAME in $TARGET_DBS
do
    echo "[$(date)] 正在备份数据库: $DB_NAME ..."
  
    # 定义文件名: 库名_时间.gzip
    BACKUP_NAME="${DB_NAME}_${DATE_STR}.gzip"
  
    # 执行备份
    # 注意: 指定 --db 时无法使用 --oplog,这在跳过日志库的场景下是必须的妥协
    /usr/bin/mongodump \
      --host "$DB_HOST" \
      --port "$DB_PORT" \
      --db "$DB_NAME" \
      --gzip \
      --archive="${LOCAL_BACKUP_DIR}/${BACKUP_NAME}"
  
    if [ $? -eq 0 ]; then
        echo "[$(date)] 数据库 $DB_NAME 备份成功。"
    else
        echo "[$(date)] !!! 警告: 数据库 $DB_NAME 备份失败。"
    fi
done

# 3. 传输文件到远程主机 (192.168.1.21)
echo "[$(date)] 开始传输本次备份文件到远程主机 $REMOTE_IP ..."

# 传输所有包含本次时间戳的文件
scp ${LOCAL_BACKUP_DIR}/*_${DATE_STR}.gzip ${REMOTE_USER}@${REMOTE_IP}:${REMOTE_DIR}

if [ $? -eq 0 ]; then
  echo "[$(date)] 远程传输成功。"
else
  echo "[$(date)] 远程传输失败!请检查 SSH 连接。"
fi

# 4. 清理旧备份 (本地)
echo "[$(date)] 清理本地超过 $RETENTION_DAYS 天的旧文件..."
find "$LOCAL_BACKUP_DIR" -name "*.gzip" -type f -mtime +$RETENTION_DAYS -delete

# 5. 清理旧备份 (远程)
# 通过 SSH 命令清理副机上的过期文件,防止副机磁盘满
echo "[$(date)] 清理远程超过 $RETENTION_DAYS 天的旧文件..."
ssh ${REMOTE_USER}@${REMOTE_IP} "find ${REMOTE_DIR} -name '*.gzip' -type f -mtime +$RETENTION_DAYS -delete"

echo "[$(date)] ====== 任务全部完成 ======"

赋予执行权限

chmod +x /opt/mongo_custom_backup.sh

4. 设置定时任务 (Crontab)

建议在业务低峰期(如凌晨 2 点)执行。

在 1.20 上输入 crontab -e,添加以下内容:

# 每天凌晨 02:00 执行 MongoDB 备份,日志记录到 /tmp
0 2 * * * /opt/mongo_custom_backup.sh > /tmp/mongo_backup.log 2>&1

5. 数据恢复指南

当发生意外需要恢复数据时,使用 mongorestore

场景:恢复 testdata 库到最新备份

假设你要恢复 20250101 的备份文件。

# 1. 解压并恢复 testdata 库
mongorestore \
  --host 127.0.0.1 \
  --port 27017 \
  --gzip \
  --archive=/data/backup/testdata_20250101_020000.gzip \
  --nsInclude="testdata.*"
  • --gzip --archive: 指定读取压缩归档文件。
  • --nsInclude="testdata.*": 明确指定恢复该库下的所有集合(通常不需要,但在单库恢复时加上更保险)。

6. 重要提示与风险告知

  1. 关于一致性 (Consistency)
    由于我们为了跳过日志库使用了 --db 参数,导致无法开启 --oplog。这意味着备份不是“严格的时间点快照”。

    • 缓解建议:只要你在凌晨业务写入量极低的时候备份,这个风险是可以忽略的。
  2. 关于安全性 (Security)
    当前使用了“无账号密码 + 白名单”模式。请务必确保服务器防火墙(firewalld/iptables)已配置好,只允许可信 IP 访问 27017 端口。如果内网有其他不可信机器,该配置存在安全隐患。

  3. 监控
    建议定期(如每周)手动检查一次 /data/backup 目录,确认文件是否正常生成,文件大小是否合理(如果不为 0,说明有数据)。