副本集部署
副本集(Replica Set)是 MongoDB 最基本的高可用架构,由一个 Primary 和多个 Secondary 组成,Primary 故障时自动选举新 Primary。
架构
┌──────────────────────────────┐
│ Replica Set │
│ ┌──────────┐ ┌──────────┐ │
│ │ Primary │──▶ Secondary │ │
│ │ 27017 │ │ 27018 │ │
│ └──────────┘ └──────────┘ │
│ │ │ │
│ └────────────┤ │
│ ▼ │
│ ┌──────────┐ │
│ │ Secondary │ (可选 Arbiter) │
│ │ 27019 │ │
│ └──────────┘ │
└──────────────────────────────┘生产环境要求:最少 3 节点(或 2 节点 + 1 Arbiter),确保选举需要多数票。
环境准备
shell
sudo mkdir -p /data/mongo/{rs0n0,rs0n1,rs0n2}
sudo chown -R $USER:$USER /data/mongo
sudo mkdir -p /var/log/mongodb
sudo chown -R $USER:$USER /var/log/mongodb1. 启动节点
shell
mongod --replSet rs0 --dbpath /data/mongo/rs0n0 \
--port 27017 --bind_ip 0.0.0.0 \
--logpath /var/log/mongodb/rs0n0.log --fork
mongod --replSet rs0 --dbpath /data/mongo/rs0n1 \
--port 27018 --bind_ip 0.0.0.0 \
--logpath /var/log/mongodb/rs0n1.log --fork
mongod --replSet rs0 --dbpath /data/mongo/rs0n2 \
--port 27019 --bind_ip 0.0.0.0 \
--logpath /var/log/mongodb/rs0n2.log --fork2. 初始化副本集
js
// mongosh --port 27017
rs.initiate({
_id: "rs0",
members: [
{ _id: 0, host: "localhost:27017", priority: 2 },
{ _id: 1, host: "localhost:27018" },
{ _id: 2, host: "localhost:27019" }
]
})
// { ok: 1 }priority: 2 使该节点优先当选 Primary。
3. 验证
js
rs.status()
// 查看各成员状态:PRIMARY / SECONDARY
rs.conf()
// 查看副本集配置
// Primary 上写入
db.test.insertOne({ msg: "hello" })
// Secondary 上读取(需先开启)
// mongosh --port 27018
rs.secondaryOk()
db.test.find()4. 连接字符串
shell
# 应用连接 — 自动发现所有节点、自动故障转移
mongosh "mongodb://localhost:27017,localhost:27018,localhost:27019/?replicaSet=rs0"5. 成员管理
js
// 添加成员
rs.add("localhost:27020")
// 添加 Arbiter(仅投票,不存数据)
rs.addArb("localhost:27021")
// 移除成员
rs.remove("localhost:27020")
// 手动切换 Primary
rs.stepDown()
// 设置成员优先级
let cfg = rs.conf()
cfg.members[0].priority = 2
rs.reconfig(cfg)6. 安全加固
shell
# 生成 keyFile
openssl rand -base64 756 > /data/mongo/keyfile
chmod 400 /data/mongo/keyfileshell
# 带认证重启
mongod --replSet rs0 --dbpath /data/mongo/rs0n0 \
--port 27017 --bind_ip 0.0.0.0 \
--keyFile /data/mongo/keyfile \
--logpath /var/log/mongodb/rs0n0.log --fork
# 其余节点同样加 --keyFilejs
// 创建管理员
use admin
db.createUser({
user: "admin",
pwd: "secure_password",
roles: ["root"]
})
db.auth("admin", "secure_password")Docker Compose
yaml
version: '3.8'
services:
rs0n0:
image: mongo:8
command: mongod --replSet rs0 --port 27017 --bind_ip_all
ports: ["27017:27017"]
volumes: [rs0n0-data:/data/db]
rs0n1:
image: mongo:8
command: mongod --replSet rs0 --port 27017 --bind_ip_all
volumes: [rs0n1-data:/data/db]
rs0n2:
image: mongo:8
command: mongod --replSet rs0 --port 27017 --bind_ip_all
volumes: [rs0n2-data:/data/db]
volumes:
rs0n0-data: rs0n1-data: rs0n2-data:启动后进入容器执行步骤 2。