MongoDB 的 Capped Collection 是什么?
简化版
Capped Collection 是固定大小、按插入顺序保存的集合,空间满了会自动覆盖最旧文档。它适合固定容量日志、最近事件、类似环形缓冲区的场景,但不适合需要长期保留、灵活删除或随意更新变大文档的业务数据。
详细版
创建 capped collection 时要指定大小,通常也可以指定最大文档数:
db.createCollection("recent_logs", {
capped: true,
size: 1024 * 1024 * 100,
max: 100000
})
它按自然插入顺序保存,满了以后旧数据被覆盖。面试要强调它和普通集合不同:空间固定、插入顺序重要、不能像普通业务表那样自由增长。MongoDB 的 oplog 也是 capped collection 的典型应用。
完整版教学
一、Capped Collection 是固定大小集合
Capped Collection 可以理解为 MongoDB 内置的环形缓冲区。创建时给它一个最大空间,写满后会覆盖最老的数据。
db.createCollection("recent_logs", {
capped: true,
size: 104857600,
max: 100000
})
这里 size 是字节数,约 100MB;max 是最多文档数。达到任一限制后,旧文档会被淘汰。
记忆钩子:普通集合像仓库,capped collection 像固定容量队列,满了就挤掉最早的数据。
二、它为什么适合日志和最近事件
很多场景只关心最近 N 条或最近一段时间的事件,比如调试日志、设备心跳、实时监控快照。
如果用普通集合,需要定时删除老数据;如果删除不及时,集合会膨胀。如果使用 capped collection,容量天然固定。
| 场景 | 是否适合 | 原因 |
|---|---|---|
| 最近 10 万条访问日志 | 适合 | 只关心最近数据 |
| 审计日志长期留存 | 不适合 | 不能自动覆盖合规数据 |
| 订单主表 | 不适合 | 业务数据不能被挤掉 |
| oplog | 适合 | 顺序操作历史,固定窗口 |
面试里可以把它和 Redis list、环形队列类比,但要强调这是数据库集合能力。
三、自然顺序和 tailable cursor
Capped Collection 保持插入顺序,因此按 $natural 查询可以得到自然顺序。
db.recent_logs.find().sort({ $natural: -1 }).limit(20)
它还支持 tailable cursor,类似持续监听新插入数据。这个特性适合消费追加日志。
db.recent_logs.find().tailable()
不过实际生产里,复杂事件流更多会用 Kafka、消息队列或 Change Streams。Capped Collection 可以理解原理,但不要把它包装成万能消息系统。
四、为什么不适合普通业务数据
普通业务数据往往要求可长期保留、可按条件删除、可自由更新、可审计追溯。Capped Collection 的覆盖行为和这些要求冲突。
比如订单集合如果 capped,空间满后老订单被覆盖,这是不可接受的。用户表、支付表、库存表也一样。
另一个限制是文档更新不能导致文档变大超出原有空间安排。它更适合追加写,而不是频繁修改复杂对象。
追加写、固定容量、最近数据 -> capped
长期保存、随机删除、复杂更新 -> 普通集合
五、Capped Collection 和 TTL 索引的区别
TTL 索引按时间过期删除,Capped Collection 按空间和数量淘汰。两者都能清理数据,但触发条件不同。
| 机制 | 删除依据 | 适合场景 | 注意点 |
|---|---|---|---|
| Capped Collection | 空间或数量满 | 最近 N 条日志 | 老数据会被覆盖 |
| TTL 索引 | 日期字段过期 | session、验证码 | 删除不是准实时 |
如果需求是“只保留最近 100000 条”,capped 更直接。如果需求是“每条保留 7 天”,TTL 更自然。
六、oplog 是理解 capped 的经典例子
MongoDB 复制集的 oplog 本身就是 capped collection。它保存最近一段时间的写操作历史,Secondary 通过读取并应用这些操作完成复制。
这解释了为什么 oplog 有窗口概念:空间固定,写入越快,覆盖越快,能保留的历史时间就越短。
oplog size fixed
write rate high
old operations overwritten faster
replication window shorter
所以理解 capped collection,也能帮助理解复制延迟和重新同步问题。
七、常见误区与追问
- 误区:Capped Collection 是按时间过期。 它主要按空间和文档数限制淘汰,按时间过期应看 TTL 索引。
- 误区:业务主表可以用 capped 防止数据太多。 业务主数据不能被自动覆盖,应该归档、分表或生命周期管理。
- 误区:Capped Collection 可以随便删除任意旧数据。 它不是普通集合的自由删除模型,核心是顺序写和固定容量。
- 追问:它和 TTL 索引怎么选? 保留最近 N 条或固定容量用 capped,按时间生命周期用 TTL。
- 追问:为什么 oplog 用 capped? oplog 需要固定空间保存有序操作历史,超过窗口覆盖旧记录。
- 追问:tailable cursor 有什么用? 可以持续读取新追加文档,适合简单日志跟随场景。
八、加强记忆
Capped Collection 记成“固定空间、顺序追加、满了覆盖”。它适合最近日志、事件缓冲和 oplog 这类只关心窗口内数据的场景;不适合订单、用户、审计这类不能丢的业务数据。和 TTL 对比时,capped 按容量淘汰,TTL 按日期过期,一个管最近容量,一个管生命周期。