什么是WiredTiger?
MongoDB和 WiredTiger的职责范围
- MongoDB使用的底层存储引擎
- WT是键/值数据库,而不是文档数据库
- 支持事务
- 使用无锁算法
- 压缩磁盘上的数据
- 使用WT缓存和FS缓存
- 支持多版本控制
- 它将 BSON文档存储在BTree中
- 通过内部键索引文档
- 文档存储在叶节点中
- 索引也是由索引值构成的B树
- MongoDB数据存放在WT Table 中(collection-xxx.wt)
- MongoDB索引也存放在WT Table 中(index-xxx.wt)
除此之外还有一些WT Table 用于存放元数据:
- WiredTiger.wt: WiredTiger自己使用的元数据
- _mdb_catalog.wt: MongoDB表定义等元数据
- sizeStorer.wt:数据大小,条数等元数据
Journaling和Checkpoints
- WiredTiger使用Journaling (预写日志)和Checkpoints(检查点)来确保数据在服务器发生故障时是持久化且可恢复的
- Journaling是一种预写日志,其中最后一个检查点之后的更改以简单、可重放的形式保存到磁盘。
- Checkpoint每分钟发生一次,以确保磁盘上始终存在完全一致的数据。恢复需要在最新检查点上重放最多一分钟的日志。
数据库中的缓存
- WiredTiger有一块缓存
- 默认大小是(RAM - 1GB)的一半或256MB,取较大值。
- 除非在同一台服务器上运行多个实例,否则不应更改此设置·缓存中的数据块可以在需要时保留文档的多个版本
- 不再使用时,未使用的块将从缓存中清除
- 如果当majority无法满足,数据将写入称为LAS文件的缓存文件
- 当需要空间时,不常用的数据将从缓存中逐出
- 缓存中的块可以来自集合或索引
触发缓存驱逐的阈值
- Read cache
- 80%以下没有驱逐缓存政策
- 80+%开始使用后台线程驱逐缓存
- 95+%开始使用应用程序线程进行主动驱逐。
- 100%阻止新的操作,直到发生一些驱逐
- Dirty cache
- 5%以下无缓存处理。
- 5+%开始使用后台线程
- 20+%开始使用应用程序线程来提供帮助
合理的缓存大小
- 不能依赖Pagefault,需要结合查看iostats 和serverStatus()指标:
- 磁盘读取
- 磁盘写入。字节读入缓存
- 从缓存中写入的字节
- 如果磁盘低读磁盘+高数据读入缓存
- 增加WT缓存大小
- 如果中到高读磁盘+中到高数据读入缓存
- 添加内存
WiredTiger的读写过程
- 所有数据库块都通过WiredTiger缓存读取和写入
- 何时需要将数据读入WiredTiger缓存
- MongoDB将只会读入它需要的数据块
WiredTiger 压缩
- 使用WiredTiger,默认情况下为集合和索引启用压缩
- 压缩有助于最大限度地减少存储使用,但需要更多CPU计算
- 数据库块(页面)在磁盘和系统缓存中被压缩,但在 WiredTiger缓存中未压缩o
- Snappy(默认)、Zlib、Zstd、未压缩
- 为什么你会选择不同的压缩方式?
- 索引在RAM和磁盘上都被压缩
- 索引压缩使用前缀压缩
- 每个条目都存储为已经出现过条目的增量
WiredTiger并发
- WiredTiger对写操作使用文档级并发控制
- 写入操作永远不会阻止其他线程读取数据
- 写入只会短暂地阻止其他线程写入相同的文档
- 表或数据库级别的锁定很少见
- 某些维护操作可能会锁定数据库或集合
- 客户端试图同时更改同一份数据时
- 从技术上讲,两者都在缓存中创建了一个新版本,但较晚完成的版本需要基于已经完成的版本重新开始
- 这实际上导致写入形成一个队列
WriteConcern写关注
当你写入复制集时:
- 如何保证持久化?
- 如果主节点的最新数据在宕机后回滚,会发生什么?谁来决定哪些数据不能丢失?
数据复制过程
- 应用程序将所有更新写入到主节点
- 主节点在时间T应用变更,并将变更记录放在操作日志(Oplog)中
- 从节点观察Oplog并将读取到时间T的变更
- 从节点将到时间T的更新记录应用于自己本身
- 从节点将变更记录记录在自己的Oplog中
- 从节点继续请求时间T之后的数据
- 主节点知道每个从节点最新的时间T的记录.
数据写入过程
写关注级别
- MongoDB中允许你定义'OK, committed"的级别。
- 由主节点通过网络接收,但未写检查确认(w :O)
- 由主节点接收和写入-持久化到主节点的磁盘(w :1, j : 1)。
- 由大多数节点接收和写入( w : "majority") w是服务器数量,j是否等待下一次磁盘刷新(默认为大多数)
你可以在应用程序中的任何写入,连接或用于写入的对象上指定这些
MongoDB将等到它达到你请求的级别或者超时时间.如果它超时,它可能仍然完成了其中的一部分.如果发生超时,你可能需要确认状态
Read preference读偏好
根据场景需求选择合适的读偏好
- 仅从主节点读
- 优先从从主节点读,除非不存在主节点(primaryPreferred)
- 仅从从节点读取
- 优先从从节点读,除非不存在从节点.
- 从最近的地理位置的节点上读
- 从一组指定的节点上读