MongoDB 常见问题解答
本文档汇总 MongoDB 开发和运维中的常见问题及解决方案。
连接问题
Q1: 连接超时
症状:客户端无法连接到 MongoDB,出现超时错误。
排查步骤:
bash
# 检查 MongoDB 服务状态
sudo systemctl status mongod
# 检查端口监听
netstat -tlnp | grep 27017
# 或
lsof -i :27017
# 检查防火墙
sudo ufw status
sudo ufw allow 27017
# 检查绑定 IP
cat /etc/mongod.conf | grep bindIp
# 测试连接
mongosh "mongodb://localhost:27017"解决方案:
- 确保 MongoDB 服务正在运行
- 检查
bindIp配置,如需远程访问,设置为0.0.0.0或具体 IP - 开放防火墙端口
- 检查网络连通性
Q2: 认证失败
症状:连接时报错 Authentication failed。
排查步骤:
javascript
// 检查用户权限
use admin
db.getUser("myAdmin")
// 查看所有用户
db.getUsers()解决方案:
javascript
// 重置密码
db.changeUserPassword("myAdmin", "newPassword")
// 创建新管理员
db.createUser({
user: "newAdmin",
pwd: "password",
roles: ["root"]
})bash
# 检查认证数据库
mongosh -u myAdmin -p --authenticationDatabase adminQ3: 副本集连接问题
症状:无法连接副本集,或连接后无法执行操作。
解决方案:
javascript
// 确保连接字符串正确
mongodb://user:pass@host1:27017,host2:27017,host3:27017/db?replicaSet=myRs
// 检查副本集状态
rs.status()
// 检查成员健康状态
rs.isMaster()
// 重新配置副本集(必要时)
rs.reconfig({
_id: "myRs",
members: [
{ _id: 0, host: "host1:27017" },
{ _id: 1, host: "host2:27017" },
{ _id: 2, host: "host3:27017" }
]
})性能问题
Q4: 查询慢
症状:查询响应时间长。
排查步骤:
javascript
// 1. 使用 explain 分析
db.collection.find({ field: "value" }).explain("executionStats")
// 2. 检查是否使用索引
// 查找 "stage": "COLLSCAN" 表示全表扫描
// "stage": "IXSCAN" 表示使用了索引
// 3. 查看慢查询
db.system.profile.find({ millis: { $gt: 100 } }).sort({ ts: -1 })
// 4. 检查索引
db.collection.getIndexes()解决方案:
javascript
// 创建合适索引
db.collection.createIndex({ field: 1 })
// 使用投影
db.collection.find({ field: "value" }, { _id: 0, field: 1 })
// 限制结果
db.collection.find().limit(100)
// 使用覆盖索引
db.collection.createIndex({ status: 1, name: 1 })
db.collection.find({ status: "active" }, { _id: 0, status: 1, name: 1 })Q5: 内存不足
症状:MongoDB 占用大量内存,或 OOM。
排查步骤:
javascript
// 检查内存使用
db.serverStatus().mem
// 检查缓存使用
db.serverStatus().wiredTiger.cache
// 检查连接数
db.serverStatus().connections解决方案:
yaml
# 调整 WiredTiger 缓存
# mongod.conf
storage:
wiredTiger:
engineConfig:
cacheSizeGB: 2 # 限制缓存大小javascript
// 限制查询结果
db.collection.find().limit(100)
// 使用游标迭代
for await (const doc of db.collection.find()) {
// 处理文档
}Q6: 写入慢
症状:写入操作耗时过长。
排查步骤:
javascript
// 检查写关注级别
db.collection.insertOne({...}, { writeConcern: { w: "majority", j: true } })
// 检查索引数量
db.collection.getIndexes()
// 检查锁情况
db.currentOp({ "waitingForLock": true })解决方案:
javascript
// 批量写入
db.collection.insertMany([...])
// 使用无序写入
db.collection.insertMany([...], { ordered: false })
// 降低写关注(非关键数据)
db.collection.insertOne({...}, { writeConcern: { w: 1 } })
// 减少不必要的索引
db.collection.dropIndex("unused_index")数据问题
Q7: 文档过大
症状:无法插入文档,报错文档超过 16MB 限制。
解决方案:
javascript
// 检查文档大小
Object.bsonsize(db.collection.findOne())
// 方案1:拆分文档
// 将大字段拆分到独立集合
// 方案2:使用 GridFS 存储大文件
const bucket = new mongoose.mongo.GridFSBucket(db)
// 上传文件
fs.createReadStream('./large-file.pdf')
.pipe(bucket.openUploadStream('large-file.pdf'))
// 下载文件
bucket.openDownloadStreamByName('large-file.pdf')
.pipe(fs.createWriteStream('./downloaded-file.pdf'))Q8: 数据类型问题
症状:字段类型不一致导致查询或更新失败。
排查步骤:
javascript
// 检查字段类型
db.collection.find({ field: { $type: "string" } })
// 查看所有存在的类型
db.collection.aggregate([
{ $group: { _id: { $type: "$field" } } }
])解决方案:
javascript
// 类型转换(聚合)
db.collection.aggregate([
{ $project: { quantity: { $toInt: "$quantityStr" } } }
])
// 更新字段类型
db.collection.find().forEach(doc => {
db.collection.updateOne(
{ _id: doc._id },
{ $set: { quantity: parseInt(doc.quantityStr) } }
)
})
// 使用 $convert 安全转换
db.collection.aggregate([
{
$project: {
quantity: {
$convert: {
input: "$quantityStr",
to: "int",
onError: 0,
onNull: 0
}
}
}
}
])Q9: 重复键错误
症状:插入时报错 E11000 duplicate key error。
排查步骤:
javascript
// 检查唯一索引
db.collection.getIndexes()
// 查找重复数据
db.collection.aggregate([
{ $group: { _id: "$email", count: { $sum: 1 }, ids: { $push: "$_id" } } },
{ $match: { count: { $gt: 1 } } }
])解决方案:
javascript
// 删除重复数据(保留第一条)
db.collection.aggregate([
{ $group: { _id: "$email", count: { $sum: 1 }, ids: { $push: "$_id" } } },
{ $match: { count: { $gt: 1 } } }
]).forEach(doc => {
doc.ids.slice(1).forEach(id => {
db.collection.deleteOne({ _id: id })
})
})
// 使用 upsert
db.collection.updateOne(
{ email: "user@example.com" },
{ $set: { name: "User" } },
{ upsert: true }
)运维问题
Q10: 磁盘空间不足
症状:磁盘使用率过高,无法写入数据。
排查步骤:
javascript
// 检查数据库大小
db.stats()
// 检查集合大小
db.collection.stats()
// 查看存储大小
db.collection.stats().storageSize解决方案:
javascript
// 压缩数据(需要维护窗口)
db.runCommand({ compact: "collection" })
// 删除旧数据
db.collection.deleteMany({ createdAt: { $lt: new Date("2023-01-01") } })
// 使用 TTL 索引自动删除
db.collection.createIndex(
{ createdAt: 1 },
{ expireAfterSeconds: 86400 } // 24小时后删除
)
// 删除不需要的索引
db.collection.dropIndex("unused_index")bash
# 修复数据库(需要足够空间)
mongod --repair --dbpath /data/dbQ11: 副本集同步延迟
症状:从节点数据落后于主节点太多。
排查步骤:
javascript
// 检查复制延迟
rs.printSlaveReplicationInfo()
// 检查从节点状态
rs.status().members.forEach(m => {
if (m.stateStr === "SECONDARY") {
print(m.name + " lag: " + m.optimeDate)
}
})解决方案:
javascript
// 1. 增加从节点硬件配置(I/O、网络)
// 2. 调整读写关注
db.collection.find().readPref("primary")
// 3. 检查网络延迟
rs.status().members.forEach(m => print(m.name + " ping: " + m.pingMillis + "ms"))
// 4. 禁用链式复制(必要时)
var cfg = rs.conf()
cfg.settings.chainingAllowed = false
rs.reconfig(cfg)Q12: 分片数据倾斜
症状:部分分片存储的数据远多于其他分片。
排查步骤:
javascript
// 检查分片分布
db.collection.getShardDistribution()
// 查看块分布
use config
db.chunks.find({ ns: "mydb.collection" })
// 检查均衡器状态
sh.getBalancerState()解决方案:
javascript
// 1. 选择更好的分片键
// 如果当前分片键不好,需要迁移数据到新集合
// 2. 使用哈希分片
sh.shardCollection("mydb.collection", { field: "hashed" })
// 3. 手动迁移块
sh.moveChunk("mydb.collection", { shardKey: "value" }, "shard2")
// 4. 使用标签分片
sh.addShardTag("shard1", "high")
sh.addTagRange("mydb.collection", { userId: 0 }, { userId: 1000 }, "high")错误码参考
| 错误码 | 名称 | 说明 | 解决方案 |
|---|---|---|---|
| 2 | BadValue | 参数错误 | 检查参数格式 |
| 6 | HostNotFound | 主机未找到 | 检查网络和 DNS |
| 11 | UserNotFound | 用户不存在 | 检查用户名和认证库 |
| 18 | AuthenticationFailed | 认证失败 | 检查用户名密码 |
| 48 | NamespaceExists | 集合已存在 | 更换集合名或删除后创建 |
| 59 | CommandNotFound | 命令不存在 | 检查 MongoDB 版本 |
| 11000 | DuplicateKey | 重复键错误 | 检查唯一索引 |
| 11001 | DuplicateKeyOnUpdate | 更新时重复键 | 检查更新的值 |
| 11600 | InterruptedAtShutdown | 关闭时中断 | 重启 MongoDB |
| 13113 | CursorNotFound | 游标不存在 | 增加游标超时时间 |
| 15998 | WriteConflict | 写冲突 | 重试事务 |
| 211 | RangeConflict | 范围冲突 | 重试操作 |
性能问题诊断清单
code
□ 检查索引是否被使用
□ 检查是否有全表扫描
□ 检查查询是否返回过多字段
□ 检查是否有 N+1 查询问题
□ 检查写关注级别是否过高
□ 检查连接池配置
□ 检查副本集复制延迟
□ 检查内存使用情况
□ 检查磁盘 I/O
□ 检查网络延迟上一篇:运维管理