MongoDB运维踩坑记录

MongoDB运维踩坑记录

用MongoDB做数据库几年了,从单机到复制集,踩了不少坑。记录一下运维经验和常见问题。

安装配置

Windows安装

  1. 官网下载MSI安装包
  2. 选择”Complete”完整安装
  3. 勾选”Install MongoDB as a Service”
1
2
3
4
5
6
7
8
# 查看版本
mongod --version

# 启动服务
net start MongoDB

# 连接数据库
mongo

坑1:数据库工具分离

MongoDB 4.4+版本将工具(mongodump、mongorestore等)分离为独立包,需要单独下载安装。

1
2
3
4
5
# 下载地址
https://www.mongodb.com/try/download/database-tools

# 解压到MongoDB安装目录的bin文件夹
# 添加到系统PATH

Linux安装

CentOS

1
2
3
4
5
6
7
8
9
10
11
12
13
# 配置MongoDB源
cat > /etc/yum.repos.d/mongodb-org.repo <<EOF
[mongodb-org-6.0]
name=MongoDB Repository
baseurl=https://repo.mongodb.org/yum/redhat/\$releasever/mongodb-org/6.0/x86_64/
gpgcheck=1
enabled=1
gpgkey=https://www.mongodb.org/static/pgp/server-6.0.asc
EOF

sudo yum install -y mongodb-org
sudo systemctl start mongod
sudo systemctl enable mongod

Ubuntu

1
2
3
4
5
6
7
8
wget -qO - https://www.mongodb.org/static/pgp/server-6.0.asc | sudo apt-key add -
echo "deb [ arch=amd64,arm64 ] https://repo.mongodb.org/apt/ubuntu focal/mongodb-org/6.0 multiverse" | sudo tee /etc/apt/sources.list.d/mongodb-org-6.0.list

sudo apt-get update
sudo apt-get install -y mongodb-org

sudo systemctl start mongod
sudo systemctl enable mongod

认证配置

启用身份验证

编辑配置文件:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
# /etc/mongod.conf (Linux)
# <安装目录>\bin\mongod.cfg (Windows)

net:
port: 27017
bindIp: 127.0.0.1 # 生产环境限制访问IP

security:
authorization: enabled

storage:
dbPath: /var/lib/mongo
journal:
enabled: true

创建管理员用户

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
// 连接到admin数据库
use admin

// 创建超级管理员
db.createUser({
user: "root",
pwd: "secure_password",
roles: [
{ role: "userAdminAnyDatabase", db: "admin" },
{ role: "readWriteAnyDatabase", db: "admin" },
{ role: "dbAdminAnyDatabase", db: "admin" },
{ role: "clusterAdmin", db: "admin" }
]
})

// 创建数据库管理员(特定数据库)
use myapp
db.createUser({
user: "appuser",
pwd: "app_password",
roles: [
{ role: "readWrite", db: "myapp" }
]
})

连接字符串

1
2
3
4
5
6
7
8
9
10
11
# 本地无认证连接
mongo

# 本地认证连接
mongo -u root -p --authenticationDatabase admin

# 远程连接
mongo "mongodb://root:password@192.168.1.100:27017/admin"

# 应用连接字符串
mongodb://appuser:password@localhost:27017/myapp?authSource=myapp

数据备份与还原

mongodump备份

完整备份

1
2
3
4
5
6
7
mongodump \
--host 0.0.0.0 \
--port 27017 \
--username root \
--password rootpassword \
--authenticationDatabase admin \
--out /opt/backup/$(date +%Y%m%d)

备份指定数据库

1
2
3
4
5
6
mongodump \
--db myapp \
--username root \
--password rootpassword \
--authenticationDatabase admin \
--out /opt/backup/

备份指定集合

1
2
3
4
5
6
7
mongodump \
--db myapp \
--collection users \
--username root \
--password rootpassword \
--authenticationDatabase admin \
--out /opt/backup/

mongorestore还原

还原整个数据库

1
2
3
4
5
6
7
8
9
mongorestore \
--host 0.0.0.0 \
--port 27017 \
--username root \
--password rootpassword \
--authenticationDatabase admin \
--db testdb \
--drop \
/opt/backup/backup/testdb

Windows环境还原

1
2
3
4
5
6
7
8
9
mongorestore.exe ^
--host 0.0.0.0 ^
--port 27017 ^
--authenticationDatabase admin ^
-u root ^
-p rootpassword ^
-d testdb ^
--drop ^
E:\mongodbBackup\backup\testdb

自动化备份脚本

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
#!/bin/bash

BACKUP_DIR="/opt/backup"
DATE=$(date +%Y%m%d_%H%M%S)
MONGO_USER="root"
MONGO_PASS="password"
RETENTION_DAYS=7

mkdir -p $BACKUP_DIR/$DATE

# 执行备份
mongodump \
--username $MONGO_USER \
--password $MONGO_PASS \
--authenticationDatabase admin \
--gzip \
--out $BACKUP_DIR/$DATE

# 检查备份结果
if [ $? -eq 0 ]; then
echo "[$(date)] 备份成功: $BACKUP_DIR/$DATE"
else
echo "[$(date)] 备份失败!" >&2
exit 1
fi

# 清理过期备份
find $BACKUP_DIR -type d -mtime +$RETENTION_DAYS -exec rm -rf {} \;

echo "[$(date)] 清理完成,保留最近 $RETENTION_DAYS 天备份" >> $BACKUP_DIR/backup.log

添加到定时任务:

1
2
3
4
crontab -e

# 每天凌晨2点执行备份
0 2 * * * /opt/scripts/backup_mongodb.sh

性能监控

常用命令

1
2
3
4
5
6
7
8
9
10
11
# 查看服务器状态
db.serverStatus()

# 查看当前操作
db.currentOp()

# 查看集合统计信息
db.collection.stats()

# 查看执行计划
db.collection.find({name: "test"}).explain("executionStats")

索引优化

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
// 单字段索引
db.users.createIndex({ email: 1 }, { unique: true })

// 复合索引
db.orders.createIndex({ userId: 1, createdAt: -1 })

// 文本索引
db.articles.createIndex({ title: "text", content: "text" })

// 地理空间索引
db.locations.createIndex({ coordinates: "2dsphere" })

// 查看所有索引
db.collection.getIndexes()

// 删除索引
db.collection.dropIndex("index_name")
db.collection.dropIndexes()

// 查看索引使用情况
db.collection.aggregate([{ $indexStats: {} }])

查询优化建议

1
2
3
4
5
6
7
8
9
// 使用投影减少返回字段
db.users.find({}, { name: 1, email: 1, _id: 0 })

// 使用limit限制返回数量
db.posts.find().sort({ createdAt: -1 }).limit(10)

// 避免全表扫描 - 确保有索引
db.users.createIndex({ status: 1 })
db.users.find({ status: "active" })

复制集配置

复制集架构

1
2
3
4
5
6
7
8
9
10
11
12
13
┌─────────────────┐
│ Primary │ ◄── 读写操作
│ (主节点) │
└────────┬────────┘

│ 复制 (Oplog)

┌────┴────┐
│ │
┌───▼───┐ ┌──▼────┐
│Secondary│ │Secondary│ ◄── 只读操作(可选)
│(从节点) │ │(从节点) │
└─────────┘ └─────────┘

配置步骤

1. 准备配置文件(每个节点)

1
2
3
4
5
6
7
8
9
storage:
dbPath: /var/lib/mongo

net:
port: 27017
bindIp: 0.0.0.0

replication:
replSetName: rs0

2. 启动所有节点

1
sudo systemctl start mongod

3. 初始化复制集

1
2
3
4
5
6
7
8
9
10
11
12
rs.initiate({
_id: "rs0",
members: [
{ _id: 0, host: "192.168.1.10:27017", priority: 2 },
{ _id: 1, host: "192.168.1.11:27017", priority: 1 },
{ _id: 2, host: "192.168.1.12:27017", arbiterOnly: true }
]
})

// 查看复制集状态
rs.status()
rs.conf()

读写分离

1
2
3
4
5
6
7
8
9
10
// 应用连接配置(Node.js示例)
const MongoClient = require('mongodb').MongoClient;

const uri = "mongodb://user:password@node1:27017,node2:27017,node3:27017/mydb?replicaSet=rs0&readPreference=secondaryPreferred";

const client = new MongoClient(uri, {
readPreference: 'secondaryPreferred', // 优先从从节点读取
w: 'majority', // 写操作等待大多数节点确认
retryWrites: true
});

读偏好模式

模式 说明
primary 只从主节点读取(默认)
primaryPreferred 优先主节点,不可用时从从节点读取
secondary 只从从节点读取
secondaryPreferred 优先从节点,都不可用时从主节点读取
nearest 从网络延迟最低的节点读取

分片集群

分片键选择策略

策略 适用场景 示例
哈希分片 写入压力大、数据分布均匀 { _id: "hashed" }
范围分片 范围查询频繁、数据有序 { createdAt: 1 }
复合分片 多维度查询 { userId: 1, _id: 1 }
1
2
3
4
5
6
7
8
// 连接到mongos
sh.enableSharding("mydb")

// 对集合启用分片
sh.shardCollection("mydb.users", { userId: "hashed" })

// 查看分片状态
sh.status()

安全配置

安全加固检查表

  • 启用身份验证(authorization: enabled)
  • 配置防火墙,限制访问IP
  • 使用强密码策略
  • 启用TLS/SSL加密传输
  • 定期备份数据
  • 最小权限原则分配角色
  • 启用审计日志
  • 及时更新到最新版本

TLS/SSL配置

1
2
3
4
5
net:
tls:
mode: requireTLS
certificateKeyFile: /etc/ssl/mongodb.pem
CAFile: /etc/ssl/ca.pem

坑2:内存占用过高

MongoDB默认会占用大量内存做缓存,可以通过配置限制:

1
2
3
4
storage:
wiredTiger:
engineConfig:
cacheSizeGB: 2 # 限制缓存大小

坑3:连接数过多

默认连接数限制可能不够,需要调整:

1
2
net:
maxIncomingConnections: 1000

同时检查应用端连接池配置,确保正确释放连接。

坑4:数据目录权限

Linux下数据目录权限不对会导致启动失败:

1
2
sudo chown -R mongod:mongod /var/lib/mongo
sudo chown -R mongod:mongod /var/log/mongodb

总结

MongoDB运维常见坑点:

  1. 4.4+版本工具要单独安装
  2. 启用认证后连接字符串要指定authSource
  3. 备份脚本要加–gzip压缩,省磁盘空间
  4. 复制集初始化要注意节点优先级配置
  5. 内存占用高就限制wiredTiger缓存
  6. 连接数问题要检查应用连接池配置

MongoDB文档模型灵活,但运维也要细心。定期备份、监控性能、及时升级是基本操作。