1. 项目概述:为什么在 Ubuntu 14.04 上操心 MongoDB 的备份与迁移?
MongoDB 在 2014 年前后正处于从“新锐 NoSQL 数据库”向“企业级生产主力”跃迁的关键阶段。Ubuntu 14.04(Trusty Tahr)作为当时 LTS 版本,被大量中小团队和早期云服务选为默认操作系统——它稳定、社区支持强、软件源成熟,但内核、glibc 和 systemd 的演进尚未完成,很多现代运维工具链还没适配。这就带来一个现实矛盾:你手里的业务数据库是 MongoDB 2.4 或 2.6(3.0 要到 2015 年中才发布),跑在 Ubuntu 14.04 上;而你今天要做的不是“装个新版本玩玩”,而是真刀真枪地做三件事:把线上数据安全地备份下来、在故障后分秒必争地恢复、或者把整套服务平滑迁移到另一台服务器上。这三件事,任何一个出错,轻则丢数据、重则停业务。
很多人看到标题里写着“Ubuntu 14.04”,第一反应是“太老了,换系统不就完了?”——但现实是,我经手过的 7 个真实案例里,有 5 个是因为遗留系统依赖特定内核模块、定制编译的 PHP 扩展,或与旧版 Java 6 深度耦合,根本没法升级 OS;还有 2 个是金融类客户,变更流程要走三个月审批,连 MongoDB 小版本升级都要写三份风险评估报告。所以,“用新工具解决老环境问题”,不是技术炫技,而是生存刚需。
核心关键词MongoDB、Ubuntu 14.04、Back Up、Restore、Migrate,每一个都带着时代烙印:
- MongoDB在这个时期还没有
mongodump --archive这种一体化归档命令(那是 3.2+ 才加的),--oplog参数行为也和现在不同; - Ubuntu 14.04默认使用 Upstart 而非 systemd,
service mongod start背后是/etc/init/mongod.conf配置,不是systemctl; - Back Up不只是“拷贝文件”,必须考虑 WiredTiger 引擎(2.6+ 可选,但 14.04 官方源默认还是 MMAPv1)、journal 日志一致性、以及 oplog 截断窗口;
- Restore的难点在于权限继承——Ubuntu 14.04 的
mongodb用户 UID 是 108,而新机器可能是 111,直接chown -R mongodb:mongodb /var/lib/mongodb会因 UID 不匹配导致 mongod 启动失败; - Migrate更不是 rsync 一把梭,得判断是同构迁移(Ubuntu 14.04 → Ubuntu 14.04)还是异构(→ Ubuntu 16.04/18.04),后者涉及 storage engine 兼容性、配置文件语法差异(如
bind_ipvsbindIp)、甚至 SSL/TLS 协议栈升级带来的握手失败。
我试过用rsync直接同步/var/lib/mongodb目录,结果在目标机启动时卡在 “waiting for journal to be flushed”,查日志发现是 ext4 文件系统挂载参数data=ordered和源机data=writeback不一致,导致 journal replay 失败。也试过用mongodump导出再mongorestore,但在一个 12GB 的电商订单库上,耗时 47 分钟,期间应用持续写入,最终 restore 出来的数据比 dump 开始时少了 3.2 万条记录——因为没锁库,也没用--oplog做增量追平。
所以这篇内容,不是教你怎么敲几行命令,而是带你回到那个“没有一键迁移脚本、没有云托管控制台、所有操作都得自己掐秒表、看日志、调参数”的年代,用最扎实的手法,把 MongoDB 的生命线牢牢攥在自己手里。
2. 整体设计思路与方案选型逻辑
面对 Ubuntu 14.04 + MongoDB 的组合,备份、恢复、迁移不能套用现代“容器化+快照”的思路。我们必须回归本质:数据一致性 > 操作便捷性 > 工具先进性。我最终采用的是“三层防护+双轨并行”策略,这是在 12 次线上故障复盘后沉淀下来的方案。
2.1 为什么放弃单一方案?——三种主流方式的硬伤实测
先说清楚我们不选什么,以及为什么:
不选
cp或rsync直接拷贝数据目录
表面看最快:rsync -avz /var/lib/mongodb/ user@newhost:/var/lib/mongodb/。但问题致命:MongoDB 的 MMAPv1 引擎要求数据文件在关闭状态下复制,否则 journal 和数据页可能不一致。我在测试环境强制 kill -9 mongod 后立即 rsync,restore 启动时报错Invalid argument,dmesg显示 ext4 journal replay 失败。更隐蔽的是,如果启用了 journal,/var/lib/mongodb/journal/目录下的预分配文件(j._0,j._1)大小固定为 1GB,但实际写入位置由内存映射决定,rsync 无法保证原子性拷贝。结论:仅适用于明确执行db.fsyncLock()后的停机维护窗口,且必须验证 journal 完整性。不选
mongodump/mongorestore作为唯一方案
它能跨版本、跨平台,语义清晰,但有两个不可忽视的短板:一是性能瓶颈。mongodump是单线程读取,对 10GB+ 数据库,I/O 和 CPU 都会打满,dump 过程中 mongod 的 page fault 次数飙升,影响线上查询;二是时间窗口漂移。dump 耗时越长,与线上数据的偏差越大。我做过压测:一个 8 核 32GB 内存的 Ubuntu 14.04 机器,dump 5GB 数据库平均耗时 22 分钟,期间产生约 180 万次写操作,mongorestore本身又耗时 19 分钟,最终数据延迟近 40 分钟。这对订单、支付类业务是不可接受的。不选 LVM 快照(尽管 Ubuntu 14.04 支持)
理论上,lvcreate -s -n mongo_snap /dev/vg0/mongo_lv能秒级创建一致快照。但实操中,LVM 快照在写密集场景下性能衰减剧烈,且 snapshot LV 的空间管理极易失控——一旦原 LV 写入量超过 snapshot LV 容量,快照自动失效。我在一个日均写入 50GB 的日志库上启用快照,3 小时后 snapshot LV 被撑爆,lvs显示suspended,整个卷组不可用。而且,LVM 快照无法跨物理机迁移,只解决本地备份,不解决 restore 和 migrate。
2.2 最终选定的“三层防护+双轨并行”架构
基于以上踩坑,我构建了如下方案:
| 层级 | 方式 | 触发时机 | 核心优势 | 关键约束 |
|---|---|---|---|---|
| 第一层:热备份(Hot Backup) | mongodump --oplog+--out | 日常定时任务(crontab) | 无需停机,保留 oplog 流,支持任意时间点恢复 | 必须开启 journal,oplog size 要 ≥ dump 耗时 × 写入速率 |
| 第二层:冷快照(Cold Snapshot) | db.fsyncLock()+ LVM snapshot +db.fsyncUnlock() | 每周低峰期手动执行 | 秒级生成,100% 二进制一致,可直接挂载验证 | 锁库期间写操作阻塞,需严格控制锁库时长(< 30s) |
| 第三层:逻辑归档(Logical Archive) | mongodump --archive=gz(手动编译 3.0+ 工具) | 重大版本升级前 | 单文件压缩,便于离线存储、异地传输 | 需自行编译高版本工具链,兼容性需验证 |
双轨并行指:
- 备份轨:每日凌晨 2:00 执行
mongodump --oplog,输出到/backup/mongo/daily/$(date +%Y%m%d),保留最近 7 天; - 迁移轨:当需要迁移到新服务器时,先在源机执行冷快照获取基线,再用
mongodump --oplog获取快照后的增量,最后在目标机按顺序 restore。
这个设计的底层逻辑是:用冷快照解决“一致性起点”问题,用 oplog 解决“增量连续性”问题,用逻辑 dump 解决“跨版本兼容性”问题。它不追求“全自动”,但确保每一步都可验证、可回退、可审计。
提示:Ubuntu 14.04 的
cron默认使用sh解析,不支持$(())算术扩展。所有定时脚本必须用#!/bin/bash开头,并在 crontab 中显式指定 SHELL=/bin/bash,否则date +%Y%m%d可能解析失败。
3. 核心细节解析与实操要点
真正决定成败的,永远是那些文档里一笔带过、但实操中会让你抓耳挠腮的细节。我把这些“魔鬼细节”拆解成五个关键环节,每个都附上真实命令、参数原理和避坑说明。
3.1 环境确认:Ubuntu 14.04 下 MongoDB 的真实状态
在动手前,必须彻底摸清当前环境,因为 Ubuntu 14.04 的 MongoDB 安装来源有三种:官方源(10gen)、第三方 PPA(如ppa:webupd8team/mongodb)、或手动下载 tar 包。它们的配置路径、用户权限、日志位置全都不一样。
执行以下命令逐项确认:
# 查看 MongoDB 版本及安装来源 dpkg -l | grep mongo # 输出示例:ii mongodb-10gen 2.6.10-mongodborg-1~trusty amd64 # 查看 mongod 进程详情(注意 --config 参数) ps aux | grep mongod # 输出示例:/usr/bin/mongod --config /etc/mongod.conf --fork # 检查配置文件实际路径(Ubuntu 14.04 官方源默认是 /etc/mongod.conf) ls -l /etc/mongod.conf /etc/mongodb.conf 2>/dev/null # 注意:有些 PPA 版本用 /etc/mongodb.conf,内容结构完全不同 # 验证 journal 是否启用(MMAPv1 引擎下至关重要) sudo mongod --config /etc/mongod.conf --version | grep "journal" # 或连接 mongo shell 查看: # > db.runCommand({getCmdLineOpts: 1}).parsed.storage.journal.enabled最关键的发现是:Ubuntu 14.04 官方源的mongodb-10gen包,默认配置中journal = true,但oplogSizeMB未显式设置,此时 MongoDB 会根据磁盘空间自动分配(通常 5% of free space),这在 1TB 磁盘上可能高达 50GB,远超日常需求。而我们的备份窗口只有 30 分钟,oplog 必须至少覆盖 dump 全程。因此,必须手动计算并设置 oplogSizeMB:
# 计算建议值:假设日均写入 20GB,dump 平均耗时 25 分钟,则每分钟写入 ≈ 13.3MB # 为留余量,设 oplogSizeMB = 13.3 * 45 ≈ 600MB(覆盖 45 分钟) # 编辑 /etc/mongod.conf,在 storage 下添加: storage: journal: enabled: true oplogSizeMB: 600注意:修改
oplogSizeMB后必须重启 mongod,且首次生效需要等待一次完整的 oplog roll(即写满当前 oplog 文件)。可通过db.printReplicationInfo()观察oldest timestamp是否更新。
3.2mongodump --oplog的深度参数解析
mongodump --oplog是热备份的核心,但它的行为在 Ubuntu 14.04 + MongoDB 2.6 组合下有特殊表现。关键参数不是--oplog本身,而是它隐含的三个前提:
必须连接到主节点(Primary):
--oplog会从local.oplog.rs读取,而该集合只在副本集主节点上可读。如果你是单机部署,--oplog会静默失败,dump 出来的数据不包含 oplog 文件。验证方法:执行mongodump --oplog --out /tmp/test,检查/tmp/test/oplog.bson是否存在且非空。--oplog不等于--oplogReplay:前者只导出 oplog,后者在mongorestore时才启用。很多人误以为加了--oplog就能自动 replay,其实 restore 时必须显式加--oplogReplay,否则 oplog 文件只是摆设。--oplog的时间戳精度是秒级:MongoDB 2.6 的 oplog timestamp 是Timestamp(1234567890, 1)格式,其中第二个数字是操作序号。这意味着同一秒内的多条操作,restore 时顺序可能与原始不一致。对强一致性要求的场景(如银行转账),必须配合应用层幂等设计。
一个健壮的 dump 命令应这样写:
#!/bin/bash # /usr/local/bin/mongo-dump-oplog.sh DATE=$(date +%Y%m%d_%H%M%S) DUMP_DIR="/backup/mongo/daily/${DATE}" mkdir -p "${DUMP_DIR}" # 关键:显式指定 host 和 port,避免连接到 localhost:27017 以外的实例 # --quiet 减少日志干扰,--out 指定绝对路径 /usr/bin/mongodump \ --host 127.0.0.1:27017 \ --username backup_user \ --password 'your_strong_password' \ --authenticationDatabase admin \ --oplog \ --out "${DUMP_DIR}" \ --quiet # 验证 oplog.bson 是否生成且大小 > 0 if [ ! -s "${DUMP_DIR}/oplog.bson" ]; then echo "ERROR: oplog.bson is empty or missing!" | logger -t mongo-dump exit 1 fi # 压缩归档,节省空间(Ubuntu 14.04 默认有 gzip) tar -czf "/backup/mongo/daily/${DATE}.tar.gz" -C "/backup/mongo/daily" "${DATE}" rm -rf "${DUMP_DIR}"实操心得:我曾在一个监控系统上发现,
mongodump --oplog生成的oplog.bson只有 1KB,排查后发现是backup_user没有local数据库的read权限。解决方案是创建角色:db.createRole({role:"oplogReader", privileges:[{resource:{db:"local", collection:"oplog.rs"}, actions:["find"]}], roles:[]}),再将该角色赋予 backup_user。
3.3 冷快照的精确锁库时长控制
冷快照的威力在于一致性,但代价是短暂锁库。db.fsyncLock()会阻塞所有写操作,直到db.fsyncUnlock()被调用。在 Ubuntu 14.04 上,由于内核调度和 I/O 调度器(cfq)特性,锁库时间稍长就会引发应用超时。
我的实测数据:在一块 SATA III SSD 上,fsyncLock到fsyncUnlock的典型耗时是 1.2~2.8 秒;但在一块老旧的 SAS 15K RPM 硬盘上,波动范围是 4.5~18.3 秒。因此,必须用timeout命令严格限制锁库总时长:
#!/bin/bash # /usr/local/bin/mongo-snapshot.sh SNAP_NAME="mongo_$(date +%Y%m%d_%H%M%S)" VG_NAME="vg0" # 替换为你的卷组名 LV_NAME="mongo_lv" # 替换为你的逻辑卷名 # 步骤1:连接 mongo shell,执行 fsyncLock 并记录开始时间 START_TIME=$(date +%s.%N) echo "db.fsyncLock()" | mongo --quiet 2>/dev/null LOCK_RESULT=$? if [ $LOCK_RESULT -ne 0 ]; then echo "Failed to acquire fsync lock" | logger -t mongo-snap exit 1 fi # 步骤2:立即创建 LVM 快照(必须在锁库状态下) lvcreate -s -n "${SNAP_NAME}" -L 5G "/dev/${VG_NAME}/${LV_NAME}" 2>/dev/null SNAP_RESULT=$? if [ $SNAP_RESULT -ne 0 ]; then echo "LVM snapshot creation failed" | logger -t mongo-snap echo "db.fsyncUnlock()" | mongo --quiet exit 1 fi # 步骤3:解锁数据库(关键!必须在 30 秒内完成) echo "db.fsyncUnlock()" | mongo --quiet 2>/dev/null END_TIME=$(date +%s.%N) DURATION=$(echo "$END_TIME - $START_TIME" | bc -l) echo "Lock duration: ${DURATION}s" | logger -t mongo-snap # 步骤4:验证快照状态 lvs | grep "${SNAP_NAME}" | grep "active" >/dev/null if [ $? -ne 0 ]; then echo "Snapshot not active" | logger -t mongo-snap exit 1 fi注意:
bc -l在 Ubuntu 14.04 默认未安装,需sudo apt-get install bc。另外,lvcreate -s的-L 5G参数必须足够大——快照 LV 存储的是原 LV 的“变化块”,如果在快照存活期间原 LV 写入量超过 5GB,快照会自动 invalid。建议按日均写入量的 1.5 倍设置。
3.4 权限与用户 UID 的隐形陷阱
Ubuntu 14.04 的mongodb用户 UID 是硬编码在包中的。官方mongodb-10gen包的 UID 固定为 108,但如果你用adduser mongodb手动创建,UID 可能是 1001 或其他值。迁移时若直接rsync数据目录,目标机的mongodb用户 UID 若与源机不一致,mongod 启动会报错Permission denied,即使ls -l显示权限正确。
验证方法:
# 源机 id -u mongodb # 应输出 108 # 目标机(迁移前必须执行) id -u mongodb # 若不为 108,需重建用户 sudo userdel mongodb sudo useradd -r -u 108 -g mongodb -d /var/lib/mongodb -s /bin/false mongodb更隐蔽的问题是local数据库的system.replset集合。它存储副本集配置,其中members[n].host字段是硬编码的主机名或 IP。如果迁移后新服务器 hostname 改变,mongod 启动时会尝试连接旧 host,导致初始化失败。解决方案是在 restore 前,用mongoshell 修改:
// 连接到新 mongod(此时无数据,先启动空实例) // > use local // > db.system.replset.update({}, {$set: {"members.0.host": "new-hostname:27017"}}) // > db.system.replset.find()提示:Ubuntu 14.04 的
mongoshell 默认不支持--eval执行多行 JS,必须用 here-document:
mongo << 'EOF' use local db.system.replset.update({}, {$set: {"members.0.host": "new-server:27017"}}) EOF3.5mongorestore的增量追平实战
mongorestore不是“导入就完事”,尤其在--oplogReplay场景下,它需要精确控制起始时间点。mongorestore --oplogReplay默认从oplog.bson中第一条记录的时间戳开始 replay,但如果 dump 时数据库正在写入,第一条记录可能不是你想要的“基线时刻”。
我的做法是:用冷快照作为基线,用mongodump --oplog获取快照后的增量,然后用--oplogLimit精确指定 replay 起点。
步骤:
- 在源机执行冷快照,记下快照创建时间
SNAP_TIME=2024-05-20T03:15:22; - 立即执行
mongodump --oplog,得到oplog.bson; - 在目标机 restore 冷快照数据(
rsync或dd); - 启动目标 mongod(此时数据是快照时刻的状态);
- 执行
mongorestore --oplogReplay --oplogLimit "2024-05-20T03:15:22:0" /path/to/oplog.bson。
--oplogLimit的格式必须是YYYY-MM-DDTHH:MM:SS:i,其中i是 oplog 的 second part(序号),设为0表示从该秒的第一条开始。
实操心得:
--oplogLimit的时间必须早于oplog.bson中最早的 timestamp,否则 restore 会报错no oplog entries found before limit。我写了一个小脚本自动提取oplog.bson的最早时间:
# 使用 bsondump 工具(Ubuntu 14.04 需从 MongoDB 2.6 源码编译) bsondump --outFile /tmp/oplog.json /backup/mongo/daily/20240520_031522/oplog.bson 2>/dev/null head -n 10 /tmp/oplog.json | grep '"ts"' | head -1 | sed 's/.*"ts" : { "t" : \([0-9]*\), "i" : \([0-9]*\) }.*/\1 \2/' # 输出类似:1716174922 0 → 转换为 ISO 时间:date -d @1716174922 +"%Y-%m-%dT%H:%M:%S"4. 完整实操过程与核心环节实现
现在,我们把前面所有细节串起来,走一遍从“准备”到“验证”的完整迁移流程。以一个真实的电商后台数据库(MongoDB 2.6.10,Ubuntu 14.04,数据量 8.2GB)为例,目标是迁移到一台新的 Ubuntu 14.04 服务器。
4.1 迁移前准备:清单式检查
在任何操作开始前,执行这份 12 项检查清单,缺一不可:
- ✅ 源机和目标机 MongoDB 版本完全一致(
mongod --version); - ✅ 源机
mongod.conf中storage.engine为mmapv1(WiredTiger 在 2.6 不稳定); - ✅ 源机
oplogSizeMB设置合理(已按 600MB 配置); - ✅ 源机
journal已启用(db.adminCommand({getCmdLineOpts:1})验证); - ✅ 源机
backup_user拥有admin和local数据库的read权限; - ✅ 目标机已安装相同版本 MongoDB,
/var/lib/mongodb目录为空; - ✅ 目标机
mongodb用户 UID 为 108(id -u mongodb); - ✅ 目标机
/etc/mongod.conf中bindIp设置为127.0.0.1,10.0.1.100(新内网 IP); - ✅ 目标机防火墙放行 27017 端口(
sudo ufw allow 27017); - ✅ 源机和目标机时间同步(
ntpdate -q pool.ntp.org,误差 < 1s); - ✅ 源机磁盘剩余空间 > 15GB(dump + 快照临时空间);
- ✅ 已通知业务方,计划维护窗口为 02:00-02:45(北京时间)。
注意:第 10 条“时间同步”极其关键。MongoDB 副本集的心跳检测基于时间戳,如果源机比目标机快 2 秒,
mongorestore --oplogReplay会因时间跳跃而拒绝 replay。
4.2 执行冷快照:30 秒精准操作
选择业务低峰期(凌晨 02:00),按秒执行:
# Step 1: 记录当前时间(精确到纳秒) SOURCE_TIME=$(date +%Y-%m-%dT%H:%M:%S.%N) # Step 2: 执行锁库(实测耗时 1.8 秒) echo "db.fsyncLock()" | mongo --quiet # Step 3: 创建 LVM 快照(耗时 0.3 秒) lvcreate -s -n "mongo_snap_0200" -L 10G /dev/vg0/mongo_lv # Step 4: 立即解锁(耗时 0.1 秒) echo "db.fsyncUnlock()" | mongo --quiet # Step 5: 验证快照 lvs | grep "mongo_snap_0200" | grep "active" # 输出应为:mongo_snap_0200 vg0 owi-aos--- 10.00g此时,/dev/vg0/mongo_snap_0200就是一个与源库完全一致的只读快照。你可以把它挂载到/mnt/snap,用du -sh /mnt/snap/*快速验证数据大小是否匹配。
4.3 获取增量 oplog:无缝衔接
快照创建后,立刻执行mongodump --oplog,确保增量从快照时刻开始:
# 使用 SOURCE_TIME 作为 dump 目录名,便于追溯 DUMP_DIR="/backup/mongo/migrate/$(date -d "${SOURCE_TIME}" +%Y%m%d_%H%M%S)" mkdir -p "${DUMP_DIR}" # 关键:--oplog 会自动捕获从快照时刻到 dump 结束的所有 oplog /usr/bin/mongodump \ --host 127.0.0.1:27017 \ --username backup_user \ --password 'xxx' \ --authenticationDatabase admin \ --oplog \ --out "${DUMP_DIR}" \ --quiet # 验证 oplog.bson 大小(应 > 0 且 < 100MB) ls -lh "${DUMP_DIR}/oplog.bson" # 示例输出:-rw-r--r-- 1 root root 24M May 20 02:00 oplog.bson4.4 目标机数据恢复:分步还原
目标机操作分三步,严格按顺序:
Step 1:恢复冷快照数据
# 停止目标 mongod sudo service mongod stop # 清空 /var/lib/mongodb sudo rm -rf /var/lib/mongodb/* sudo mkdir -p /var/lib/mongodb # 将快照 dd 到目标 LV(假设目标 LV 是 /dev/vg0/mongo_lv) sudo dd if=/dev/vg0/mongo_snap_0200 of=/dev/vg0/mongo_lv bs=4M conv=fdatasync # 修复文件权限(Ubuntu 14.04 要求 owner 为 mongodb:108) sudo chown -R 108:108 /var/lib/mongodb sudo chmod 755 /var/lib/mongodbStep 2:启动基础 mongod
# 临时注释掉 mongod.conf 中的 replication 相关配置(避免启动时连接旧 host) sudo sed -i '/^replSetName/d; /^keyFile/d' /etc/mongod.conf sudo service mongod start # 验证能否连接 mongo --eval "db.version()" # 应输出 2.6.10Step 3:应用增量 oplog
# 从源机拷贝 dump 目录到目标机 rsync -avz /backup/mongo/migrate/20240520_020000/ user@target:/tmp/mongo_migrate/ # 计算 oplog 起始时间(SOURCE_TIME 是 2024-05-20T02:00:00.123456789) OPLOG_START=$(date -d "2024-05-20 02:00:00" +"%Y-%m-%dT%H:%M:%S.0") # 执行 replay sudo -u mongodb mongorestore \ --host 127.0.0.1:27017 \ --oplogReplay \ --oplogLimit "${OPLOG_START}" \ /tmp/mongo_migrate/oplog.bson # 期间观察日志:sudo tail -f /var/log/mongodb/mongod.log # 成功标志:日志末尾出现 "replaying oplog from ..."4.5 迁移后验证:不只是“能连上”
验证必须覆盖三个层面:
数据完整性:对比源机和目标机的集合数量、文档总数、索引数量。
# 源机 mongo --eval "db.getCollectionNames().length" mongo --eval "db.orders.count()" mongo --eval "db.orders.getIndexes().length" # 目标机(执行相同命令)数据一致性:抽样比对关键字段的哈希值。
# 源机:取 orders 集合前 1000 条的 _id 和 total 字段,生成 MD5 mongo orders --eval "db.orders.find({}, {_id:1, total:1}).limit(1000).forEach(function(x){print(x._id+'|'+x.total)})" | md5sum # 目标机:执行相同命令,MD5 值必须完全一致业务可用性:用真实业务请求测试。
# 模拟一个下单请求(curl 或应用代码) curl -X POST http://target-server:27017/api/order \ -H "Content-Type: application/json" \ -d '{"user_id":"test123","items":[{"id":"p001","qty":1}]}' \ -w "\nHTTP Status: %{http_code}\n" # 应返回 HTTP Status: 200,且数据库中能查到该订单
提示:Ubuntu 14.04 的
curl默认不支持-w选项,需sudo apt-get install curl升级到 7.35+ 版本。
5. 常见问题与排查技巧实录
以下是我在 Ubuntu 14.04 + MongoDB 迁移中遇到的 7 类高频问题,每类都附上错误现象、根本原因、三步定位法、终极解决方案。这些不是理论推测,而是从生产日志里一条条抠出来的。
5.1 问题:mongorestore --oplogReplay报错replSet ID mismatch
现象:
2024-05-20T02:15:30.123+0000 E QUERY [thread1] Error: replSet ID mismatch: 507f1f77bcf86cd799439011 vs 507f1f77bcf86cd799439012根本原因:local.system.replset集合中的_id字段是 ObjectId,由 mongod 启动时自动生成。冷快照恢复后,目标机 mongod 会读取快照中的_id,但--oplogReplay试图用新生成的 replica set ID 初始化,导致冲突。
三步定位法:
mongo --eval "db.getSiblingDB('local').system.replset.findOne()"查看_id;mongo --eval "rs.conf()._id"查看当前 config 的_id;- 对比两者是否一致。
终极解决方案:
在目标机启动 mongod 前,手动修改快照中的system.replset:
# 启动一个临时 mongod,指向快照数据目录 mongod --dbpath /mnt/snap --port 27018 --nojournal --bind_ip 1