MongoDB 副本集从零搭建到生产可用

MongoDB 副本集从零搭建到生产可用

两台服务器:一台物理机跑主库,一台 Docker 跑从库,实现数据库高可用


一、为什么需要副本集?

#mermaid-svg-NqWdFrRXugPsR5xI{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-NqWdFrRXugPsR5xI .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-NqWdFrRXugPsR5xI .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-NqWdFrRXugPsR5xI .error-icon{fill:#552222;}#mermaid-svg-NqWdFrRXugPsR5xI .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-NqWdFrRXugPsR5xI .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-NqWdFrRXugPsR5xI .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-NqWdFrRXugPsR5xI .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-NqWdFrRXugPsR5xI .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-NqWdFrRXugPsR5xI .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-NqWdFrRXugPsR5xI .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-NqWdFrRXugPsR5xI .marker{fill:#333333;stroke:#333333;}#mermaid-svg-NqWdFrRXugPsR5xI .marker.cross{stroke:#333333;}#mermaid-svg-NqWdFrRXugPsR5xI svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-NqWdFrRXugPsR5xI p{margin:0;}#mermaid-svg-NqWdFrRXugPsR5xI .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-NqWdFrRXugPsR5xI .cluster-label text{fill:#333;}#mermaid-svg-NqWdFrRXugPsR5xI .cluster-label span{color:#333;}#mermaid-svg-NqWdFrRXugPsR5xI .cluster-label span p{background-color:transparent;}#mermaid-svg-NqWdFrRXugPsR5xI .label text,#mermaid-svg-NqWdFrRXugPsR5xI span{fill:#333;color:#333;}#mermaid-svg-NqWdFrRXugPsR5xI .node rect,#mermaid-svg-NqWdFrRXugPsR5xI .node circle,#mermaid-svg-NqWdFrRXugPsR5xI .node ellipse,#mermaid-svg-NqWdFrRXugPsR5xI .node polygon,#mermaid-svg-NqWdFrRXugPsR5xI .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-NqWdFrRXugPsR5xI .rough-node .label text,#mermaid-svg-NqWdFrRXugPsR5xI .node .label text,#mermaid-svg-NqWdFrRXugPsR5xI .image-shape .label,#mermaid-svg-NqWdFrRXugPsR5xI .icon-shape .label{text-anchor:middle;}#mermaid-svg-NqWdFrRXugPsR5xI .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-NqWdFrRXugPsR5xI .rough-node .label,#mermaid-svg-NqWdFrRXugPsR5xI .node .label,#mermaid-svg-NqWdFrRXugPsR5xI .image-shape .label,#mermaid-svg-NqWdFrRXugPsR5xI .icon-shape .label{text-align:center;}#mermaid-svg-NqWdFrRXugPsR5xI .node.clickable{cursor:pointer;}#mermaid-svg-NqWdFrRXugPsR5xI .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-NqWdFrRXugPsR5xI .arrowheadPath{fill:#333333;}#mermaid-svg-NqWdFrRXugPsR5xI .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-NqWdFrRXugPsR5xI .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-NqWdFrRXugPsR5xI .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-NqWdFrRXugPsR5xI .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-NqWdFrRXugPsR5xI .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-NqWdFrRXugPsR5xI .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-NqWdFrRXugPsR5xI .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-NqWdFrRXugPsR5xI .cluster text{fill:#333;}#mermaid-svg-NqWdFrRXugPsR5xI .cluster span{color:#333;}#mermaid-svg-NqWdFrRXugPsR5xI div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-NqWdFrRXugPsR5xI .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-NqWdFrRXugPsR5xI rect.text{fill:none;stroke-width:0;}#mermaid-svg-NqWdFrRXugPsR5xI .icon-shape,#mermaid-svg-NqWdFrRXugPsR5xI .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-NqWdFrRXugPsR5xI .icon-shape p,#mermaid-svg-NqWdFrRXugPsR5xI .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-NqWdFrRXugPsR5xI .icon-shape .label rect,#mermaid-svg-NqWdFrRXugPsR5xI .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-NqWdFrRXugPsR5xI .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-NqWdFrRXugPsR5xI .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-NqWdFrRXugPsR5xI :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} 自动同步
主库挂了
客户端
主库 PRIMARY
从库 SECONDARY
自动选举 - 从库变主库

副本集解决的核心问题

  • 主库宕机 → 从库自动顶上(无需人工干预)
  • 数据冗余 → 主库磁盘坏了,从库还有数据
  • 读写分离 → 主库写,从库读,分担压力

二、环境准备

角色 部署方式 IP 端口 MongoDB 版本
Primary 物理机 192.168.1.100 27017 3.6
Secondary Docker 192.168.1.101 27017(映射8017) 3.6

主库配置(物理机)

mongod.conf

yaml 复制代码
net:
  port: 27017
  bindIp: 0.0.0.0

replication:
  replSetName: rs0

security:
  keyFile: /data/mongodb.key

storage:
  dbPath: /data/mongo/db

生成 Keyfile(节点间认证用)

bash 复制代码
# 在主库生成
openssl rand -base64 756 > /data/mongodb.key
chmod 400 /data/mongodb.key
chown 999:999 /data/mongodb.key

# 复制到从库
scp /data/mongodb.key root@192.168.1.101:/data/mongodb.key

三、部署步骤

主库初始化

bash 复制代码
# 启动 MongoDB
mongod -f /etc/mongod.conf

# 初始化副本集
mongo 127.0.0.1:27017/admin --eval '
  rs.initiate({
    _id: "rs0",
    members: [{ _id: 0, host: "192.168.1.100:27017" }]
  })
'

从库部署(Docker)

bash 复制代码
# 启动容器
docker run -d --name mongo_node1 --restart always \
  -p 8017:27017 \
  -v /data/mongo/sec:/data/db \
  -v /data/mongodb.key:/data/mongodb.key:ro \
  mongo:3.6.23 \
  mongod --replSet rs0 --bind_ip_all --keyFile /data/mongodb.key

# 加入副本集(在主库执行)
mongo 127.0.0.1:27017/admin --eval 'rs.add("192.168.1.101:8017")'

验证

javascript 复制代码
rs.status()
// 应看到:
// PRIMARY  health: 1  stateStr: "PRIMARY"
// SECONDARY health: 1  stateStr: "SECONDARY"

四、创建用户与开启认证

bash 复制代码
# 创建管理员
mongo 127.0.0.1:27017/admin --eval '
  db.createUser({
    user: "admin",
    pwd: "123456",
    roles: [{ role: "root", db: "admin" }]
  })
'

之后连接必须带用户名密码:

bash 复制代码
mongo 192.168.1.100:27017/admin -u admin -p 123456

五、测试高可用

bash 复制代码
# 在主库写入测试数据
mongo 192.168.1.100:27017/test -u admin -p 123456 \
  --eval 'db.test.insert({msg: "副本集测试"})'

# 模拟主库故障
systemctl stop mongod

# 等待几秒,查看从库状态
docker exec mongo_node1 mongo --eval 'rs.status()'
# 从库自动变成 PRIMARY

# 恢复主库后,它会作为从库重新加入
systemctl start mongod

六、应用连接

javascript 复制代码
// Node.js
const uri = 'mongodb://admin:密码@192.168.1.100:27017,192.168.1.101:8017/mydb?replicaSet=rs0';

// Java
MongoClientURI uri = new MongoClientURI(
  "mongodb://admin:密码@192.168.1.100:27017,192.168.1.101:8017/mydb?replicaSet=rs0"
);

七、总结

复制代码
✅ 主从自动同步
✅ 主库挂了自动切换
✅ 节点间加密通信
✅ 客户端认证保护
❌ 注意版本统一(主从必须兼容)
相关推荐
雨辰AI1 小时前
SpringBoot3 整合达梦 DM9 超详细入门实战|从零搭建可直接上线
数据库·微服务·架构·政务
我是一颗柠檬2 小时前
【MySQL全面教学】MySQL性能优化实战Day13(2026年)
数据库·后端·sql·mysql·性能优化·database
AI人工智能+电脑小能手2 小时前
【大白话说Java面试题 第84题】【Mysql篇】第14题:为什么用 InnoDB 存储引擎的表建议用整型的自增主键?
java·开发语言·数据库·mysql·面试
张彦峰ZYF2 小时前
检索增强生成(RAG)系统的基础:全面深入矢量数据库
数据库·大模型·rag
Elastic 中国社区官方博客3 小时前
我们如何在 Elasticsearch Serverless 上将向量搜索吞吐量提升一倍
大数据·数据库·人工智能·elasticsearch·搜索引擎·云原生·serverless
一 乐3 小时前
高校实习信息发布网站|基于Spring Boot的高校实习信息发布网站的设计与实现(源码+数据库+文档)
java·数据库·spring boot·后端·论文·毕设·高校实习信息发布网站
zgl_200537794 小时前
源代码:跨数据库通用SQL语法解析与标注拆解
大数据·数据库·数据仓库·sql·etl·源代码管理
雪度娃娃4 小时前
存储器层次结构——磁盘硬盘存储
服务器·网络·数据库·计算机组成原理
暴力求解4 小时前
Mysql数据库基础
数据库·mysql·操作系统