MongoDB系列之WiredTiger引擎

概述

关系型数据库MySQL有InnoDB存储引擎,存储引擎很大程度上决定着数据库的性能。

在MongoDB早期版本中,默认使用MMapV1存储引擎,其索引就是一个B-树(也称B树)。

从MongoDB 3.0开始引入WiredTiger(以下简称WT)存储引擎,在性能及稳定性上都有明显的提升。从MongoDB 3.2开始,WT作为默认的引擎,在索引和集合的检索上借鉴B+树。

WT是一个优秀的单机数据库存储引擎,拥有诸多特性,支持BTree、LSM Tree索引,支持行存储和列存储,实现ACID级别事务、支持大到4G的记录。

现代计算机近20年来CPU的计算能力和内存容量飞速发展,但磁盘的访问速度并没有得到相应的提高,WT就是在这样的一个情况下研发出来,充分利用CPU并行计算的内存模型的无锁并行框架,使得WT引擎在多核CPU上的表现优于其他存储引擎。针对磁盘存储特性,WT实现一套基于BLOCK/Extent的磁盘友好访问算法,使得WT在数据压缩和磁盘I/O访问上优势明显。实现基于snapshot技术的ACID事务,snapshot技术大大简化WT的事务模型,摒弃传统的事务锁隔离又同时能保证事务的ACID。WT根据现代内存容量特性实现一种基于Hazard Pointer的LRU cache模型,充分利用内存容量的同时又能拥有很高的事务读写并发。

WiredTiger存储引擎在数据检索性能上做了许多优化,基于内存的二级的缓存提供高速读取数据能力,在写方面则是根据磁盘I/O的特点做缓冲式写入,这是基于空间、时间因素权衡的一种择优设计。

MongoDB在写入更新记录时使用基于version的乐观锁模式,当写冲突产生(尝试更新失败)时,WiredTiger内部会产生WT_ROLLBACK结果,MongoDB检测到该状态之后会抛出WriteConflictException,最终由写入的执行线程捕获该异常并重试。

WiredTiger对事务的支持同时包含:未提交读、提交读、快照一致性读。MongoDB事务采用快照一致性读。

原理

读缓存

理想情况下,MongoDB可提供近似内存式的读写性能。WiredTiger引擎实现数据的二级缓存,第一层是操作系统层级的页面缓存,第二层则是引擎提供的内部缓存:
在这里插入图片描述
读取数据时的流程:

  • 数据库发起Buffer I/O读操作,由操作系统将磁盘数据页加载到文件系统的页缓存区
  • 引擎层读取页缓存区的数据,进行解压后存放到内部缓存区
  • 在内存中完成匹配查询,将结果返回给应用。

如果数据已经被存储在内部缓存中,MongoDB则可以发挥最佳的读性能。稍差的情况是内部缓存中找不到,但数据仍然被存储在操作系统的页缓存中,此时需要花费一些数据解压缩的开销。直接从磁盘加载数据时,性能是最差的。因此MongoDB为了尽可能保证业务查询的热点数据能快速被访问,其内部缓存的默认大小达到内存的一半,该值由wiredTigerCacheSize参数指定,其默认计算公式: w i r e d T i g e r C a c h e S i z e = M a t h . m a x ( ( R A M − 1 G B ) , 256 M B ) wiredTigerCacheSize=Math.max((RAM-1GB),256MB) wiredTigerCacheSize=Math.max((RAM1GB),256MB)

写缓冲

当数据发生写入时,MongoDB并不会立即持久化到磁盘上,而是先在内存中记录这些变更,随后通过CheckPoint机制将变化的数据写入磁盘。即,非实时持久化。

采用延迟持久化方案,则避不开可靠性问题。

MongoDB单机下保证数据可靠性的机制包括以下两个部分:

  1. CheckPoint机制:快照(snapshot)描述某一时刻(point-in-time)数据在内存中的一致性视图,而这种数据的一致性是WiredTiger通过MVCC(多版本并发控制)实现的。当建立CheckPoint时,WiredTiger会在内存中建立所有数据的一致性快照,并将该快照覆盖的所有数据变化一并进行持久化(fsync)。成功之后,内存中数据的修改才得以真正保存。MongoDB默认每60s建立一次CheckPoint,在检查点写入过程中,上一个检查点仍然是可用的。这样可以保证一旦出错,仍能恢复到上一个检查点。
  2. Journal日志:一种预写式日志(write ahead log)机制,主要用来弥补CheckPoint机制的不足。如果开启Journal日志,那么WiredTiger会将每个写操作的redo日志写入Journal缓冲区,该缓冲区会频繁地将日志持久化到磁盘上。默认情况下,Journal缓冲区每100ms执行一次持久化。此外,Journal日志达到100MB,或是应用程序指定journal:true,写操作都会触发日志的持久化。一旦MongoDB发生宕机,重启程序时会先恢复到上一个检查点,然后根据Journal日志恢复增量的变化。由于Journal日志持久化的间隔非常短,数据能得到更高的保障,如果按照当前版本的默认配置,则其在断电情况下最多会丢失100ms的写入数据。

结合CheckPoint和Journal日志,数据写入的内部流程图:
在这里插入图片描述
步骤:

  • 应用向MongoDB写入数据(插入、修改或删除)
  • 数据库从内部缓存中获取当前记录所在的页块,如果不存在则会从磁盘中加载(Buffer I/O)
  • WiredTiger开始执行写事务,修改的数据写入页块的一个更新记录表,此时原来的记录仍然保持不变
  • 如果开启Journal日志,在写数据同时会写入一条Journal日志(Redo Log)。该日志在最长不超过100ms之后写入磁盘
  • 数据库每隔60s执行一次CheckPoint操作,此时内存中的修改会真正刷入磁盘。

Journal日志采用的是顺序I/O写操作,频繁地写入对磁盘的影响并不是很大。在MongoDB 3.4及以下版本中,当Journal日志达到2GB时同样会触发CheckPoint行为。如果应用存在大量随机写入,则CheckPoint可能会造成磁盘I/O的抖动。在磁盘性能不足的情况下,问题会更加显著,此时适当缩短CheckPoint周期可以让写入平滑一些。

缓存页管理

WiredTiger仍然使用Page(页)作为数据存取的单元。其中,内存和磁盘中的页结构是不同的,Block Manager被用于处理这些差异。

页块在内存中以类B+树的结构进行组织,中间节点用于存放key,而叶子节点则存放key和value:
在这里插入图片描述
与传统B+树结构稍微不同的是,叶子节点(Leaf Page)通过父级指针(Parent Pointer)来实现范围遍历操作(避免并发写产生DeadLock)。当读取数据时,会先通过B+树索引找到对应的叶节点页面,而在页内则使用二分查找来查找记录。

当叶节点产生数据写入时,这些更新记录会被写入节点的一块独立区域,此时该节点被标记为脏页:
在这里插入图片描述
Inserts和Updates是单独的跳跃表(skiplist)结构,分别存放插入和修改操作,删除操作也被认为是一种修改(状态变更为删除)。如果存在修改,则读取时还会从跳跃表中做合并查找。

在CheckPoint时,引擎会通过Block Manager发起Reconciliation过程。此时,CheckPoint线程会遍历内存中的全部页并找到所有的脏页进行持久化,为了不阻塞读,使用Copy-On-Write方式。

对于脏页的处理并不是就地更新,而是为需要变更的页块生成新的节点(包括其父级节点),每次CheckPoint都会产生一个新的根节点(Root Page)。当持久化工作完成后,由这个新的根节点接管操作,淘汰不用的节点。

CheckPoint时,WiredTiger需要将BTree修改过的PAGE都进行持久化存储,每个BTree对应磁盘上一个物理文件,BTree的每个PAGE以文件里的extent形式(由文件offset + size标识)存储,一个CheckPoint包含如下元数据:

  • root page地址:地址由文件offset,size及内容的checksum组成
  • alloc extent list地址:存储从上次checkpoint起新分配的extent列表
  • discard extent list地址:存储从上次checkpoint起丢弃的extent列表
  • available extent list地址:存储可分配的extent列表,只有最新的CheckPoint包含该列表
  • file size:如需恢复到该CheckPoint状态,将文件truncate到file size即可

在Reconciliation过程中,BlockManager需要将内存中的页块转换为磁盘上的页,内存页要比磁盘页大一些:

  1. memory_page_max:内部缓存页大小的最大值,默认是5MB
  2. internal_page_max:磁盘中间页大小的最大值,默认是4KB
  3. leaf_page_max:磁盘叶节点页大小的最大值,默认是32KB
  4. allocation_size:磁盘文件的存储单元,默认是4KB,internal_page_max、leaf_page_max必须是它的整数倍

其中,memory_page_max的取值会影响写入延迟。这个值如果太小,则会导致频繁地分裂和淘汰(阻塞写入),如果太大则会导致每次产生阻塞的时间变长。internal_page_max存储的是B+树的索引,因此它会影响树的深度。在需要大量扫描磁盘记录的场景中leaf_page_max需要加大,可减少I/O次数,而在特别关注读写时延的场景中则需要适当减小。allocation_size则需要与操作系统的页缓存大小对齐,以达到最好的效率。

触发Reconciliation的条件:

  • CheckPoint
  • 缓存中的页超过最大值(存在大量的修改),产生分裂,此时会触发evict命令并持久化
  • 缓存中的脏数据比例达到一定阈值,触发缓存淘汰(evict)。

缓存淘汰策略
WiredTiger基于LRU算法来实现缓存淘汰,常态下会由后台的evict线程来负责淘汰页面。如果内存非常紧张,则用户线程也会加入缓存淘汰的工作中,此时表现出读写请求有一定阻塞。WiredTiger存储引擎eviction策略的4个可配置参数:

参数默认值解释
eviction_target80当cache used超过eviction_target时,后台evict线程开始淘汰Clean Page
eviction_trigger95当cache used超过eviction_trigger时,用户线程也开始淘汰Clean Page
eviction_dirty_target5当cache dirty超过eviction_dirty_target时,后台evict线程开始淘汰Dirty Page
eviction_dirty_trigger20当cache dirty超过eviction_dirty_trigger时,用户线程也开始淘汰Dirty Page

数据

里一个典型的WiredTiger数据库存储布局大致如下:

$tree
.
├── journal
│   ├── WiredTigerLog.0000000003
│   └── WiredTigerPreplog.0000000001
├── WiredTiger
├── WiredTiger.basecfg
├── WiredTiger.lock
├── WiredTiger.turtle
├── admin
│   ├── table1.wt
│   └── table2.wt
├── local
│   ├── table1.wt
│   └── table2.wt
└── WiredTiger.wt

文件解释:

  • WiredTiger.basecfg:存储基本配置信息
  • WiredTiger.lock:用于防止多个进程连接同一个WiredTiger数据库
  • table*.wt:存储各个tale(数据库中的表)的数据
  • WiredTiger.wt:特殊Table,用于存储所有其他Table的元数据信息
  • WiredTiger.turtle:存储WiredTiger.wt的元数据信息
  • journal:存储Write ahead log

压缩

默认情况下,WiredTiger对集合使用块压缩,对索引使用前缀压缩。当页面被写入磁盘时执行压缩,而从磁盘中读入缓存时对页面进行解压。持久化的Journal日志也会采用Snappy压缩算法(块压缩的一种)

内部缓存和磁盘中的数据有着不同的格式:

  1. 磁盘中的数据和文件系统的缓存是一致的,这些都是经过压缩的。文件系统缓存是操作系统层的机制,这是为了减少磁盘I/O而做出的优化
  2. 集合数据在内部缓存中是未经过压缩的(方便直接读写),而在磁盘和页缓存中则保持压缩的格式
  3. 索引在磁盘和页面缓存中均保持前缀压缩的形态,其在内部缓存中是另外一种结构,但同样利用前缀压缩算法

参数

  • storage.journal.commitIntervalMs:Journal日志的刷新周期。3.4及以下版本默认值50ms,3.6版本之后调整到100ms
  • storage.syncPeriodSecs:CheckPoint刷新周期,默认60s。
  • storage.wiredTiger.collectionConfig.blockCompressor:用于指定集合数据的压缩算法,选项如下:
    • None:不启用压缩
    • Snappy:默认,谷歌开源的强大而稳定的压缩算法,最高可达30%以下的压缩比,性价比较好
    • Zlib:相比Snappy来说压缩率更好,但需要消耗更多的CPU
    • Zstd:Facebook提供的新型高速压缩算法,能以较低的CPU消耗实现更高的压缩比。MongoDB 4.2版本开始支持
  • storage.wiredTiger.indexConfig.prefixCompression:用于指定是否启用索引前缀压缩(key prefix compression),默认true。前缀压缩对于CPU的消耗很小,平均可达到近50%的压缩率。

参考

  • MongoDB进阶与实战:微服务整合、性能优化、架构管理
  • https://mongoing.com/archives/5367

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/679011.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

使用C++从零开始,自己写一个MiniWeb

第一步:新建项目 1、打开VS点击创建新项目 2、选择空项目并点下一步(切记不能选错项目类型) 3、填写项目名称和路径,点击创建即可 新建好后项目是这样的比较干净 4、右击源文件,点击添加,新建http.cpp文件…

最简单的基于 FFmpeg 的视频编码器(YUV 编码为 H.264)

最简单的基于 FFmpeg 的视频编码器(YUV 编码为 H.264) 最简单的基于 FFmpeg 的视频编码器(YUV 编码为 H.264)正文结果工程文件下载 最简单的基于 FFmpeg 的视频编码器(YUV 编码为 H.264) 参考雷霄骅博士的…

第78讲 修改密码

系统管理实现 修改密码实现 前端 modifyPassword.vue&#xff1a; <template><el-card><el-formref"formRef":model"form":rules"rules"label-width"150px"><el-form-item label"用户名&#xff1a;&quo…

《CSS 简易速速上手小册》第2章:CSS 布局与定位(2024 最新版)

文章目录 2.1 Flexbox&#xff1a;灵活的布局解决方案2.1.1 基础知识2.1.2 重点案例&#xff1a;创建一个响应式导航菜单2.1.3 拓展案例 1&#xff1a;卡片布局2.1.4 拓展案例 2&#xff1a;中心对齐的登录表单 2.2 Grid 布局&#xff1a;网格系统的魔力2.2.1 基础知识2.2.2 重…

C语言求解猴子分桃子

问题&#xff1a;海滩上有一堆桃子&#xff0c;五只猴子来分。第一只猴子把这堆桃子平均分为五份&#xff0c;多了一个&#xff0c;这只 猴子把多的一个扔入海中&#xff0c;拿走了一份。第二只猴子把剩下的桃子又平均分成五份&#xff0c;又多了 一个&#xff0c;它同样把多的…

english_syntax

文章目录 什么是英语的句子&#xff1f;英语句子的结构句子的成分&#xff08;词性问题&#xff09;谓语系动词主语宾语表语 并列句从句引导词名词性从句形容词性从句&#xff08;定语从句&#xff09;副词性从句&#xff08;状语从句&#xff09; 特殊结构强调句型倒装句型虚拟…

VitePress-13- 配置-title的作用详解

作用描述 1、title 是当前站点的标题&#xff1b;2、默认值是 &#xff1a;VitePress&#xff1b;3、当使用默认主题时&#xff0c;会直接展示在 页面的【导航条】中&#xff1b;4、一个特殊的作用 &#xff1a; 会作为单个页面的默认标题后缀&#xff01;除非又指定了【title…

WSL下如何使用Ubuntu本地部署Vits2.3-Extra-v2:中文特化修复版(新手从0开始部署教程)

环境&#xff1a; 硬&#xff1a; 台式电脑 1.cpu:I5 11代以上 2.内存16G以上 3.硬盘固态500G以上 4.显卡N卡8G显存以上 20系2070以上 本案例英伟达4070 12G 5.网络可连github 软&#xff1a; Win10 专业版 19045以上 WSL2 -Ubuntu22.04 1.bert-Vits2.3 Extra-v2:…

CSP-201912-1-报数

CSP-201912-1-报数 知识点总结 整数转化为字符串#include <string> string str_num to_string(num);字符串中查找是否包含字符‘7’&#xff1a;str_num.find(7) 未找到返回-1找到返回返回该字符在字符串中的位置&#xff08;即第一次出现的索引位置&#xff09; #i…

腾讯云4核8G服务器够用吗?容纳多少人同时访问?

腾讯云4核8G服务器支持多少人在线访问&#xff1f;支持25人同时访问。实际上程序效率不同支持人数在线人数不同&#xff0c;公网带宽也是影响4核8G服务器并发数的一大因素&#xff0c;假设公网带宽太小&#xff0c;流量直接卡在入口&#xff0c;4核8G配置的CPU内存也会造成计算…

java nio零拷贝

零拷贝是一种计算机执行IO操作的优化技术&#xff0c;其核心目标是减少数据拷贝次数&#xff0c;从而提高系统性能。它主要体现在以下几个方面&#xff1a; 1. **定义与原理**&#xff1a;零拷贝字面上的意思包括“零”和“拷贝”。其中&#xff0c;“拷贝”是指数据从一个存储…

读千脑智能笔记11_保存人类遗产

1. 智能生物通常能延续多久 1.1. SETI和METI计划的可行性在很大程度上取决于智能生物通常能延续多久 1.1.1. 搜寻地外文明&#xff08;以下简称SETI&#xff09;计划的目标 1.1.1.1. 这是一个力图寻找宇宙其他地方智能生物存在证据的研究项目 1.1.1.2. SETI计划旨在寻找含有…

[NSSCTF]-Web:[SWPUCTF 2021 新生赛]easy_sql解析

查看网页 有提示&#xff0c;参数是wllm&#xff0c;并且要我们输入点东西 所以&#xff0c;我们尝试以get方式传入 有回显&#xff0c;但似乎没啥用 从上图看应该是字符型漏洞&#xff0c;单引号字符注入 先查看字段数 /?wllm2order by 3-- 没回显 报错了&#xff0c;说明…

顺序表、链表(ArrayList、LinkedList)

目录 前言&#xff1a; 顺序表&#xff08;ArrayList&#xff09;&#xff1a; 顺序表的原理&#xff1a; ArrayList源码&#xff1a; 的含义&#xff1a;​编辑 ArrayList的相关方法&#xff1a;​编辑 向上转型List&#xff1a; 练习题&#xff08;杨辉三角&#x…

轻薄型工业平板亿道EM-T195,续航持久高达10小时

时尚而坚固的 10.1英寸EM-T195触摸屏平板电脑融合了高耐力和无与伦比的适应性&#xff0c;可抵御极端天气条件和多重冲击&#xff0c;借助强大的联发科8核处理器&#xff0c;它可以从容面对任何工作挑战。 其读取能力&#xff08;2D 成像器&#xff09;结合其坚固性&#xff0…

探索现代Web前端开发框架:选择最适合你的工具

在当今快速发展的Web开发领域&#xff0c;前端开发框架的选择显得尤为关键。这些框架可以帮助我们更高效地构建出交互性强、性能卓越的用户界面。本文将带你了解几个当前最受欢迎的Web前端开发框架&#xff0c;并帮助你根据自己的需求选择最合适的工具。 1. React React由Fac…

2.10日学习打卡----初学RocketMQ(一)

2.10日学习打卡 对于MQ(Message queue)消息队列的一些解释可以看我原来写的文章 初学RabbitMQ 各大MQ产品比较 一.RocketMQ概述 发展历程 RocketMQ概念术语 生产者和消费者 生产者负责生产消息&#xff0c;一般由业务系统负责生产消息&#xff0c;消费者即后台系统&…

无人机遥感技术应用分析,无人机遥感系统测绘技术详解

由于无人机具有机动快速、使用成本低、维护操作简单等技术特点,因此被作为一种理想的飞行平台广泛应用于军事和民用各个领域。尤其是进入二十一世纪以后,许多国家将无人机系统的研究、开发、应用置于优先发展的地位,体积小、重量轻、探测精度高的新型传感器的不断问世,也使无人…

解决挂梯子 无法正常上网 的问题

方法&#xff1a; 打开 控制面板 &#x1f449; 网络和Internet &#x1f449; Internet选项 &#x1f449; 连接 &#x1f449; 局域网设置 &#x1f449; 代理服务器 &#x1f449; 取消选项 有问题可参考下图

中科大计网学习记录笔记(九):DNS

前言&#xff1a; 学习视频&#xff1a;中科大郑烇、杨坚全套《计算机网络&#xff08;自顶向下方法 第7版&#xff0c;James F.Kurose&#xff0c;Keith W.Ross&#xff09;》课程 该视频是B站非常著名的计网学习视频&#xff0c;但相信很多朋友和我一样在听完前面的部分发现信…