Mongo 进阶 - WT 引擎:Page 生命周期 | Java 全栈知识体系

通过前文我们了解到数据以 page 为单位加载到 cache; 有必要系统的分析一页 page 的生命周期、状态以及相关参数的配置,这对后续 MongoDB 的性能调优和故障问题的定位和解决有帮助。@pdai

  为什么要了解 Page 生命周期


  通过前文我们了解到数据以 page 为单位加载到 cache、cache 里面又会生成各种不同类型的 page 及为不同类型的 page 分配不同大小的内存、eviction 触发机制和 reconcile 动作都发生在 page 上、page 大小持续增加时会被分割成多个小 page,所有这些操作都是围绕一个 page 来完成的。

  因此,有必要系统的分析一页 page 的生命周期、状态以及相关参数的配置,这对后续 MongoDB 的性能调优和故障问题的定位和解决有帮助。

  Page 的生命周期


  Page 的典型生命周期如下图所示:

  • 第一步:pages 从磁盘读到内存;
  • 第二步:pages 在内存中被修改;
  • 第三步:被修改的脏 pages 在内存被 reconcile,完成后将 discard 这些 pages。
  • 第四步:pages 被选中,加入淘汰队列,等待被 evict 线程淘汰出内存;
  • 第五步:evict 线程会将“干净“的 pages 直接从内存丢弃(因为相对于磁盘 page 来说没做任何修改),将经过 reconcile 处理后的磁盘映像写到磁盘再丢弃“脏的”pages。

  pages 的状态是在不断变化的,因此,对于读操作来说,它首先会检查 pages 的状态是否为 WT_REF_MEM​,然后设置一个 hazard 指针指向要读的 pages,如果刷新后,pages 的状态仍为 WT_REF_MEM,读操作才能继续处理。

  与此同时,evict 线程想要淘汰 pages 时,它会先锁住 pages,即将 pages 的状态设为 WT_REF_LOCKED​,然后检查 pages 上是否有读操作设置的 hazard 指针,如有,说明还有线程正在读这个 page 则停止 evict,重新将 page 的状态设置为 WT_REF_MEM​;如果没有,则 pages 被淘汰出去。

  Page 的各种状态


  针对一页 page 的每一种状态,详细描述如下:

  • WT_REF_DISK: 初始状态,page 在磁盘上的状态,必须被读到内存后才能使用,当 page 被 evict 后,状态也会被设置为这个。
  • WT_REF_DELETED: page 在磁盘上,但是已经从内存 B-Tree 上删除,当我们不在需要读某个 leaf page 时,可以将其删除。
  • WT_REF_LIMBO: page 的映像已经被加载到内存,但 page 上还有额外的修改数据在 lookasidetable 上没有被加载到内存。
  • WT_REF_LOOKASIDE: page 在磁盘上,但是在 lookasidetable 也有与此 page 相关的修改内容,在 page 可读之前,也需要加载这部分内容。

  当对一个 page 进行 reconcile 时,如果系统中还有之前的读操作正在访问此 page 上修改的数据,则会将这些数据保存到 lookasidetable;当 page 再被读时,可以利用 lookasidetable 中的数据重新构建内存 page。

  • WT_REF_LOCKED: 当 page 被 evict 时,会将 page 锁住,其它线程不可访问。
  • WT_REF_MEM: page 已经从磁盘读到内存,并且能正常访问。
  • WT_REF_READING: page 正在被某个线程从磁盘读到内存,其它的读线程等待它被读完,不需要重复去读。
  • WT_REF_SPLIT: 当 page 变得过大时,会被 split,状态设为 WT_REF_SPLIT,原来指向的 page 不再被使用。

  Page 的大小参数


  无论将数据从磁盘读到内存,还是从内存写到磁盘,都是以 page 为单位调度的,但是在磁盘上一个 page 到底多大?是否是最小分割单元?以及内存里面的各种 page 的大小对存储引擎的性能是否有影响?本节将围绕这些问题,分析与 page 大小相关的参数是如何影响存储引擎性能的。 总的来说,涉及到的关键参数和默认值如下表所示:

参数名称 默认配置值 含义
allocation_size 4KB 磁盘上最小分配单元
memory_page_max 5MB 内存中允许的最大 page 值
internal_page_max 4KB 磁盘上允许的最大 internal page 值
leaf_page_max 32KB 磁盘上允许的最大 leaf page 值
internal_key_max 1/10*internal_page internal page 上允许的最大 key 值
leaf_key_max 1/10*leaf_page leaf page 上允许的最大 key 值
leaf_key_value 1/2*leaf_page leaf page 上允许的最大 value 值
split_pct 75% reconciled 的 page 的分割百分比

  详细说明如下:

  • allocation_size

  MongoDB 磁盘文件的最小分配单元(由 WiredTiger 自带的块管理模块来分配),一个 page 的可以由一个或多个这样的单元组成;默认值是 4KB,与主机操作系统虚拟内存页的大小相当,大多数场景下不需要修改这个值。

  • memory_page_max

  WiredTigerCache 里面一个内存 page 随着不断插入修改等操作,允许增长达到的最大值,默认值为 5MB。当一个内存 page 达到这个最大值时,将会被 split 成较小的内存 pages 且通过 reconcile 将这些 pages 写到磁盘 pages,一旦完成写到磁盘,这些内存 pages 将从内存移除。

  需要注意的是:split 和 reconcile 这两个动作都需要获得 page 的排它锁,导致应用程序在此 page 上的其它写操作会等待,因此设置一个合理的最大值,对系统的性能也很关键。

  如果值太大,虽然 spilt 和 reconcile 发生的机率减少,但一旦发生这样的动作,持有排它锁的时间会较长,导致应用程序的插入或修改操作延迟增大;

  如果值太小,虽然单次持有排它锁的时间会较短,但是会导致 spilt 和 reconcile 发生的机率增加。

  • internal_page_max

  磁盘上 internalpage 的最大值,默认为 4KB。随着 reconcile 进行,internalpage 超过这个值时,会被 split 成多个 pages。

  这个值的大小会影响磁盘上 B-Tree 的深度和 internalpage 上 key 的数量,如果太大,则 internalpage 上的 key 的数量会很多,通过遍历定位到正确 leaf page 的时间会增加;如果太小,则 B-Tree 的深度会增加,也会影响定位到正确 leaf page 的时间。

  • leaf_page_max

  磁盘上 leaf page 的最大值,默认为 32KB。随着 reconcile 进行,leaf page 超过这个值时,会被 split 成多个 pages。

  这个值的大小会影响磁盘的 I/O 性能,因为我们在从磁盘读取数据时,总是期望一次 I/O 能多读取一点数据,所以希望把这个参数调大;但是太大,又会造成读写放大,因为读出来的很多数据可能后续都用不上。

  • internal_key_max

  internalpage 上允许的最大 key 值,默认大小为 internalpage 初始值的 1/10,如果超过这个值,将会额外存储。导致读取 key 时需要额外的磁盘 I/O。

  • leaf_key_max

  leaf page 上允许的最大 key 值,默认大小为 leaf page 初始值的 1/10,如果超过这个值,将会额外存储。导致读取 key 时需要额外的磁盘 I/O。

  • leaf_value_max

  leaf page 上允许的最大 value 值(保存真正的集合数据),默认大小为 leaf page 初始值的 1/2,如果超过这个值,将会额外存储。导致读取 value 时需要额外的磁盘 I/O。

  • split_pct

  内存里面将要被 reconciled 的 page 大小与 internal_page_max 或 leaf_page_max 值的百分比,默认值为 75%,如果内存里面被 reconciled 的 page 能够装进一个单独的磁盘 page 上,则不会发生 spilt,否则按照该百分比值*最大允许的 page 值分割新 page 的大小。

  Page 无锁及压缩


  https://blog.csdn.net/weixin_45583158/article/details/100143033

  参考文章


  • 文章来源在新窗口打开
  • 作者:郭远威
  • MongoDB 中文社区委员,长沙分会主席;《大数据存储 MongoDB 实战指南》作者资深大数据架构师,通信行业业务架构与数据迁移专家
  • 文章来源在新窗口打开
  • 袁荣喜,学霸君工程师,2015 年加入学霸君,负责学霸君的网络实时传输和分布式系统的架构设计和实现,专注于基础技术领域,在网络传输、数据库内核、分布式系统和并发编程方面有一定了解
  • MongoDB

    MongoDB(来自于英文单词“Humongous”,中文含义为“庞大”)是一个基于分布式文件存储的数据库,由 C++ 语言编写。旨在为应用提供可扩展的高性能数据存储解决方案。MongoDB 是一个介于关系数据库和非关系数据库之间的产品,是非关系数据库当中功能最丰富,最像关系数据库的。它支持的数据结构非常松散,是类似 JSON 的 BSON 格式,因此可以存储比较复杂的数据类型。

    91 引用 • 59 回帖 • 5 关注

相关帖子

欢迎来到这里!

我们正在构建一个小众社区,大家在这里相互信任,以平等 • 自由 • 奔放的价值观进行分享交流。最终,希望大家能够找到与自己志同道合的伙伴,共同成长。

注册 关于
请输入回帖内容 ...

推荐标签 标签

  • API

    应用程序编程接口(Application Programming Interface)是一些预先定义的函数,目的是提供应用程序与开发人员基于某软件或硬件得以访问一组例程的能力,而又无需访问源码,或理解内部工作机制的细节。

    79 引用 • 431 回帖
  • sts
    2 引用 • 2 回帖 • 241 关注
  • WebSocket

    WebSocket 是 HTML5 中定义的一种新协议,它实现了浏览器与服务器之间的全双工通信(full-duplex)。

    48 引用 • 206 回帖 • 287 关注
  • 面试

    面试造航母,上班拧螺丝。多面试,少加班。

    326 引用 • 1395 回帖 • 2 关注
  • 黑曜石

    黑曜石是一款强大的知识库工具,支持本地 Markdown 文件编辑,支持双向链接和关系图。

    A second brain, for you, forever.

    24 引用 • 242 回帖 • 2 关注
  • CSDN

    CSDN (Chinese Software Developer Network) 创立于 1999 年,是中国的 IT 社区和服务平台,为中国的软件开发者和 IT 从业者提供知识传播、职业发展、软件开发等全生命周期服务,满足他们在职业发展中学习及共享知识和信息、建立职业发展社交圈、通过软件开发实现技术商业化等刚性需求。

    14 引用 • 155 回帖 • 1 关注
  • 导航

    各种网址链接、内容导航。

    45 引用 • 177 回帖 • 1 关注
  • 设计模式

    设计模式(Design pattern)代表了最佳的实践,通常被有经验的面向对象的软件开发人员所采用。设计模式是软件开发人员在软件开发过程中面临的一般问题的解决方案。这些解决方案是众多软件开发人员经过相当长的一段时间的试验和错误总结出来的。

    201 引用 • 120 回帖 • 3 关注
  • abitmean

    有点意思就行了

    34 关注
  • Jenkins

    Jenkins 是一套开源的持续集成工具。它提供了非常丰富的插件,让构建、部署、自动化集成项目变得简单易用。

    54 引用 • 37 回帖 • 2 关注
  • C++

    C++ 是在 C 语言的基础上开发的一种通用编程语言,应用广泛。C++ 支持多种编程范式,面向对象编程、泛型编程和过程化编程。

    108 引用 • 153 回帖
  • jsDelivr

    jsDelivr 是一个开源的 CDN 服务,可为 npm 包、GitHub 仓库提供免费、快速并且可靠的全球 CDN 加速服务。

    5 引用 • 31 回帖 • 105 关注
  • VirtualBox

    VirtualBox 是一款开源虚拟机软件,最早由德国 Innotek 公司开发,由 Sun Microsystems 公司出品的软件,使用 Qt 编写,在 Sun 被 Oracle 收购后正式更名成 Oracle VM VirtualBox。

    10 引用 • 2 回帖 • 17 关注
  • Sym

    Sym 是一款用 Java 实现的现代化社区(论坛/BBS/社交网络/博客)系统平台。

    下一代的社区系统,为未来而构建

    524 引用 • 4601 回帖 • 709 关注
  • TensorFlow

    TensorFlow 是一个采用数据流图(data flow graphs),用于数值计算的开源软件库。节点(Nodes)在图中表示数学操作,图中的线(edges)则表示在节点间相互联系的多维数据数组,即张量(tensor)。

    20 引用 • 19 回帖
  • CodeMirror
    2 引用 • 17 回帖 • 167 关注
  • JRebel

    JRebel 是一款 Java 虚拟机插件,它使得 Java 程序员能在不进行重部署的情况下,即时看到代码的改变对一个应用程序带来的影响。

    26 引用 • 78 回帖 • 675 关注
  • gRpc
    11 引用 • 9 回帖 • 99 关注
  • GraphQL

    GraphQL 是一个用于 API 的查询语言,是一个使用基于类型系统来执行查询的服务端运行时(类型系统由你的数据定义)。GraphQL 并没有和任何特定数据库或者存储引擎绑定,而是依靠你现有的代码和数据支撑。

    4 引用 • 3 回帖 • 11 关注
  • Follow
    4 引用 • 12 回帖 • 1 关注
  • FFmpeg

    FFmpeg 是一套可以用来记录、转换数字音频、视频,并能将其转化为流的开源计算机程序。

    23 引用 • 32 回帖 • 1 关注
  • OnlyOffice
    4 引用 • 19 关注
  • OpenStack

    OpenStack 是一个云操作系统,通过数据中心可控制大型的计算、存储、网络等资源池。所有的管理通过前端界面管理员就可以完成,同样也可以通过 Web 接口让最终用户部署资源。

    10 引用 • 1 关注
  • GitLab

    GitLab 是利用 Ruby 一个开源的版本管理系统,实现一个自托管的 Git 项目仓库,可通过 Web 界面操作公开或私有项目。

    46 引用 • 72 回帖
  • Bootstrap

    Bootstrap 是 Twitter 推出的一个用于前端开发的开源工具包。它由 Twitter 的设计师 Mark Otto 和 Jacob Thornton 合作开发,是一个 CSS / HTML 框架。

    18 引用 • 33 回帖 • 648 关注
  • Sandbox

    如果帖子标签含有 Sandbox ,则该帖子会被视为“测试帖”,主要用于测试社区功能,排查 bug 等,该标签下内容不定期进行清理。

    436 引用 • 1238 回帖 • 588 关注
  • 服务

    提供一个服务绝不仅仅是简单的把硬件和软件累加在一起,它包括了服务的可靠性、服务的标准化、以及对服务的监控、维护、技术支持等。

    41 引用 • 24 回帖