CentOS 7 搭建 MongoDB 副本集,yum 安装必须用官方源(EPEL 版本过旧不支持 keyFile 认证和 YAML 配置),且需调优内核参数(tcp_fin_timeout=30、vm.swappiness=1、fs.file-max=655360)以避免心跳超时、选举失败或 oplog 同步卡住;配置中 security.authorization 与 keyFile 必须共存,bindIp 应明确指定成员 IP 而非 0.0.0.0,replSetName 全集一致,/etc/hosts 必须精确映射 IP 与 hostname,初始化前须逐节点验证连通性,状态异常优先查 journalctl 日志。

直接上结论:CentOS 7 搭建 MongoDB 副本集,yum 安装最稳,但必须用官方源(不能依赖 EPEL),且内核参数不调优会导致副本集心跳超时、选举失败或 oplog 同步卡住——这不是配置问题,是 Linux 层面的资源限制在咬人。
为什么必须用 MongoDB 官方 Yum 源而不是 EPEL
EPEL 提供的 mongodb 包早已停止维护,版本普遍卡在 2.6 或 3.2,不支持 replSetName 的 YAML 配置格式,更无法启用 keyFile 认证。官方源则持续更新到 6.x(截至 2026 年 5 月),且包结构清晰:mongodb-org-server 含完整服务脚本,mongodb-org-shell 提供 mongosh(替代已弃用的 mongo)。
实操建议:
- 删掉所有残留的 EPEL MongoDB 包:
yum remove mongodb* - 创建
/etc/yum.repos.d/mongodb-org-6.0.repo,内容必须含gpgcheck=1和对应 GPG key(如https://www.mongodb.org/static/pgp/server-6.0.asc),否则yum install会静默跳过关键组件 - 确认
baseurl中的$releasever被正确解析为7(不是7Server或空值),可用rpm -q --qf '%{VERSION}' centos-release验证
副本集启动前必须调的三个内核参数
MongoDB 副本集节点间靠 TCP 心跳维持状态,默认每 2 秒发一次,若系统 net.ipv4.tcp_fin_timeout 过长或 vm.swappiness 过高,会导致连接堆积、选举超时(错误日志常见 Failed to heartbeat 或 electionTimeoutMillis elapsed)。
实操建议(每台节点都执行):
-
echo 'net.ipv4.tcp_fin_timeout = 30' >> /etc/sysctl.conf—— 避免 TIME_WAIT 连接占满端口 -
echo 'vm.swappiness = 1' >> /etc/sysctl.conf—— 强制内存优先,MongoDB 对 swap 敏感,哪怕只 swap 几 MB 也会触发WT_CACHE_FULL报错 -
echo 'fs.file-max = 655360' >> /etc/sysctl.conf—— 副本集每个成员默认最多建立 64K 连接,三节点互连+客户端接入极易突破默认 8K 限制 - 执行
sysctl -p生效,用sysctl net.ipv4.tcp_fin_timeout单独验证
配置文件里最容易漏掉的两个安全项
副本集能跑通不代表生产可用。mongod 启动后若没开认证,任何知道 IP 的人都能连上去删库;若没设 bindIp 细粒度控制,防火墙一旦失效就等于裸奔。
实操建议(以 /etc/mongod.conf 为例):
-
security.authorization: enabled必须和security.keyFile同时存在,否则副本集初始化会报Authentication failed——keyFile要用openssl rand -base64 756 > /etc/mongod-keyfile生成,权限严格设为600,属主为mongod -
net.bindIp别写0.0.0.0,应明确列出本机 IP 和其他副本集成员 IP,例如:192.168.10.11,192.168.10.12,192.168.10.13,这样即使防火墙规则漏配,网络层也拦得住 -
replication.replSetName值必须全副本集一致(如rs0),且不能含下划线以外的特殊字符,否则rs.initiate()会返回Invalid replSet name
初始化副本集时最常卡住的点
进 mongosh 执行 rs.initiate() 后,状态长期停在 "startup2" 或反复刷 "still initializing",大概率不是配置错,而是 DNS 或主机名解析问题。
实操建议:
- 所有节点的
/etc/hosts必须互相映射 IP 和 hostname,例如:192.168.10.11 node1,且hostname命令输出必须与 hosts 里一致 -
rs.initiate()的参数里host字段必须用 IP,不能用 hostname(即使 hosts 已配),否则仲裁节点可能解析失败 - 用
mongosh --host 192.168.10.11:27017 --eval "db.adminCommand({ping:1})"先逐个测通每个节点的本地连接,再测跨节点连通性 - 初始化后立刻执行
rs.status().members.forEach(m => print(m.name + ': ' + m.stateStr)),确认所有成员状态为PRIMARY、SECONDARY或ARBITER,而非UNKNOWN或DOWN
真正麻烦的从来不是命令敲不对,而是 rs.status() 里某个成员的 lastHeartbeatMessage 显示 Connection refused 却死活找不到原因——这时候该去查 journalctl -u mongod -n 50,而不是反复改 mongod.conf。











