根本原因是wiredtiger静态加密强制禁用页压缩,导致写放大2–3倍;同时aes-ni缺失时加解密退化为软件实现,引发cpu瓶颈与刷脏死循环。

开启加密后磁盘I/O显著增加,根本原因不是“加密本身慢”,而是WiredTiger在启用静态加密(Encryption at Rest)时,强制将所有数据页写入前做加解密操作,并且默认禁用部分I/O优化路径——比如页压缩会在加密后被跳过,导致写入量变大、刷脏更频繁。
WiredTiger加密与压缩互斥导致写放大
WiredTiger的静态加密(通过storage.wiredTiger.engineConfig.encryptionKeyFile启用)与blockCompressor不兼容。一旦设置encryptionKeyFile,引擎会自动忽略storage.wiredTiger.collectionConfig.blockCompressor配置,无论你设成snappy还是zstd都无效。
- 后果:原本能压缩到 1/3 大小的数据页,现在以明文尺寸落盘 → 写入字节数上升 2–3 倍
- 典型表现:
mongostat中netIn和netOut变化不大,但disk列的read/writeKB/s 翻倍,page相关指标(如pgsw,pgs)同步飙升 - 验证方式:运行
db.serverStatus().wiredTiger["cache"]["bytes currently in the cache"]对比开启前后,若缓存命中率未降但pages written from cache暴涨,基本可锁定是写放大
Linux内核不支持AES-NI时CPU成为I/O瓶颈
MongoDB静态加密使用AES-256-CBC,依赖CPU的AES-NI指令集加速。若宿主机(尤其是云服务器)未启用或内核未暴露该能力,加解密会退回到纯软件实现,单线程吞吐不足 20 MB/s,而WiredTiger后台线程持续刷脏,形成“CPU等加密 → 加密拖慢刷脏 → 缓存dirty堆积 → 更多刷脏排队”死循环。
- 快速检测:执行
grep -q aes /proc/cpuinfo && echo "AES-NI available" || echo "missing";若输出 missing,加密必成瓶颈 - Ubuntu上常见陷阱:KVM虚拟机未透传
+aesCPU flag,或内核启动参数含nopti/nospectre_v2等安全补丁导致AES-NI被禁用 - 临时缓解:降低
storage.wiredTiger.engineConfig.cacheSizeGB(例如从8GB压到4GB),减少单位时间需加密的脏页数,但会牺牲缓存效率
避免全量重加密触发批量I/O风暴
对已有数据目录启用加密,MongoDB不会原地改写,而是启动一个后台迁移任务:逐个collection重建为加密格式。这个过程本质是「读原始页 → 解密(空操作)→ 加密 → 写新页 → 删除旧文件」,期间同时产生双倍读+双倍写,且无法限速。
- 错误做法:直接在生产
mongod.conf里加encryptionKeyFile并重启 → 触发不可控的全量重加密 - 正确路径:先停机,用
mongod --repair --encryptionKeyFile=xxx --dbpath=/old导出为BSON,再用mongorestore --uri="mongodb://..."导入到新加密实例;或使用mongodump+mongorestore配合--gzip压缩传输流,避开磁盘层加解密 - 注意:
mongorestore导入时若目标库已启用加密,它只负责写入加密页,不参与重加密逻辑,因此无I/O风暴风险
真正难处理的从来不是“怎么开加密”,而是“加密后谁来扛住多出来的那30%~300% I/O”。硬件加速不可缺,压缩让路是事实,而任何试图绕过WiredTiger加密机制(比如用LUKS全盘加密)的做法,都会破坏WiredTiger的检查点原子性和崩溃恢复能力——这点容易被忽略,但线上出事就是数据不一致。











