MongoDB运维踩坑记录
用MongoDB做数据库几年了,从单机到复制集,踩了不少坑。记录一下运维经验和常见问题。
安装配置
Windows安装
- 官网下载MSI安装包
- 选择”Complete”完整安装
- 勾选”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
|
Linux安装
CentOS:
1 2 3 4 5 6 7 8 9 10 11 12 13
| 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
|
net: port: 27017 bindIp: 127.0.0.1
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
| 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
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 })
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
| 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
| sh.enableSharding("mydb")
sh.shardCollection("mydb.users", { userId: "hashed" })
sh.status()
|
安全配置
安全加固检查表
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运维常见坑点:
- 4.4+版本工具要单独安装
- 启用认证后连接字符串要指定authSource
- 备份脚本要加–gzip压缩,省磁盘空间
- 复制集初始化要注意节点优先级配置
- 内存占用高就限制wiredTiger缓存
- 连接数问题要检查应用连接池配置
MongoDB文档模型灵活,但运维也要细心。定期备份、监控性能、及时升级是基本操作。