1. 为什么现在还有人要在 CentOS 6.X 上装 MongoDB 4.0
先把话说在前头:CentOS 6 早就停止官方维护了,MongoDB 4.0 也不是什么新版本。但现实情况是,不少工厂产线、医院内网、政企离线环境里跑着的还是 CentOS 6.5 到 6.9 这一批老机器,业务系统动不了,可数据量又涨上来了,原来的 MongoDB 2.6 或者 3.0 在并发和聚合查询上已经明显吃力。这时候最务实的做法不是换系统,而是在现有环境里把 MongoDB 升到 4.0——它是最后一个官方还提供 CentOS 6 兼容包的稳定大版本,再往上 4.2 就要求 glibc 2.17 以上,CentOS 6 自带的 glibc 2.12 直接卡死。
所以这篇东西解决的就是一个很具体的场景:在一台不能重装、不能联网、glibc 版本偏低的 CentOS 6.X 机器上,把 MongoDB 4.0 跑起来,并且这套操作在 CentOS 7.X 上同样适用。我会把依赖库、yum 源、目录规划、配置文件、systemd 与 SysVinit 的差异、以及几个我实际踩过的坑都讲清楚。适合谁看?适合手里有老服务器、需要做离线部署、或者正在做系统迁移前期验证的运维和后台开发。新手也能照着做,因为每一步我都会说清楚"为什么这么干"。
需要提前说明的是,MongoDB 4.0 相比 3.x 引入了副本集事务、$convert类型转换、$toString等聚合操作符,还有对 WiredTiger 存储引擎的进一步优化。这些特性在老业务里未必马上用得上,但升级到 4.0 之后,后续往 4.2、4.4 迁移的路径会顺畅很多,因为 4.0 是官方明确支持"滚动升级"的中间跳板版本。换句话说,这一步不是终点,是给未来留后路。
2. 安装前的环境盘点与依赖梳理
2.1 先确认你的系统到底能不能装
动手之前,先跑几条命令把底摸清楚。很多人一上来就yum install,结果报一堆依赖错误,回头再查浪费时间。
cat /etc/redhat-release uname -r ldd --version | head -1 free -h df -h /var第一条看系统版本,CentOS 6.5 到 6.10 都在支持范围内。第二条看内核,MongoDB 4.0 官方要求 Linux 内核 2.6.36 以上,CentOS 6 的 2.6.32 其实略低于这个线,但实测在 6.6 以后的内核上跑没问题,因为 Red Hat 给 2.6.32 打了大量 backport 补丁。第三条看 glibc,必须是 2.12 或更高,CentOS 6 默认就是 2.12,刚好卡在门槛上。第四条看内存,MongoDB 4.0 的 WiredTiger 引擎默认会用掉可用内存的一半做缓存,建议至少 2GB,低于 1GB 的机器跑起来会非常难受。第五条看/var分区空间,数据目录默认放这里,别装到一半发现磁盘满了。
提示:如果你的 CentOS 6 是 6.0 到 6.4 这几个早期版本,glibc 可能低于 2.12,这种情况要么升级 glibc(风险极高,容易把系统搞崩),要么放弃 4.0 改用 3.6。别硬上。
2.2 依赖库和工具的准备
MongoDB 4.0 的官方 RPM 包依赖几个基础库,离线环境下这些必须提前备好。核心依赖是openssl、libcurl、cyrus-sasl和net-snmp(如果启用 SNMP 监控)。CentOS 6 自带的 openssl 是 1.0.1e,MongoDB 4.0 需要 1.0.1 以上,勉强够用,但如果你的系统很久没更新,建议先把 openssl 升到 1.0.2 系列,避免 TLS 握手时出现协议不兼容。
yum install -y openssl libcurl cyrus-sasl cyrus-sasl-plain net-snmp联网环境直接跑上面这条就行。离线环境的话,你需要在一台同版本的联网机器上用yumdownloader把这些包和它们的依赖全部下载下来,然后拷到目标机器上用rpm -ivh或者yum localinstall安装。这里有个经验:yumdownloader --resolve会自动把依赖树拉全,比手动一个个找靠谱得多。
yumdownloader --resolve --destdir=/tmp/mongo-deps openssl libcurl cyrus-sasl cyrus-sasl-plain net-snmp下载完把/tmp/mongo-deps整个目录打包拷过去,目标机器上执行yum localinstall /tmp/mongo-deps/*.rpm即可。注意--resolve有时候会漏掉一些间接依赖,装的时候如果报缺包,再单独补下载。
2.3 目录规划:别把数据放在默认位置
MongoDB 默认数据目录是/var/lib/mongo,日志是/var/log/mongodb。生产环境我强烈建议单独规划,原因有两个:一是/var分区通常不大,数据一涨就爆;二是后续做备份、迁移、挂载独立磁盘时,独立目录更好操作。
我习惯的规划是这样的:
| 用途 | 路径 | 说明 |
|---|---|---|
| 数据目录 | /data/mongodb/data | 挂独立数据盘,权限 700 |
| 日志目录 | /data/mongodb/log | 单独放,方便切割 |
| 配置目录 | /etc/mongod.conf | 保持默认位置 |
| 二进制目录 | /usr/bin | RPM 安装自动放这里 |
创建目录并授权:
mkdir -p /data/mongodb/data /data/mongodb/log chown -R mongod:mongod /data/mongodb chmod 700 /data/mongodb/data这里chmod 700是必须的,MongoDB 启动时会检查数据目录权限,如果其他用户可读可写,它会拒绝启动并报permissions on /data/mongodb/data are too open。这个坑我见过太多次了,尤其是用 root 手动创建目录之后忘了改权限。
3. 安装 MongoDB 4.0 的完整实操流程
3.1 配置 yum 源(联网与离线两种方式)
联网环境下,直接写一个 yum 源文件就行。MongoDB 官方源地址是repo.mongodb.org,但老环境里经常遇到 TLS 版本协商失败的问题,因为 CentOS 6 的 curl 和 openssl 太老。如果yum makecache报 SSL 错误,可以临时用--nogpgcheck跳过校验,或者改用国内镜像源。
cat > /etc/yum.repos.d/mongodb-org-4.0.repo << 'EOF' [mongodb-org-4.0] name=MongoDB Repository baseurl=https://repo.mongodb.org/yum/redhat/$releasever/mongodb-org/4.0/x86_64/ gpgcheck=1 enabled=1 gpgkey=https://www.mongodb.org/static/pgp/server-4.0.asc EOF注意$releasever在 CentOS 6 上会解析成6,正好对应官方源里的6目录。CentOS 7 上解析成7,同样适用。这就是标题里说"适用于 CentOS 7.X"的原因——源地址的版本变量是通用的,配置文件也基本一致,差异只在服务管理方式上。
离线环境就把 RPM 包直接下载好。官方提供两种包:mongodb-org是元包,会拉全套;mongodb-org-server、mongodb-org-shell、mongodb-org-tools是分体包。离线部署建议下分体包,按需安装,省空间。
# 联网机器上执行 yumdownloader --resolve --destdir=/tmp/mongo-rpm mongodb-org-server-4.0.28 mongodb-org-shell-4.0.28 mongodb-org-tools-4.0.28版本号建议选 4.0 系列的最后一个版本 4.0.28,bug 修复最全。下载完拷到目标机器,rpm -ivh安装即可。
3.2 安装过程与关键参数确认
联网环境直接:
yum install -y mongodb-org-4.0.28 mongodb-org-server-4.0.28 mongodb-org-shell-4.0.28 mongodb-org-tools-4.0.28安装完成后,RPM 会自动创建mongod用户和组,并生成默认配置文件/etc/mongod.conf。这里有个细节:CentOS 6 的 RPM 包默认用 SysVinit 脚本/etc/init.d/mongod来管理服务,而 CentOS 7 用的是 systemd 单元/usr/lib/systemd/system/mongod.service。两者配置文件路径一样,但启动命令不同。
验证安装:
mongod --version mongo --version正常输出应该显示db version v4.0.28。如果报error while loading shared libraries: libcrypto.so.10,说明 openssl 版本不对,需要检查ldd $(which mongod)看具体缺哪个库。
3.3 配置文件 mongod.conf 的逐项解读
默认配置文件内容很简略,生产环境必须改。我一般会改成下面这样:
systemLog: destination: file logAppend: true path: /data/mongodb/log/mongod.log storage: dbPath: /data/mongodb/data journal: enabled: true wiredTiger: engineConfig: cacheSizeGB: 1 processManagement: fork: true pidFilePath: /data/mongodb/mongod.pid net: port: 27017 bindIp: 127.0.0.1 security: authorization: disabled逐项说下为什么这么配。systemLog.logAppend: true让日志追加而不是覆盖,方便排查历史问题。storage.journal.enabled: true是 WiredTiger 的预写日志,保证崩溃恢复,生产环境绝对不能关。cacheSizeGB默认是可用内存的一半,但如果机器上还跑着别的服务,手动限制到 1GB 到 2GB 更稳妥,避免 MongoDB 把内存吃光导致系统 OOM。
processManagement.fork: true让 mongod 以守护进程方式运行,配合pidFilePath方便管理。net.bindIp默认只监听本地,如果要远程访问,改成0.0.0.0或者具体内网 IP,但强烈建议配合防火墙和认证,MongoDB 裸奔被挖矿的事情太多了。
security.authorization先设为disabled,等创建完管理员用户后再改成enabled。这个顺序不能反,否则你连创建用户的权限都没有。
注意:CentOS 6 上如果启用了 SELinux,需要额外处理。要么把 SELinux 设为 permissive,要么给数据目录打上正确的上下文标签
chcon -R -t mongod_var_lib_t /data/mongodb/data。我一般直接setenforce 0并改/etc/selinux/config为SELINUX=permissive,因为老业务环境里 SELinux 带来的麻烦远大于收益。
4. 启动服务与初始化配置
4.1 CentOS 6 与 CentOS 7 的启动差异
CentOS 6 用 SysVinit:
service mongod start chkconfig mongod onCentOS 7 用 systemd:
systemctl start mongod systemctl enable mongod启动后检查状态和日志:
tail -f /data/mongodb/log/mongod.log看到waiting for connections on port 27017就说明起来了。如果启动失败,日志里通常会有明确原因,常见的是目录权限、端口占用、配置文件语法错误。YAML 对缩进极其敏感,必须用空格,不能用 Tab,这一点坑过无数人。
4.2 创建管理员用户并开启认证
先用 mongo shell 连进去:
mongo --host 127.0.0.1 --port 27017切换到 admin 库,创建超级管理员:
use admin db.createUser({ user: "siteAdmin", pwd: "换成你的强密码", roles: [ { role: "userAdminAnyDatabase", db: "admin" }, "readWriteAnyDatabase" ] })创建完退出,把配置文件里的authorization改成enabled,重启服务。然后再连进去验证:
mongo -u siteAdmin -p --authenticationDatabase admin能进去就说明认证生效了。这里有个经验:密码里如果包含@、:、/这些特殊字符,在连接字符串里需要 URL 编码,否则会解析错误。我一般建议密码用大小写字母加数字加!、#、%这类,避开 URL 保留字符。
4.3 业务库和普通用户的创建
管理员账号只用来管理,业务连接要用单独的库和用户。比如给一个叫appdb的库建用户:
use appdb db.createUser({ user: "appUser", pwd: "另一个强密码", roles: [ { role: "readWrite", db: "appdb" } ] })这样即使这个账号泄露,影响范围也只限于appdb。最小权限原则在老系统里尤其重要,因为很多老业务代码里硬编码了连接串,一旦泄露就是全库沦陷。
5. 常见问题排查与避坑经验
5.1 启动失败类问题速查
| 现象 | 可能原因 | 解决方法 |
|---|---|---|
| 启动后立即退出 | 数据目录权限不对 | chown -R mongod:mongod并chmod 700 |
报libcrypto.so.10缺失 | openssl 版本不匹配 | 升级 openssl 或安装兼容包 |
报Address already in use | 27017 端口被占 | netstat -tlnp | grep 27017查进程 |
| YAML 解析错误 | 用了 Tab 缩进 | 全部改成空格 |
| 日志无输出 | 日志目录权限或路径错误 | 检查systemLog.path和目录权限 |
| 内存溢出被 kill | cacheSizeGB 太大 | 调小到 1GB 或更低 |
5.2 几个我实际踩过的坑
第一个坑是NUMA 架构下的性能抖动。CentOS 6 在多路 CPU 服务器上默认启用 NUMA,MongoDB 在这种环境下会出现内存分配不均、偶发卡顿。解决办法是启动时加numactl --interleave=all,或者直接在 BIOS 里关掉 NUMA。我一般是在/etc/init.d/mongod的启动命令前加上numactl --interleave=all,实测下来稳定很多。
第二个坑是透明大页(THP)。CentOS 6 默认开启 THP,MongoDB 官方明确建议关闭,否则 WiredTiger 的内存管理会出现延迟尖刺。关闭方法:
echo never > /sys/kernel/mm/redhat_transparent_hugepage/enabled echo never > /sys/kernel/mm/redhat_transparent_hugepage/defrag要永久生效就写进/etc/rc.local。这个改动对数据库性能提升是实打实的,尤其是写入密集场景。
第三个坑是文件句柄数限制。CentOS 6 默认ulimit -n是 1024,MongoDB 在高并发下会报Too many open files。改/etc/security/limits.conf:
mongod soft nofile 64000 mongod hard nofile 64000改完重启服务,用cat /proc/$(cat /data/mongodb/mongod.pid)/limits | grep files确认生效。
5.3 升级到 4.0 之后的兼容性检查
从 3.x 升到 4.0,有几个行为变化要注意。一是$type操作符对数组的处理逻辑变了,老代码里如果有依赖旧行为的查询,结果可能不一致。二是副本集的心跳和选举协议有调整,跨版本混跑时建议先升从节点再升主节点。三是db.collection.count()在分片集群里的行为有变化,建议改用countDocuments()。
升级前务必用mongodump做全量备份,并且在测试环境先跑一遍。我见过直接在生产上yum update然后起不来的案例,回滚都来不及。
6. 性能调优与日常维护建议
6.1 针对老硬件的参数微调
CentOS 6 的机器普遍配置不高,内存 4GB 到 8GB 居多。这种情况下cacheSizeGB设成 1 到 2 比较合适,留足内存给系统和业务进程。wiredTiger.engineConfig.journalCompressor可以设为snappy,减少日志写入量,对机械硬盘尤其有效。
连接数方面,net.maxIncomingConnections默认是 65536,老机器上没必要开这么大,设成 1000 到 2000 就够,避免连接堆积拖垮系统。
6.2 备份策略的落地
老环境里我最推荐的是mongodump加定时任务,简单可靠。每天凌晨低峰期跑一次全量,保留最近 7 天:
mongodump --host 127.0.0.1 --port 27017 -u siteAdmin -p 密码 --authenticationDatabase admin --out /data/backup/$(date +%Y%m%d) find /data/backup -type d -mtime +7 -exec rm -rf {} \;如果数据量大,mongodump会拖慢主库,可以考虑在从节点上执行,或者用文件系统快照。但老环境里往往没有 LVM 或者云盘快照,所以mongodump还是最实际的方案。
6.3 监控指标的关注重点
MongoDB 4.0 自带db.serverStatus(),重点看几个指标:connections.current是否接近上限,globalLock.currentQueue.total是否持续偏高,wiredTiger.cache.bytes currently in the cache是否接近cacheSizeGB。如果队列数长期大于 0,说明有慢查询,需要开profiling排查。
db.setProfilingLevel(1, { slowms: 100 }) db.system.profile.find().sort({ ts: -1 }).limit(10)把超过 100ms 的操作记录下来,定期分析,这是老系统上最有效的优化手段。
7. 关于这套方案在 CentOS 7.X 上的复用
标题里特意标注"适用于 CentOS 7.X",不是随便写的。这套流程里,yum 源配置、RPM 包、mongod.conf内容、用户创建、备份脚本,在 CentOS 7 上完全通用。唯一的差异是服务管理命令从service换成systemctl,以及 CentOS 7 默认的 glibc 是 2.17,可以直接上 MongoDB 4.2 甚至 4.4,不必卡在 4.0。
如果你是在做系统迁移,从 CentOS 6 迁到 CentOS 7,我的建议是:先在 7 上装同版本 MongoDB,用mongodump从 6 导出,再mongorestore到 7,验证业务无误后再切流量。这样比原地升级系统安全得多,因为 CentOS 6 到 7 的原地升级基本等于重装,风险不可控。
最后分享一个我在实际迁移中总结的小技巧:把mongod.conf里的bindIp在迁移期间临时设为0.0.0.0,配合防火墙只放行新老两台机器的 IP,这样可以在不切流量的情况下做双写验证。验证通过后再改回127.0.0.1并正式切换。这个中间态能帮你省掉很多来回折腾的时间。