我是去年接手的一个项目,业务在跑 MongoDB,数据量不大但绝对不能挂。客户预算有限,不上分片集群,也买不起商业版,要求就是高可用。我最后选了“三台云主机 + Docker + MongoDB 副本集”这个方案,一直稳定跑到今天。如果你也打算在生产环境用 Docker 部署 MongoDB 副本集,这篇可以完整给你参考:架构怎么规划、Compose 文件怎么编写、副本集初始化顺序为什么不能乱、认证开启后踩过哪些坑,我都整理在下面。
这个方案比较适合中小规模业务、微服务内网环境、自己私有的测试/预发生产集群,也适合想用一套可复现的方式快速搭建高可用 MongoDB 的团队。读之前先明确一点:这里说的“生产级”不是指大规模高并发,而是指具备持久化、认证、故障自愈、可备份恢复这几个基本能力。如果你是要做日均亿级请求的写入,那架构就完全不是这篇文章的范畴了。
1. 为什么生产环境我坚持用 Docker 跑 MongoDB 副本集
很多人听到“生产”就下意识觉得应该裸机安装,Docker 只是开发环境玩具。这个观念得改改了。我在多套环境里对比过:Docker 跑 MongoDB 的额外损耗在个位数百分比以内,但换来的是部署速度、可迁移性、版本一致性和故障恢复效率的指数级提升。
1.1 直接装 MongoDB 和 Docker 部署的最大差异
直接在三台机器上 apt install mongodb-org 然后改配置,看起来也不复杂,但现实问题在于:
- 三台机器的操作系统版本、依赖库、mongod 版本可能出现差异,一旦某台的 libssl 升级出问题,整个副本集的行为就开始诡异;
- 手动安装时 MongoDB 的数据目录、日志目录、配置文件分散在 /var/lib、/var/log、/etc 下,迁移一台节点时要把它们完整捞出来,非常容易漏;
- 如果要升级 MongoDB 版本,逐台停服务、替换二进制、检查兼容性,一个晚上就没了。
用 Docker 之后,镜像锁定了 mongo 版本,所有配置通过 bind mount 统一管理,数据卷可以在任意同配置机器上拉起来。迁移节点就是一个 docker compose up -d。实测下来,一套三节点副本集从零到全部加入并初始化完成,熟练的话 20 分钟内能搞定。
1.2 Docker 跑数据库的“性能损耗”到底有多少
我在交付前专门用 mongostat 和 mongoperf 对比过物理机直装和 Docker 容器化的吞吐与延迟。结论是:在默认桥接网络、数据目录挂载宿主机普通 SSD 的前提下,吞吐量差异在 3%-5% 左右,延迟增加不到 1ms。这对绝大多数业务来说完全无感。
当然有个前提:你启动容器时不能带着一堆不必要的重定向、磁盘限制和嵌套存储驱动。生产部署建议用 --storage-driver=overlay2、数据卷直接挂到宿主机磁盘,不要用 docker volume 的默认系统盘。云服务器环境里,直接把宿主机的一块独立数据盘挂到 /data,再 bind mount 到容器里是最稳的做法。
1.3 什么时候不推荐用 Docker 部署副本集
说实话,这套方案也不是万能的。如果你遇到下面几种情况,我更建议用物理机、云厂商的托管数据库或者 Kubernetes 方案:
- 单节点写入负载非常高,要求极低延迟、极稳定的磁盘 IOPS,这时宿主机直接跑 mongod 和容器化之间一点性能差距都会被放大;
- 需要精细控制 NUMA、透明大页、文件系统预读这些底层参数,Docker 容器对部分系统级调优存在隔离,虽然可以通过 privileged 绕开,但没必要;
- 团队缺乏 Docker 运维基础,出了问题没人能第一时间处理容器日志。
但如果你的业务属于常规 CRUD、中等 QPS、希望部署快且好维护,Docker 完全能扛住生产要求。下面我就以这套思路来拆解完整方案。
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. 三机三节点架构规划:从IP、数据盘到系统参数一个都不能少
生产部署最忌讳的是拿到三台机器就开始跑 docker run,最后发现端口冲突、数据目录没分开、机器时钟不同步、重启后容器没拉起。所以第一步一定是纸上谈兵——把架构图画清楚,把我们这次的角色划分和目录规划敲定了再动手。
2.1 副本集角色划分与IP/端口规划
这个方案里三台机器都是数据节点,不单独放仲裁节点。原因很简单:我们在企业中实际遇到的情况是,仲裁节点不存数据,多一台机器就多一份成本,三台机器全部做数据节点能让副本集在任一节点宕机后仍有完整数据副本。如果你的机器资源非常紧张,才考虑“2 数据 + 1 仲裁”,否则一律建议 3 数据节点。
我用到的规划如下:
| 节点 | IP 示例 | 角色 | MongoDB 端口 | 宿主机数据目录 |
|---|---|---|---|---|
| mongo-1 | 192.168.1.11 | 主节点/备份节点 | 27017 | /data/mongo/mongo-1 |
| mongo-2 | 192.168.1.12 | 副本节点 | 27017 | /data/mongo/mongo-2 |
| mongo-3 | 192.168.1.13 | 副本节点 | 27017 | /data/mongo/mongo-3 |
副本集名称我用的是 rs_prod,这个名字会写进 MongoDB 配置文件和初始化命令里,后续所有节点加入时都必须一致。端口统一用 27017,因为副本集内部通信(心跳、数据同步)也走这个端口。这里务必记住一个原则:生产环境的 MongoDB 只监听内网 IP,不要用 0.0.0.0 对公网开放,否则扫描端口的人一分钟内就能找上你。
2.2 数据盘挂载与目录划分
这步是很多人会忽略的坑。MongoDB 的数据文件对 IO 非常敏感,建议至少区分三块区域:
- 数据目录:存放 dbpath,也就是 MongoDB 实际数据文件,需要大容量且
