Skip to content

副本集部署

副本集(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/mongodb

1. 启动节点

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 --fork

2. 初始化副本集

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/keyfile
shell
# 带认证重启
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
# 其余节点同样加 --keyFile
js
// 创建管理员
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。

参考