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

4231

积分

1

好友

586

主题
发表于 昨天 06:55 | 查看: 7| 回复: 0

虽然MongoDB的复制集架构极大地保证了数据的可用性,数据丢失的风险变得很低,但这绝不意味着我们可以忽视备份工作。就像给房子买了保险,并不代表不用防火一样,定期备份是守护数据资产的最后一道坚实防线。

为什么要进行MongoDB备份?

备份的核心目的主要有以下几点:

  • 防范硬件故障:磁盘损坏、服务器宕机等物理问题可能导致数据不可用。
  • 避免人为失误:误删数据、误执行破坏性命令是运维中常见的事故。
  • 实现时间点恢复:可以将数据回溯到过去的某个特定状态,用于审计或分析。
  • 满足合规要求:许多行业法规要求企业必须保留特定时期的数据快照。

MongoDB备份恢复工具箱

MongoDB提供了几套不同的备份恢复工具,它们各有侧重,适用于不同的场景。

逻辑备份:mongoexport / mongoimport

这对工具主要用于逻辑备份,类似于 MySQL 的 mysqldump,可以将数据导出为人类可读的 JSON 或 CSV 格式文件。

适用场景总结

  • 异构平台迁移:例如,将数据从 MySQL 迁移到 MongoDB,或者反向操作。
  • 跨大版本迁移:在不同大版本的 MongoDB 之间进行数据迁移(例如从 2.x 迁移到 3.x),当二进制格式(BSON)不兼容时,JSON格式是一个可靠的备选方案。

需要注意的是,mongoexport 只备份数据本身,不会备份索引、账户信息等其他元数据

物理备份:mongodump / mongorestore

这是 MongoDB 日常备份恢复中最常用的工具组。它们进行的是物理备份,导出的是二进制的 BSON 格式文件,备份和恢复速度通常更快,并且会包含集合的索引信息

mongodump 的工作原理是在运行时对数据库进行查询,然后将所有查到的文档写入磁盘。这带来一个特点:它产生的备份不一定是数据库的实时快照。如果在备份过程中持续有数据写入,那么备份文件可能无法完全等同于备份完成那一刻的数据库状态。

mongodump 虽然灵活,但在备份大量数据时可能会对线上服务的性能产生一定影响,并且其导出的数据只能代表一个“时间段”的状态,而非精确的“时间点”。

工具对比:如何选择?

  • 格式与可读性mongoexport 导出 JSON/CSV,可读性强但体积大;mongodump 导出 BSON,体积小但为二进制,几乎不可读。
  • 元数据mongodump 会包含索引信息,mongoexport 仅包含数据。
  • 版本兼容性:不同版本间的 BSON 格式可能有差异,因此跨版本的 mongodump/mongorestore 需谨慎并检查兼容性。此时,格式通用的 mongoexport/mongoimport 成为一个可行的选择。
  • 性能影响mongodump 在备份大量数据时对线上业务的影响通常比 mongoexport 要小。

简单来说,日常物理备份推荐使用 mongodump/mongorestore;需要进行跨数据库平台或特定格式的数据交换时,则使用 mongoexport/mongoimport

备份工具的安装

从 MongoDB 4.4 版本开始,数据库工具(包括 mongoexport, mongodump 等)已经从服务器包中分离,拥有独立的版本号。

下载链接

https://www.mongodb.com/try/download/shell

在 Rocky Linux 8 上安装示例

[root@Rocky8 ~]# wget https://fastdl.mongodb.org/tools/db/mongodb-database-tools-rhel80-x86_64-100.9.5.rpm
[root@Rocky8 ~]# yum -y install mongodb-database-tools-rhel80-x86_64-100.9.5.rpm
[root@Rocky8 ~]# rpm -ql mongodb-database-tools
/usr/bin/bsondump
/usr/bin/mongodump
/usr/bin/mongoexport
/usr/bin/mongofiles
/usr/bin/mongoimport
/usr/bin/mongorestore
/usr/bin/mongostat
/usr/bin/mongotop
...(其他输出省略)...

深入使用 mongoexport 与 mongoimport

导出工具:mongoexport

mongoexport 一次只能针对一个集合(表)进行导出,不支持整库所有表的批量导出。

官方文档https://www.mongodb.com/docs/database-tools/mongoexport/

基本参数说明

$ mongoexport --help
参数说明:
-h  # 数据库主机IP
-u  # 用户名
-p  # 密码
-d  # 数据库名
-c  # 集合名
-f  # 指定要导出的字段(列)
-o  # 输出文件名
-q  # 数据过滤条件(JSON格式查询)
--type=csv 或 --csv  # 指定导出为CSV格式(默认为JSON)
--authenticationDatabase <验证库>  # 指定用于身份验证的数据库

操作示例

  1. 导出为 JSON 格式

    # 导出 test 数据库的 vast 集合到文件
    mongoexport -d test -c vast -o /data/backup/vast.json
    
    # 带条件导出特定字段
    mongoexport -d test -c log -f uid,name -q '{"uid":3}' -o vast.json
  2. 导出为 CSV 格式

    # 必须使用 --type=csv 和 -f 指定字段
    mongoexport -d test -c vast2 --type=csv -f uid,name,age,date -o /data/backup/vast2.csv

实际导出过程与结果

[root@Rocky8 ~]# mongoexport -d test -c vast -o /data/backup/vast.json
2024-06-29T12:20:09.686+0800 connected to: mongodb://localhost/
2024-06-29T12:20:10.688+0800 [###.....................]  test.vast  88000/572239  (15.4%)
2024-06-29T12:20:11.690+0800 [########................]  test.vast  208000/572239  (36.3%)
2024-06-29T12:20:12.688+0800 [#############...........]  test.vast  328000/572239  (57.3%)
2024-06-29T12:20:13.688+0800 [###################.....]  test.vast  456000/572239  (79.7%)
2024-06-29T12:20:14.440+0800 [########################]  test.vast  572239/572239  (100.0%)
2024-06-29T12:20:14.440+0800 exported 572239 records

[root@Rocky8 ~]# head -n 3 /data/backup/vast.json
{"_id":{"$oid":"667ef3cd8467a66237990681"},"id":0,"name":"dinginx","age":25,"date":{"$date":"2024-06-28T17:33:01.225Z"}}
{"_id":{"$oid":"667ef3cd8467a66237990682"},"id":1,"name":"dinginx","age":25,"date":{"$date":"2024-06-28T17:33:01.244Z"}}
{"_id":{"$oid":"667ef3cd8467a66237990683"},"id":2,"name":"dinginx","age":25,"date":{"$date":"2024-06-28T17:33:01.253Z"}}

导入工具:mongoimport

官方文档https://www.mongodb.com/docs/database-tools/mongoimport/

基本参数说明

mongoimport --help
#参数说明:
-h  # 数据库主机IP
-u  # 用户名
-p  # 密码
-d  # 数据库名
-c  # 集合名
-f  # 指定要导入的字段(列),顺序需与文件对应
--type=csv  # 指定导入CSV格式文件(默认为JSON)
-j, --numInsertionWorkers=<number>  # 并发插入的Worker数量,默认为1,增加可提升导入速度
--headerline  # 指明CSV文件第一行是列名,导入时跳过

数据恢复示例

# 导入JSON格式数据到新集合 vast1
mongoimport -d test -c vast1 /data/backup/vast.json

# 导入带表头的标准CSV文件(使用--headerline自动识别列)
mongoimport -d test -c vast2 --type=csv --headerline /data/backup/vast2.csv

# 导入无表头的CSV文件(必须用-f指定字段名)
mongoimport -d test -c vast3 --type=csv -f uid,name,age,date /data/backup/vast2_no_header.csv

异构平台迁移实战案例

案例一:将 MySQL 数据迁移至 MongoDB

方法一:通过 SELECT ... INTO OUTFILE

# 1. 确保MySQL已开启安全文件写入路径(在my.cnf中配置secure-file-priv)
# 2. 从MySQL导出CSV数据(例如导出zabbix.events表)
mysql -e "SELECT * FROM zabbix.events INTO OUTFILE '/tmp/events.csv' FIELDS TERMINATED BY ',';"

# 3. (可选)获取表的列名,并添加到CSV文件第一行,或使用-f参数指定
mysql -e "SELECT GROUP_CONCAT(COLUMN_NAME) FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_SCHEMA='zabbix' AND TABLE_NAME='events';" > columns.txt

# 4. 导入到MongoDB
# 方法A:如果CSV已包含表头行
mongoimport -d test -c events --type=csv --headerline --file /tmp/events.csv
# 方法B:使用-f手动指定所有列名
mongoimport -d test -c events --type=csv -f eventid,source,object,objectid,clock,value,acknowledged,ns,name,severity --file /tmp/events.csv

方法二:通过 mysqldump 导出文本

# 1. 使用mysqldump导出为制表符分隔的文本
mysqldump hellodb students -T /data/mysql
# 会生成 students.sql(表结构)和 students.txt(数据)

# 2. 将制表符替换为逗号
sed -i.bak 's/\t/,/g' /data/mysql/students.txt

# 3. 导入到MongoDB
mongoimport -d test -c students --type=csv -f stuid,name,age,gender,classid,teacherid /data/mysql/students.txt

案例二:将 MongoDB 数据迁移至 MySQL

思路是先用 mongoexport 将数据导出为 CSV,然后在 MySQL 中通过 LOAD DATA INFILE 加载。

# 1. 从MongoDB导出为CSV(假设已导出为 /tmp/students_info.csv)
[root@rocky8 ~]# head /tmp/students_info.csv
1,Shi Zhongyu,22,M,2,3
2,Shi Potian,22,M,1,7
3,Xie Yanke,53,M,2,16
...

# 2. 在MySQL中创建结构相同的表并导入数据
mysql> USE hellodb;
mysql> CREATE TABLE students_info LIKE students; -- 复制表结构
mysql> LOAD DATA INFILE '/tmp/students_info.csv' INTO TABLE students_info
    -> FIELDS TERMINATED BY ',' OPTIONALLY ENCLOSED BY '"';

深入使用 mongodump 与 mongorestore

对于分片集群,备份原理与复制集类似,但有重要区别:

  1. 分别备份:需要为每个分片(Shard)和配置服务器(Config Server)分别执行备份。
  2. 一致性要求:要确保所有分片能恢复到同一个精确的时间点,保证分片间数据一致性。
  3. 暂停均衡器:备份前必须停止集群的平衡器(balancer),防止备份期间数据自动分片导致数据不一致或丢失。

备份工具:mongodump

官方文档https://www.mongodb.com/docs/database-tools/mongodump/

基本参数说明

mongodump --help
参数说明:
-h, --host # 数据库主机
-u, --username # 用户名
-p, --password # 密码
-d, --db # 数据库名
-c, --collection # 集合名
-o, --out # 输出目录
-q, --query # 导出数据的过滤条件(JSON格式)
-j, --numParallelCollections # 并行导出的集合数量,默认为4,可加快全库备份速度
--oplog # 备份的同时记录oplog,用于实现“热备份”和基于时间点的恢复(仅复制集模式有效)
--gzip # 在导出时直接进行压缩,节省磁盘空间

备份文件的规律

  • 导出的文件存放在以 -o 参数指定的目录下。
  • 每个数据库一个子目录。
  • 每个集合对应两个文件:.bson(数据文件)和 .metadata.json(元数据,包含索引信息等)。
  • 如果不指定数据库或集合,则导出所有数据。

恢复工具:mongorestore

官方文档https://www.mongodb.com/docs/database-tools/mongorestore/

关键参数说明

mongorestore --help
-h, --host # 数据库主机
-u, --username # 用户名
-p, --password # 密码
-d, --db # 恢复到哪个数据库(可与备份时的库名不同)
-c, --collection # 恢复到哪个集合
--authenticationDatabase # 验证库名
--gzip # 恢复压缩的备份文件
--drop # 恢复前先删除目标集合(**危险!请谨慎使用**)
--oplogReplay # 恢复数据后,重放备份中包含的oplog,使数据更接近备份结束点的状态
--oplogLimit <timestamp> # 重放oplog时,仅重放到指定的时间点(用于恢复误操作)

备份与恢复操作范例

# 1. 全库备份
mkdir -p /data/full
mongodump -o /data/full/
# 查看备份结构
ls /data/full/  # 输出: admin config dinginx test ...

# 2. 备份指定库
mongodump -d dinginx -o /data/dinginx_backup

# 3. 备份指定集合
mongodump -d test -c events -o /backup/events

# 4. 压缩备份(推荐)
mongodump -o /backup/full_gzip --gzip

# 5. 恢复全库备份
mongorestore /backup/full

# 6. 从压缩备份中恢复指定库到新库名
mongorestore -d test1 /backup/full_gzip/test --gzip

# 7. 恢复单个集合(需指定.bson文件路径)
mongorestore -d test -c vast1 --gzip /backup/full_gzip/test/vast.bson.gz

# 8. 覆盖式恢复(先删除已存在集合,再恢复)
mongorestore -d magedu --drop /backup/magedu

高级技巧:利用 Oplog 实现精确时间点恢复

什么是 Oplog?
Oplog(操作日志)是 MongoDB 复制集的核心组件,类似于 MySQL 的 binlog。它记录了所有更改数据库数据的操作(插入、更新、删除、DDL等),是一个固定大小的集合(capped collection),保存在 local 数据库的 oplog.rs 集合中。

Oplog 的关键特性

  • 幂等性:无论重放多少次,结果都相同。这是实现精确恢复的基础。
  • 时间窗口:由于大小固定,它只保留最近一段时间内的操作记录。
  • 热备份关键:配合 mongodump --oplog 选项,可以捕获备份过程中的数据变化,结合备份文件与 oplog,理论上可以将数据库恢复到备份结束后的任意时间点。

范例:模拟误删除并利用 Oplog 恢复

场景:每天凌晨3点进行全量备份。上午10点,dinginx 数据库下的 vast 表被误删除。需要恢复到误删前的状态。

恢复流程

  1. 停止应用写入,防止新数据覆盖 Oplog 时间窗口。
  2. 准备测试环境
  3. 恢复前一天的全量备份
  4. 截取全备之后到误删除时间点之间的 Oplog
  5. 在测试库上重放 Oplog,将数据恢复到误删前一刻。
  6. 验证无误后,将恢复出的表导出,再导入生产环境。

详细操作步骤

  1. 执行一次包含 Oplog 的完全备份(模拟日常备份)

    mkdir -p /data/backup/full/
    mongodump --oplog -o /data/backup/full/

    备份目录下会生成一个 oplog.bson 文件,记录了备份期间发生的操作。

  2. 模拟备份后的数据变化和误删除操作

    mongosh
    myrepl [direct: primary] dinginx> for (i=0;i<10 ;i++){ db.test.insert ( { "id" :i, "name" : "hang" , "age" : 18, "date" : new Date()})}
    myrepl [direct: primary] dinginx> db.test2.insert({name:"wang"})
    # 模拟上午10点误删除 vast 表
    myrepl [direct: primary] dinginx> db.vast.drop()
    true
  3. 备份当前的 Oplog(至关重要)

    mongodump -d local -c oplog.rs -o /data/backup/oplog_current/
  4. 找到误删除操作的时间戳

    mongosh
    myrepl:PRIMARY> use local
    myrepl:PRIMARY> db.oplog.rs.find({op:”c”, “o.drop”: “vast”}).pretty()
    # 查找输出中的 `ts` 字段,例如:
    # ts: Timestamp({ t: 1720706535, i: 1 })  # 记下这个值:1720706535:1
  5. 准备恢复用的备份文件

    # 用最新的oplog覆盖备份中的旧oplog
    cp /data/backup/oplog_current/local/oplog.rs.bson /data/backup/full/oplog.bson
  6. 执行基于时间点的恢复

    # --oplogReplay: 重放oplog
    # --oplogLimit “1720706535:1”: 只重放到误删除发生之前的时间点
    # --drop: 恢复前清空目标库(测试环境使用)
    mongorestore --oplogReplay --oplogLimit “1720706535:1” --drop /data/backup/full/
  7. 验证恢复结果

    mongosh
    myrepl [direct: primary] dinginx> show tables
    # 应该能看到 test, test2, vast 三个表都回来了
    myrepl [direct: primary] dinginx> db.vast.countDocuments()
    # 应该返回原有数据量(例如110)

通过以上步骤,我们成功地利用 Oplog 将数据库恢复到了误删除发生前的精确状态。这套方法充分展现了 MongoDB 在数据备份与恢复方面的强大能力,是每一位数据库管理员必须掌握的核心运维技能。希望这篇在 云栈社区 分享的详细指南能帮助你构建起更稳固的数据安全防线。




上一篇:基于Claude Code Hook实现AI编程时供应链安全实时拦截方案
下一篇:OpenAI联创Karpathy坦言编程范式剧变,AI时代开发者如何自处?
您需要登录后才可以回帖 登录 | 立即注册

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

GMT+8, 2026-3-10 09:16 , Processed in 0.531279 second(s), 42 queries , Gzip On.

Powered by Discuz! X3.5

© 2025-2026 云栈社区.

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