这是《MongoDB 零基础实战指南》的独立章节版。本章从概念、实操和生产排查三个视角展开,代码块保留了原书可直接运行的版本。 本章整理 MongoDB 高频面试题。回答时先给结论,再讲机制,最后补充生产实践、性能边界和故障处理。
30.1 MongoDB 是什么数据库?
MongoDB 是面向文档的分布式数据库,使用 BSON 文档保存数据,集合组织文档,支持丰富索引、聚合管道、副本集、分片和事务。
加分回答:
- 单文档操作原子;
- 多文档事务可用但应短小;
- 副本集提供高可用;
- 分片提供水平扩展;
- Schema 灵活但仍需治理。
30.2 MongoDB 支持 ACID 吗?
支持:
- 单文档更新天然原子;
- 副本集和分片集群支持多文档 ACID 事务;
- 事务需要 session、副本集环境;
- 分片事务成本更高;
- 应优先设计单文档边界。
不要回答“不支持事务”,这个结论已经过时。
30.3 内嵌和引用如何选择?
内嵌适合:
- 一起读取;
- 数量有限;
- 更新频率低;
- 生命周期一致。
引用适合:
- 无界增长;
- 独立查询;
- 多方修改;
- 文档过大。
核心是按访问模式建模,而不是机械翻译关系表。
30.4 为什么要避免无界数组?
风险:
- 文档持续增长;
- 写放大;
- 复制延迟增加;
- 索引开销增加;
- 查询投影浪费;
- 接近文档大小上限。
订单流水、评论、日志应拆集合并分页。
30.5 复合索引如何设计?
遵循 ESR:
Equality -> Sort -> Range
示例:
db.orders.createIndex({
tenant_id: 1,
status: 1,
created_at: -1
})
同时满足最左前缀,并让排序字段进入索引,避免内存排序。
30.6 explain 怎么看?
重点字段:
| 字段 | 判断 |
|---|---|
winningPlan.stage |
COLLSCAN 或 IXSCAN |
keysExamined |
索引扫描量 |
docsExamined |
文档扫描量 |
nReturned |
返回量 |
SORT |
内存排序 |
executionTimeMillis |
总耗时 |
理想情况是 nReturned 接近 keysExamined。
30.7 副本集如何工作?
流程:
client write -> primary -> oplog -> secondary apply
Primary 故障后,多数投票成员选主。生产至少三个数据节点,跨故障域部署,关键写使用 majority。
30.8 什么是 oplog?
oplog 是 local 库中的固定大小集合,记录可幂等重放的变更,用于 Secondary 同步和增量恢复。
关注:
- oplog 窗口;
- 写入速率;
- 复制延迟;
- Secondary 是否可增量追赶;
- 初始同步时间。
30.9 读写关注如何组合?
| 场景 | 组合 |
|---|---|
| 支付后读 | majority 写 + primary 读 |
| 报表 | majority 写 + secondaryPreferred 读 |
| 用户画像 | 可接受延迟读 |
| 强一致读 | linearizable 或 primary + majority |
写关注决定确认范围,读关注决定数据级别,读偏好决定成员。
30.10 为什么会回滚?
Primary 写入后未复制到多数节点就发生故障,新 Primary 当选后,旧 Primary 恢复时会回滚这些未提交写入。
防范:
- majority 写关注;
- 监控复制延迟;
- 合理多数派拓扑;
- 处理 rollback 文件;
- 演练切主。
30.11 分片键如何选择?
目标:
- 高基数;
- 低频率;
- 写入均匀;
- 高频查询可定向;
- 单调递增热点可控;
- 事务跨 shard 少。
常见选择是 tenant_id + user_id、device_id + timestamp、conversation_id + message_id。
30.12 哈希分片和范围分片怎么选?
| 类型 | 优势 | 代价 |
|---|---|---|
| 哈希 | 写入均匀 | 范围查询常广播 |
| 范围 | 范围查询高效 | 递增键易热点 |
订单按用户查多于按时间范围扫全表时,可以考虑用户哈希或复合键。
30.13 什么时候分片?
分片信号:
- 单机磁盘不足;
- 写入超过单机能力;
- 工作集长期超过内存;
- 数据增长明确;
- 索引和备份时间过长。
不解决:
- 慢查询无索引;
- 单热点文档;
- 应用连接滥用;
- 磁盘临时故障。
30.14 Change Stream 的原理是什么?
基于 oplog 的可恢复事件流,支持集合、库和集群级监听,可通过 resume token 恢复。
生产要点:
- token 持久化;
- 事件幂等;
- 全量 + 增量;
- oplog 窗口足够;
- 消费积压监控。
30.15 WiredTiger cache 为什么重要?
常用数据和索引页保存在 cache。工作集超过 cache 会增加磁盘读、延迟波动和 evict 压力。
优化:
- 控制工作集;
- 减少无效索引;
- 投影;
- 冷热分离;
- 扩内存或分片。
30.16 MongoDB 为什么会出现慢查询?
常见原因:
- COLLSCAN;
- 索引选择性差;
- 无索引排序;
- 大文档返回;
- 聚合数据放大;
- cache 压力;
- 磁盘瓶颈;
- 写冲突。
排查路径是 Profiler -> explain -> 索引 -> 资源指标。
30.17 MongoDB 和 MySQL 如何选?
MongoDB 适合文档对象、灵活字段、水平分片、Change Stream 和 JSON 契约。MySQL 适合强关系、复杂事务、强约束和成熟 SQL 生态。
不要绝对化,可通过混合架构和 CDC 组合。
30.18 生产必须做哪些保障?
- 副本集跨故障域;
- 启用认证和 TLS;
- 最小权限;
- 监控复制和 cache;
- 慢查询治理;
- 索引评审;
- 备份恢复演练;
- 容量规划;
- 升级回滚方案;
- 故障演练。
本章小结
MongoDB 面试重点集中在文档建模、索引执行计划、副本集选举、oplog、一致性、分片键、事务、Change Stream 和 WiredTiger。展示生产经验的关键是说明监控、压测、备份和故障演练。
思考题
- 为什么单文档原子性是设计优势?
- 如何用 ESR 设计索引?
- majority 写是否等于不丢任何数据?
- 分片键选择错误如何补救?
- Change Stream 与 oplog 的关系是什么?