在 MongoDB 副本集中通过读取 Secondary Nodes 提升读取容量的陷阱
Source: Dev.to
想象我们负责管理支撑我国国家金融支付系统(类似巴西的 Pix)的 MongoDB 集群。我们的应用被设计为读密集型,每 20 次读操作对应一次写操作。
随着黑色星期五的临近,这段时间对我们国家金融支付系统至关重要,我们被委托制定集群的扩容方案,以应对需求激增。鉴于系统是读密集型的,我们正在探索提升集群读取性能和容量的方法。
我们负责的系统支撑约 60 % 的全国交易,因此确保该 MongoDB 集群的最高可用性至关重要——它是我国经济的脊梁。
AI‑生成的建议
当我们向多个 AI 模型(GPT‑5、Grok Code Fast 1、Claude Sonnet 4、Gemini 2.5 Pro)询问 “如何提升 MongoDB 副本集集群的读取性能和容量?”时,常见的建议是通过 readPreference 设置 将读取分配到 secondary 节点,并增加更多 secondary 节点。
所有模型都正确提醒,secondary 的读取可能 陈旧,因为复制不是瞬时完成的。
示例场景
假设有一个包含三台节点的副本集:一台 primary 和两台 secondary。每台节点最多能处理 100 次读取 / s。
| 节点数量 | 每节点读取次数 | 总读取次数 |
|---|---|---|
| 3(primary + 2 secondary) | 80 读取 / s | 240 读取 / s(我们的需求) |
如果网络故障导致其中一台节点失效,剩余两台节点必须各自承担 120 读取 / s,超出其容量,进而可能导致进一步故障,最终使整个集群宕机。
读取容量 vs. 读取性能
- 读取容量 – 集群在不使硬件过载或显著增加延迟的情况下能够维持的读取操作数量。
- 读取性能 – 单个读取操作完成的速度。
使用 secondary 节点提升读取容量可能 降低可用性:单点故障会导致剩余节点超负荷。
在不牺牲可用性的前提下提升读取性能的策略
接近性
将 secondary 节点部署得更靠近应用,以降低网络延迟。
缓存
始终在同一节点上执行相同查询,使其缓存保留所需数据,从而加速后续读取。
安全地扩容集群
在保持高可用性的前提下提升读取容量的最可靠方式是 扩容集群,可以是垂直扩容(scale‑up)或水平扩容(scale‑out)。
垂直扩容(scale‑up)
提升现有节点的资源(CPU、内存、存储、IOPS)。
优势
- 运维简单 – 无需更改数据分布或查询路由。
- 应用改动最小 – 连接字符串和查询模式通常保持不变。
- 立即提升性能,尤其是对 CPU 或内存受限的工作负载。
劣势
- 上限限制 – 最终会达到实例规格的上限。
- 性能增长非线性 – 资源翻倍不一定能让吞吐量翻倍。
- 单节点瓶颈 – 热点文档、集合或重聚合仍可能争夺 primary 资源。
- 仅限 MongoDB EA:在 Atlas 上获取额外资源相对比本地部署更容易。
水平扩容(scale‑out)
添加分片并在分片之间划分数据。
优势
- 接近线性吞吐量增长 – 增加分片即可提升读写容量和总存储。
- 热点缓解 – 合适的分片键可以均匀分摊负载。
- 地理灵活性 – 区域分片可将数据保持在用户附近,满足数据驻留要求。
劣势
- 设计复杂 – 选择合适的分片键至关重要,错误的选择会导致不均衡或低效的 scatter‑gather 查询。
- 运维开销 – 块平衡、重新分片以及跨分片查询/事务的管理增加了复杂度。
- 查询模式考量 – 为避免 fan‑out,应用通常需要在查询中包含分片键。
- 仅限 MongoDB EA:在 Atlas 上获取额外资源相对比本地部署更容易。
欲了解更多 MongoDB 扩容信息,请参阅 《水平 vs 垂直扩容指南》 与 《数据库扩容》,或查阅官方 MongoDB 文档中的扩容策略章节。
只读节点与分析节点(MongoDB Atlas)
有些读者可能会建议使用 Atlas 的 只读 或 分析 节点来提升读取容量。
Atlas 文档中的关键要点:
- 只读节点 “在节点各自的服务区域内优化本地读取”。
- 只读节点 “不提供高可用性,因为它们不参与选举”。
第一点表明只读节点可以降低本地读取的延迟,但 并未 提升整体读取容量。第二点确认只读节点不贡献高可用性,而高可用性是我们系统的关键需求。因此,这类节点并不能解决我们的容量或可用性问题。