最近,我的一台 Ubuntu 服务器上的 MongoDB 突然无法启动。启动操作看起来执行了,但系统中没有 mongod 进程,27017 端口也没有监听。
一开始,我在日志中看到过 SCRAM authentication failed, storedKey mismatch,所以最初怀疑是 MongoDB 的 root 密码或认证配置出了问题。继续检查完整启动日志后,我才发现认证报错只是之前连接数据库时留下的记录,真正导致这次 MongoDB 无法启动的原因,是 WiredTiger 数据文件的所有者被改成了 root。
本文记录完整的判断和修复过程。
一、运行环境
- 操作系统:Ubuntu 22.04
- MongoDB:6.0.10
- 配置文件:
/www/server/mongodb/config.conf
- 数据目录:
/www/server/mongodb/data
- 日志文件:
/www/server/mongodb/log/config.log
- 监听地址:
127.0.0.1:27017
- 存储引擎:WiredTiger
二、故障现象
MongoDB 启动后立即退出,使用下面的命令检查不到进程:
ps -eo pid,user,args | grep '[m]ongod'
检查端口,同样没有任何输出:
ss -lntp | grep 27017
这说明问题不是“应用连接不上已经运行的 MongoDB”,而是 MongoDB 服务本身没有完成启动。
三、先找到真正的日志文件
我的 MongoDB 日志并不在常见的 /var/log/mongodb/mongod.log,而是在自定义目录中。配置文件里的相关内容如下:
systemLog:
destination: file
logAppend: true
path: /www/server/mongodb/log/config.log
可以直接从配置文件中查找日志路径:
grep -nA10 -B2 "systemLog" /www/server/mongodb/config.conf
然后查看最后一段启动日志:
tail -n 100 /www/server/mongodb/log/config.log
四、从日志定位真正原因
日志中的关键内容如下:
MongoDB starting
Opening WiredTiger
/www/server/mongodb/data/WiredTiger.turtle: handle-open: open: Permission denied
Failed to start up WiredTiger under any compatibility version
Terminating. reason: "13: Permission denied"
***aborting after fassert() failure
其中最重要的不是后面的兼容性提示,而是前面的:
WiredTiger.turtle: open: Permission denied
这表示 WiredTiger.turtle 文件确实存在,但运行 MongoDB 的系统用户没有权限打开它。WiredTiger 无法初始化,MongoDB 只能中止启动,因此也就不会监听 27017 端口。
日志时间线也很清楚:
04:14:08:MongoDB 正常关闭,退出码为 0;
13:34:49:第一次重新启动,在打开 WiredTiger.turtle 时被拒绝;
14:04:15 和 14:04:47:再次尝试启动,仍然因相同权限错误退出。
这也说明本次故障并不是 MongoDB 无故崩溃,而是在正常停止之后,数据文件权限发生了变化。
五、什么是 WiredTiger.turtle
WiredTiger.turtle 是 WiredTiger 存储引擎启动时必须读取的核心元数据文件。它可以理解为存储引擎打开数据库元数据的“入口说明”。MongoDB 启动时必须先读取它,才能继续打开其他 WiredTiger 数据文件。
因此,这个文件无法读取时,MongoDB 不能跳过错误继续运行。
需要注意:
Permission denied 表示操作系统拒绝访问,并不等于文件内容已经损坏。
所以遇到这个错误时,不应该立即删除 WiredTiger.turtle,也不应该直接运行 --repair,而应先检查文件所有者和权限。
六、检查数据目录和文件权限
我执行了下面两个命令:
ls -ld /www/server/mongodb/data
ls -l /www/server/mongodb/data/WiredTiger.turtle
结果如下:
drwxr-xr-x 11 mongo mongo 4096 Aug 29 04:14 /www/server/mongodb/data
-rw------- 1 root root 1485 Aug 29 04:14 /www/server/mongodb/data/WiredTiger.turtle
问题到这里已经完全确定:
- 数据目录属于
mongo:mongo;
WiredTiger.turtle 却属于 root:root;
- 文件权限是
600,只有文件所有者可以读写;
- MongoDB 以
mongo 用户运行,自然无法读取属于 root 的文件。
这里的 600 权限本身没有问题,错误在于文件所有者变成了 root。
七、修复文件所有者
为了避免数据目录中还有其他文件存在同样问题,我将整个 MongoDB 数据目录的所有者统一恢复为 mongo:mongo:
chown -R mongo:mongo /www/server/mongodb/data
然后检查是否仍有不属于 mongo:mongo 的文件:
find /www/server/mongodb/data \( ! -user mongo -o ! -group mongo \) -ls
命令没有输出,说明数据目录下所有文件的所有者都已经恢复正常。
如果其他服务器上的 MongoDB 运行用户是 mongodb 或 mongod,就应该替换成对应的用户和用户组,不能机械照抄 mongo:mongo。可以通过 systemd 服务配置或启动脚本确认实际运行用户。
八、重新启动并验证
修复所有者后,我重新启动 MongoDB,然后执行:
ps -eo pid,user,args | grep '[m]ongod'
ss -lntp | grep 27017
最后检查最新日志:
tail -n 50 /www/server/mongodb/log/config.log
此时能够看到 mongod 进程和 27017 监听记录,日志中也出现了类似下面的内容:
Waiting for connections
MongoDB 恢复正常,实际测试连接也没有问题。
九、为什么最初的认证报错不是本次根因
在旧日志中,我还看到了:
AuthenticationFailed: SCRAM authentication failed, storedKey mismatch
这条日志表示某个客户端提交的密码与 MongoDB 中保存的账号凭据不匹配。但是产生认证日志有一个前提:MongoDB 当时已经启动并接受了连接。
而本次启动失败发生在 WiredTiger 初始化阶段,MongoDB 在开始监听端口之前就退出了。因此,两类报错属于不同时间、不同阶段:
storedKey mismatch:MongoDB 已经运行,但客户端密码错误;
WiredTiger.turtle Permission denied:MongoDB 无法读取数据文件,服务启动失败。
排查日志时不能只搜索某一条醒目的错误,而要结合时间戳和完整启动流程,找到最后一次启动过程中出现的第一条致命错误。
十、排查时不要做的操作
遇到 WiredTiger 启动失败时,我建议先保留现场,不要立即执行以下操作:
删除 WiredTiger.turtle
删除 WiredTiger.wt
删除 journal 目录
清空整个 data 目录
直接运行 mongod --repair
关闭 authorization 认证
这些操作可能扩大问题,甚至导致数据无法恢复。本次故障只是文件所有者错误,只需要修复权限关系,不需要修复或重建数据库。
十一、总结
这次故障的最终原因很简单:MongoDB 数据目录属于 mongo:mongo,但关键文件 WiredTiger.turtle 被改成了 root:root,同时文件权限为 600。MongoDB 服务用户无法读取该文件,导致 WiredTiger 初始化失败,MongoDB 在监听端口之前直接退出。
最终修复命令是:
chown -R mongo:mongo /www/server/mongodb/data
这次排障给我的经验是:遇到 MongoDB 无法启动时,应先确认进程和端口,再按照时间顺序查看最后一次启动日志。看到 Permission denied 时,优先检查数据目录、关键文件的所有者以及 MongoDB 的实际运行用户,不要把权限问题误判为数据库损坏。