Skip to content

MongoDB 存储架构

存储引擎架构

存储引擎类型

  • WiredTiger:默认存储引擎(MongoDB 3.2+)

    • 支持文档级并发控制
    • 提供压缩选项(snappy、zlib、zstd)
    • 支持快照隔离
    • 适合大多数生产环境
  • In-Memory:内存存储引擎

    • 数据完全存储在内存中
    • 提供低延迟访问
    • 适合缓存和临时数据场景
  • MMAPv1:旧版默认存储引擎(已废弃)

    • 基于内存映射文件
    • 集合级锁
    • 不推荐在生产环境使用

存储引擎选择

场景推荐存储引擎理由
一般生产环境WiredTiger文档级锁、压缩、高性能
低延迟要求In-Memory内存访问,延迟最低
只读/缓存场景In-Memory适合频繁读取的场景
历史系统迁移MMAPv1仅用于迁移,不推荐新部署

数据文件结构

主要数据文件

  • .wt文件:WiredTiger存储引擎的数据文件

    • WiredTiger.wt:存储引擎元数据
    • sizeStorer.wt:存储集合和索引的大小信息
    • collection-*.wt:集合数据文件
    • index-*.wt:索引数据文件
  • journal目录:事务日志文件

    • 确保写操作的持久性
    • 每个日志文件大小默认128MB
    • 定期进行检查点(checkpoint)操作
  • diagnostic.data目录:诊断数据

    • 存储崩溃信息
    • 用于故障诊断和分析

文件组织

数据存储机制

文档存储格式

  • BSON格式:Binary JSON,MongoDB的底层存储格式

    • 支持更多数据类型(Date、Binary、ObjectId等)
    • 固定大小的元素,便于快速遍历
    • 紧凑的二进制表示,节省存储空间
  • 文档压缩

    • snappy:默认压缩算法,平衡压缩比和性能
    • zlib:更高压缩比,适合冷数据
    • zstd:MongoDB 4.2+支持,提供更好的压缩比和性能
yaml
# 启用文档压缩
storage:
  wiredTiger:
    collectionConfig:
      blockCompressor: zstd

索引存储

  • B树索引结构

    • 平衡树结构,支持高效的范围查询
    • 每个节点存储多个键值对
    • 根节点和内部节点仅存储索引键和指针
    • 叶子节点存储完整的索引键和文档位置
  • 索引压缩

    • 前缀压缩:减少重复索引键的存储
    • 块压缩:使用与集合相同的压缩算法
yaml
# 启用索引压缩
storage:
  wiredTiger:
    indexConfig:
      prefixCompression: true

数据页管理

  • 页大小:默认16KB(可配置)

  • 页类型

    • 数据页:存储文档数据
    • 索引页:存储索引数据
    • 溢出页:存储大文档
  • 页缓存

    • WiredTiger使用自己的缓存管理
    • 默认使用系统内存的50%
    • 可通过wiredTiger.engineConfig.cacheSizeGB配置

日志管理

Write Ahead Log (WAL)

  • 作用:确保写操作的持久性

  • 写入流程

    1. 写操作先写入WAL日志
    2. 日志写入磁盘后,操作才返回成功
    3. 定期将内存中的数据刷新到数据文件
  • 日志配置

yaml
storage:
  journal:
    enabled: true
    commitIntervalMs: 100  # 日志提交间隔
    directoryPerDB: false  # 每个数据库单独的日志目录

检查点机制

  • 作用:将内存中的数据快照刷新到磁盘

  • 触发条件

    • 每60秒自动触发
    • 日志文件达到128MB时触发
    • 手动执行db.runCommand({ checkpoint: 1 })
  • 检查点流程

    1. 创建数据快照
    2. 将快照数据写入磁盘
    3. 更新元数据,标记检查点完成

存储优化

数据压缩优化

  • 选择合适的压缩算法

    • 热数据:使用snappy或zstd
    • 冷数据:使用zlib
    • 根据数据特性进行测试选择
  • 压缩效果监控

javascript
// 查看压缩效果
db.collection.stats().wiredTiger.block-manager.compression-ratio

存储引擎缓存优化

  • 缓存大小调整
    • 根据系统内存大小调整
    • 建议为其他进程预留足够内存
    • 监控缓存使用率,避免缓存不足
yaml
# 配置缓存大小
storage:
  wiredTiger:
    engineConfig:
      cacheSizeGB: 8  # 设置为8GB

文件系统优化

  • 文件系统选择

    • Linux:推荐XFS或EXT4
    • Windows:NTFS
    • macOS:APFS或HFS+
  • 文件系统挂载选项

    • noatime:禁用访问时间更新
    • nodiratime:禁用目录访问时间更新
    • 调整I/O调度器(如使用deadline或none)

大文档处理

文档大小限制

  • MongoDB单文档大小限制为16MB
  • 超过限制的文档需要特殊处理:
    • 使用GridFS存储
    • 拆分为多个文档
    • 存储外部引用

GridFS机制

  • 组成部分

    • fs.files:存储文件元数据
    • fs.chunks:存储文件数据块(默认255KB)
  • 使用场景

    • 存储大型文件(如图片、视频)
    • 需要查询文件元数据
    • 需要原子性的文件操作
bash
# 使用mongofiles上传文件
mongofiles --host mongodb:27017 --db test put large-file.zip

# 下载文件
mongofiles --host mongodb:27017 --db test get large-file.zip

存储监控与维护

存储监控指标

  • 存储使用率

    • dbStats.dataSize:数据大小
    • dbStats.storageSize:存储大小(压缩后)
    • dbStats.indexSize:索引大小
  • 缓存指标

    • wiredTiger.cache.bytes currently in the cache
    • wiredTiger.cache.percent dirty pages in the cache
    • wiredTiger.cache.pages evicted by application threads
  • I/O指标

    • disk.io.reads
    • disk.io.writes
    • disk.io.readWait
    • disk.io.writeWait

存储维护操作

  • 碎片整理
    javascript
    // 整理集合碎片

db.collection.reIndex() // 重建索引 db.collection.compact() // 压缩集合


- **检查点管理**:
```javascript
// 手动触发检查点
db.runCommand({ checkpoint: 1 })
  • 日志管理
    javascript
    // 查看日志状态

db.adminCommand({ getLog: 'journal' })


## 常见问题(FAQ)

### Q1: WiredTiger和MMAPv1的主要区别是什么?

A1: WiredTiger和MMAPv1的主要区别:
- 锁粒度:WiredTiger是文档级锁,MMAPv1是集合级锁
- 压缩:WiredTiger支持多种压缩算法,MMAPv1不支持
- 并发性能:WiredTiger支持更高的并发写入
- 内存管理:WiredTiger有自己的缓存管理,MMAPv1依赖操作系统

### Q2: 如何选择合适的压缩算法?

A2: 压缩算法选择建议:
- **snappy**:默认选项,平衡压缩比和性能
- **zlib**:更高的压缩比,适合冷数据
- **zstd**:MongoDB 4.2+支持,提供更好的压缩比和性能
- 建议根据数据特性进行测试,选择最适合的压缩算法

### Q3: 存储引擎缓存设置多少合适?

A3: 缓存大小建议:
- 默认使用系统内存的50%
- 为其他进程预留足够内存(至少2GB)
- 对于专用MongoDB服务器,可以设置为系统内存的60-80%
- 监控缓存使用率,避免缓存不足导致频繁的页交换

### Q4: 什么是检查点(checkpoint)?

A4: 检查点是WiredTiger存储引擎的一个重要机制:
- 将内存中的数据快照刷新到磁盘
- 确保数据一致性
- 减少恢复时间
- 每60秒自动触发,或日志文件达到128MB时触发

### Q5: 如何处理超过16MB的大文档?

A5: 处理大文档的方法:
- 使用GridFS存储大型文件
- 将大文档拆分为多个相关文档
- 存储外部引用,将实际数据存储在文件系统
- 优化文档结构,减少不必要的数据

### Q6: 如何监控存储引擎性能?

A6: 监控存储引擎性能的方法:
- 使用`db.serverStatus().wiredTiger`查看WiredTiger状态
- 使用`db.collection.stats()`查看集合存储统计
- 使用MongoDB Atlas或Ops Manager监控
- 使用第三方监控工具(如Prometheus + Grafana)
- 关注缓存使用率、I/O等待时间、压缩比率等指标